From 1b96a031d2b7f7275fd39c4597e32ffef21371e3 Mon Sep 17 00:00:00 2001 From: Tha_14 Date: Thu, 22 Feb 2024 21:43:11 +0200 Subject: [PATCH] Initial commit --- Antidote.xcodeproj/project.pbxproj | 3062 +++++++++ Antidote/ActiveSessionCoordinator.swift | 634 ++ .../ActiveSessionNavigationCoordinator.swift | 24 + Antidote/AddFriendController.swift | 245 + Antidote/AlertAudioPlayer.swift | 50 + Antidote/Antidote-Bridging-Header.h | 43 + Antidote/Antidote-Info.plist | 89 + Antidote/Antidote-Prefix.pch | 12 + Antidote/Antidote.entitlements | 12 + Antidote/AppCoordinator.swift | 163 + Antidote/AppDelegate.swift | 321 + Antidote/AudioPlayer.swift | 81 + Antidote/AutomationCoordinator.swift | 110 + Antidote/AvatarManager.swift | 131 + Antidote/BaseCell.swift | 39 + Antidote/BaseCellModel.swift | 9 + Antidote/BubbleView.swift | 104 + Antidote/Bus.swift | 86 + Antidote/CallActiveController.swift | 403 ++ Antidote/CallBaseController.swift | 117 + Antidote/CallButton.swift | 132 + Antidote/CallCoordinator.swift | 396 ++ Antidote/CallIncomingController.swift | 125 + Antidote/CallManagement/Call.swift | 93 + Antidote/CallManagement/CallManager.swift | 101 + .../CallManagement/ProviderDelegate.swift | 238 + .../ChangeAutodownloadImagesController.swift | 78 + Antidote/ChangePasswordController.swift | 254 + Antidote/ChangePinTimeoutController.swift | 111 + Antidote/ChangeUserStatusController.swift | 81 + Antidote/ChatBaseTextCell.swift | 100 + Antidote/ChatBaseTextCellModel.swift | 9 + Antidote/ChatBottomStatusViewManager.swift | 88 + Antidote/ChatEditable.swift | 29 + Antidote/ChatFauxOfflineHeaderView.swift | 49 + Antidote/ChatGenericFileCell.swift | 178 + Antidote/ChatGenericFileCellModel.swift | 26 + Antidote/ChatIncomingCallCell.swift | 86 + Antidote/ChatIncomingCallCellModel.swift | 10 + Antidote/ChatIncomingFileCell.swift | 88 + Antidote/ChatIncomingFileCellModel.swift | 8 + Antidote/ChatIncomingTextCell.swift | 37 + Antidote/ChatInputView.swift | 217 + Antidote/ChatInputViewManager.swift | 195 + Antidote/ChatListCell.swift | 160 + Antidote/ChatListCellModel.swift | 18 + Antidote/ChatListController.swift | 107 + Antidote/ChatListTableManager.swift | 222 + Antidote/ChatMovableDateCell.swift | 189 + Antidote/ChatMovableDateCellModel.swift | 9 + Antidote/ChatOutgoingCallCell.swift | 86 + Antidote/ChatOutgoingCallCellModel.swift | 10 + Antidote/ChatOutgoingFileCell.swift | 98 + Antidote/ChatOutgoingFileCellModel.swift | 9 + Antidote/ChatOutgoingTextCell.swift | 51 + Antidote/ChatOutgoingTextCellModel.swift | 10 + Antidote/ChatPrivateController.swift | 1508 +++++ Antidote/ChatPrivateTitleView.swift | 111 + Antidote/ChatProgressBridge.swift | 23 + Antidote/ChatProgressProtocol.swift | 10 + Antidote/ChatTypingHeaderView.swift | 101 + Antidote/ChatsTabCoordinator.swift | 94 + Antidote/ConnectionStatus.swift | 24 + Antidote/CoordinatorProtocol.swift | 15 + Antidote/CopyLabel.swift | 58 + Antidote/EnterPinController.swift | 148 + Antidote/ErrorHandling.swift | 337 + Antidote/ExceptionHandling.h | 11 + Antidote/ExceptionHandling.m | 19 + Antidote/ExtendedTextField.swift | 224 + Antidote/FAQController.swift | 79 + .../FilePreviewControllerDataSource.swift | 71 + Antidote/FriendCardController.swift | 186 + Antidote/FriendListCell.swift | 121 + Antidote/FriendListCellModel.swift | 20 + Antidote/FriendListController.swift | 315 + Antidote/FriendListDataSource.swift | 230 + Antidote/FriendRequestController.swift | 90 + Antidote/FriendSelectController.swift | 197 + Antidote/FriendsTabCoordinator.swift | 152 + Antidote/FullscreenPicker.swift | 158 + Antidote/HelperFunctions.swift | 19 + Antidote/ImageViewWithStatus.swift | 61 + .../AppIcon.appiconset/Contents.json | 122 + .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 0 -> 618 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 0 -> 1581 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 0 -> 2934 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 0 -> 1027 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 0 -> 2700 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 0 -> 4316 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 0 -> 1581 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 0 -> 4424 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 0 -> 7836 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 0 -> 7836 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 0 -> 11575 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 0 -> 4010 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 0 -> 11185 bytes .../Icon-App-83.5x83.5@2x.png | Bin 0 -> 10722 bytes .../AppIcon.appiconset/ItunesArtwork@2x.png | Bin 0 -> 44373 bytes Antidote/Images.xcassets/Contents.json | 6 + .../Controllers/Call/Contents.json | 6 + .../Call/end-call.imageset/Contents.json | 22 + .../Call/end-call.imageset/end-call.png | Bin 0 -> 645 bytes .../Call/end-call.imageset/end-call@2x.png | Bin 0 -> 3459 bytes .../Contents.json | 22 + .../location-call-activated-medium.png | Bin 0 -> 5416 bytes .../location-call-activated-medium@2x.png | Bin 0 -> 5697 bytes .../Contents.json | 22 + .../location-call-medium.png | Bin 0 -> 244 bytes .../location-call-medium@2x.png | Bin 0 -> 454 bytes .../Call/mute-selected.imageset/Contents.json | 22 + .../mute-selected.imageset/mute-selected.png | Bin 0 -> 1565 bytes .../mute-selected@2x.png | Bin 0 -> 1803 bytes .../Call/mute.imageset/Contents.json | 22 + .../Controllers/Call/mute.imageset/mute.png | Bin 0 -> 1491 bytes .../Call/mute.imageset/mute@2x.png | Bin 0 -> 1704 bytes .../Call/speaker.imageset/Contents.json | 22 + .../Call/speaker.imageset/speaker.png | Bin 0 -> 776 bytes .../Call/speaker.imageset/speaker@2x.png | Bin 0 -> 3910 bytes .../Call/start-call-30.imageset/Contents.json | 22 + .../start-call-30.imageset/start-call-30.png | Bin 0 -> 677 bytes .../start-call-30@2x.png | Bin 0 -> 3480 bytes .../start-call-medium.imageset/Contents.json | 22 + .../start-call-medium.png | Bin 0 -> 379 bytes .../start-call-medium@2x.png | Bin 0 -> 738 bytes .../start-call-small.imageset/Contents.json | 22 + .../start-call-small.png | Bin 0 -> 466 bytes .../start-call-small@2x.png | Bin 0 -> 466 bytes .../Call/start-call.imageset/Contents.json | 22 + .../Call/start-call.imageset/start-call.png | Bin 0 -> 738 bytes .../start-call.imageset/start-call@2x.png | Bin 0 -> 1476 bytes .../Call/switch-camera.imageset/Contents.json | 22 + .../switch-camera.imageset/switch-camera.png | Bin 0 -> 437 bytes .../switch-camera@2x.png | Bin 0 -> 730 bytes .../Call/video-call-30.imageset/Contents.json | 22 + .../video-call-30.imageset/video-call-30.png | Bin 0 -> 478 bytes .../video-call-30@2x.png | Bin 0 -> 3213 bytes .../video-call-medium.imageset/Contents.json | 22 + .../video-call-medium.png | Bin 0 -> 265 bytes .../video-call-medium@2x.png | Bin 0 -> 365 bytes .../Call/video-call.imageset/Contents.json | 22 + .../Call/video-call.imageset/video-call.png | Bin 0 -> 365 bytes .../video-call.imageset/video-call@2x.png | Bin 0 -> 744 bytes .../Controllers/Chat/Contents.json | 6 + .../Chat/chat-camera.imageset/Contents.json | 22 + .../Chat/chat-camera.imageset/chat-camera.png | Bin 0 -> 523 bytes .../chat-camera.imageset/chat-camera@2x.png | Bin 0 -> 829 bytes .../Contents.json | 22 + .../chat-delivered-checkmark.png | Bin 0 -> 436 bytes .../chat-delivered-checkmark@2x.png | Bin 0 -> 418 bytes .../chat-file-cancel.imageset/Contents.json | 22 + .../chat-file-cancel.png | Bin 0 -> 535 bytes .../chat-file-cancel@2x.png | Bin 0 -> 774 bytes .../Contents.json | 22 + .../chat-file-download-big.png | Bin 0 -> 1181 bytes .../chat-file-download-big@2x.png | Bin 0 -> 2394 bytes .../chat-file-download.imageset/Contents.json | 22 + .../chat-file-download.png | Bin 0 -> 526 bytes .../chat-file-download@2x.png | Bin 0 -> 1246 bytes .../Contents.json | 22 + .../chat-file-pause-big.png | Bin 0 -> 2967 bytes .../chat-file-pause-big@2x.png | Bin 0 -> 305 bytes .../chat-file-pause.imageset/Contents.json | 22 + .../chat-file-pause.png | Bin 0 -> 135 bytes .../chat-file-pause@2x.png | Bin 0 -> 2967 bytes .../chat-file-play-big.imageset/Contents.json | 22 + .../chat-file-play-big.png | Bin 0 -> 3215 bytes .../chat-file-play-big@2x.png | Bin 0 -> 815 bytes .../chat-file-play.imageset/Contents.json | 22 + .../chat-file-play.png | Bin 0 -> 276 bytes .../chat-file-play@2x.png | Bin 0 -> 3215 bytes .../chat-file-retry.imageset/Contents.json | 22 + .../chat-file-retry.png | Bin 0 -> 477 bytes .../chat-file-retry@2x.png | Bin 0 -> 781 bytes .../Contents.json | 22 + .../chat-file-type-7zip.png | Bin 0 -> 662 bytes .../chat-file-type-7zip@2x.png | Bin 0 -> 717 bytes .../chat-file-type-aac.imageset/Contents.json | 22 + .../chat-file-type-aac.png | Bin 0 -> 803 bytes .../chat-file-type-aac@2x.png | Bin 0 -> 1211 bytes .../chat-file-type-avi.imageset/Contents.json | 22 + .../chat-file-type-avi.png | Bin 0 -> 768 bytes .../chat-file-type-avi@2x.png | Bin 0 -> 1004 bytes .../Contents.json | 22 + .../chat-file-type-basic.png | Bin 0 -> 667 bytes .../chat-file-type-basic@2x.png | Bin 0 -> 3157 bytes .../Contents.json | 22 + .../chat-file-type-canceled.png | Bin 0 -> 681 bytes .../chat-file-type-canceled@2x.png | Bin 0 -> 748 bytes .../chat-file-type-css.imageset/Contents.json | 22 + .../chat-file-type-css.png | Bin 0 -> 812 bytes .../chat-file-type-css@2x.png | Bin 0 -> 1155 bytes .../chat-file-type-csv.imageset/Contents.json | 22 + .../chat-file-type-csv.png | Bin 0 -> 744 bytes .../chat-file-type-csv@2x.png | Bin 0 -> 1196 bytes .../chat-file-type-doc.imageset/Contents.json | 22 + .../chat-file-type-doc.png | Bin 0 -> 810 bytes .../chat-file-type-doc@2x.png | Bin 0 -> 1127 bytes .../Contents.json | 22 + .../chat-file-type-ebup.png | Bin 0 -> 794 bytes .../chat-file-type-ebup@2x.png | Bin 0 -> 1074 bytes .../chat-file-type-exe.imageset/Contents.json | 22 + .../chat-file-type-exe.png | Bin 0 -> 742 bytes .../chat-file-type-exe@2x.png | Bin 0 -> 919 bytes .../chat-file-type-fb2.imageset/Contents.json | 22 + .../chat-file-type-fb2.png | Bin 0 -> 734 bytes .../chat-file-type-fb2@2x.png | Bin 0 -> 989 bytes .../chat-file-type-flv.imageset/Contents.json | 22 + .../chat-file-type-flv.png | Bin 0 -> 720 bytes .../chat-file-type-flv@2x.png | Bin 0 -> 805 bytes .../chat-file-type-gif.imageset/Contents.json | 22 + .../chat-file-type-gif.png | Bin 0 -> 704 bytes .../chat-file-type-gif@2x.png | Bin 0 -> 790 bytes .../Contents.json | 22 + .../chat-file-type-html.png | Bin 0 -> 787 bytes .../chat-file-type-html@2x.png | Bin 0 -> 1044 bytes .../chat-file-type-jpg.imageset/Contents.json | 22 + .../chat-file-type-jpg.png | Bin 0 -> 719 bytes .../chat-file-type-jpg@2x.png | Bin 0 -> 1016 bytes .../chat-file-type-mov.imageset/Contents.json | 22 + .../chat-file-type-mov.png | Bin 0 -> 852 bytes .../chat-file-type-mov@2x.png | Bin 0 -> 1362 bytes .../chat-file-type-mp3.imageset/Contents.json | 22 + .../chat-file-type-mp3.png | Bin 0 -> 837 bytes .../chat-file-type-mp3@2x.png | Bin 0 -> 1281 bytes .../chat-file-type-mpg.imageset/Contents.json | 22 + .../chat-file-type-mpg.png | Bin 0 -> 852 bytes .../chat-file-type-mpg@2x.png | Bin 0 -> 1296 bytes .../chat-file-type-ogg.imageset/Contents.json | 22 + .../chat-file-type-ogg.png | Bin 0 -> 843 bytes .../chat-file-type-ogg@2x.png | Bin 0 -> 1225 bytes .../chat-file-type-otf.imageset/Contents.json | 22 + .../chat-file-type-otf.png | Bin 0 -> 736 bytes .../chat-file-type-otf@2x.png | Bin 0 -> 875 bytes .../chat-file-type-pdf.imageset/Contents.json | 22 + .../chat-file-type-pdf.png | Bin 0 -> 744 bytes .../chat-file-type-pdf@2x.png | Bin 0 -> 923 bytes .../chat-file-type-png.imageset/Contents.json | 22 + .../chat-file-type-png.png | Bin 0 -> 821 bytes .../chat-file-type-png@2x.png | Bin 0 -> 1141 bytes .../chat-file-type-ppt.imageset/Contents.json | 22 + .../chat-file-type-ppt.png | Bin 0 -> 720 bytes .../chat-file-type-ppt@2x.png | Bin 0 -> 745 bytes .../chat-file-type-psd.imageset/Contents.json | 22 + .../chat-file-type-psd.png | Bin 0 -> 747 bytes .../chat-file-type-psd@2x.png | Bin 0 -> 1137 bytes .../chat-file-type-rar.imageset/Contents.json | 22 + .../chat-file-type-rar.png | Bin 0 -> 823 bytes .../chat-file-type-rar@2x.png | Bin 0 -> 1181 bytes .../chat-file-type-tar.imageset/Contents.json | 22 + .../chat-file-type-tar.png | Bin 0 -> 726 bytes .../chat-file-type-tar@2x.png | Bin 0 -> 982 bytes .../chat-file-type-tif.imageset/Contents.json | 22 + .../chat-file-type-tif.png | Bin 0 -> 663 bytes .../chat-file-type-tif@2x.png | Bin 0 -> 454 bytes .../chat-file-type-ttf.imageset/Contents.json | 22 + .../chat-file-type-ttf.png | Bin 0 -> 682 bytes .../chat-file-type-ttf@2x.png | Bin 0 -> 501 bytes .../chat-file-type-txt.imageset/Contents.json | 22 + .../chat-file-type-txt.png | Bin 0 -> 690 bytes .../chat-file-type-txt@2x.png | Bin 0 -> 796 bytes .../chat-file-type-wav.imageset/Contents.json | 22 + .../chat-file-type-wav.png | Bin 0 -> 844 bytes .../chat-file-type-wav@2x.png | Bin 0 -> 1312 bytes .../chat-file-type-wma.imageset/Contents.json | 22 + .../chat-file-type-wma.png | Bin 0 -> 876 bytes .../chat-file-type-wma@2x.png | Bin 0 -> 1441 bytes .../chat-file-type-xls.imageset/Contents.json | 22 + .../chat-file-type-xls.png | Bin 0 -> 740 bytes .../chat-file-type-xls@2x.png | Bin 0 -> 1064 bytes .../chat-file-type-zip.imageset/Contents.json | 22 + .../chat-file-type-zip.png | Bin 0 -> 708 bytes .../chat-file-type-zip@2x.png | Bin 0 -> 795 bytes .../Images.xcassets/Controllers/Contents.json | 6 + .../friend-card-chat.imageset/Contents.json | 22 + .../friend-card-chat.png | Bin 0 -> 1090 bytes .../friend-card-chat@2x.png | Bin 0 -> 2199 bytes .../Login/login-logo.imageset/Contents.json | 23 + .../Login/login-logo.imageset/login-logo.png | Bin 0 -> 11512 bytes .../login-logo.imageset/login-logo@2x.png | Bin 0 -> 18617 bytes .../login-logo.imageset/login-logo@3x.png | Bin 0 -> 26780 bytes .../Contents.json | 22 + .../login-password-icon.png | Bin 0 -> 478 bytes .../login-password-icon@2x.png | Bin 0 -> 474 bytes .../login-profile-icon.imageset/Contents.json | 22 + .../login-profile-icon.png | Bin 0 -> 496 bytes .../login-profile-icon@2x.png | Bin 0 -> 573 bytes Antidote/Images.xcassets/Mocks/Contents.json | 6 + .../Mocks/female-1.imageset/Contents.json | 21 + .../Mocks/female-1.imageset/female-1.jpg | Bin 0 -> 5464 bytes .../Mocks/female-2.imageset/Contents.json | 21 + .../Mocks/female-2.imageset/female-2.jpg | Bin 0 -> 4492 bytes .../Mocks/female-3.imageset/Contents.json | 21 + .../Mocks/female-3.imageset/female-3.jpg | Bin 0 -> 4240 bytes .../Mocks/female-4.imageset/Contents.json | 21 + .../Mocks/female-4.imageset/female-4.jpg | Bin 0 -> 6210 bytes .../Mocks/female-5.imageset/Contents.json | 21 + .../Mocks/female-5.imageset/female-5.jpg | Bin 0 -> 5156 bytes .../Mocks/male-1.imageset/Contents.json | 21 + .../Mocks/male-1.imageset/male-1.jpg | Bin 0 -> 5964 bytes .../Mocks/male-2.imageset/Contents.json | 21 + .../Mocks/male-2.imageset/male-2.jpg | Bin 0 -> 5207 bytes .../Mocks/male-3.imageset/Contents.json | 21 + .../Mocks/male-3.imageset/male-3.jpg | Bin 0 -> 26066 bytes .../Mocks/male-4.imageset/Contents.json | 21 + .../Mocks/male-4.imageset/male-4.jpg | Bin 0 -> 5844 bytes .../Mocks/male-5.imageset/Contents.json | 21 + .../Mocks/male-5.imageset/male-5.jpg | Bin 0 -> 4967 bytes Antidote/Images.xcassets/Other/Contents.json | 6 + .../Other/checkmark.imageset/Contents.json | 22 + .../Other/checkmark.imageset/checkmark.png | Bin 0 -> 423 bytes .../Other/checkmark.imageset/checkmark@2x.png | Bin 0 -> 385 bytes .../Contents.json | 23 + .../icon-20.png | Bin 0 -> 4188 bytes .../icon-40.png | Bin 0 -> 1581 bytes .../icon-80.png | Bin 0 -> 4424 bytes .../notification-close.imageset/Contents.json | 22 + .../notification-close.png | Bin 0 -> 378 bytes .../notification-close@2x.png | Bin 0 -> 283 bytes .../Other/right-arrow.imageset/Contents.json | 22 + .../right-arrow.imageset/right-arrow.png | Bin 0 -> 343 bytes .../right-arrow.imageset/right-arrow@2x.png | Bin 0 -> 162 bytes .../tab-bar-chats.imageset/Contents.json | 22 + .../tab-bar-chats.imageset/tab-bar-chats.png | Bin 0 -> 731 bytes .../tab-bar-chats@2x.png | Bin 0 -> 1537 bytes .../tab-bar-friends.imageset/Contents.json | 22 + .../tab-bar-friends.png | Bin 0 -> 639 bytes .../tab-bar-friends@2x.png | Bin 0 -> 1368 bytes .../tab-bar-profile.imageset/Contents.json | 22 + .../tab-bar-profile.png | Bin 0 -> 716 bytes .../tab-bar-profile@2x.png | Bin 0 -> 1471 bytes .../tab-bar-settings.imageset/Contents.json | 22 + .../tab-bar-settings.png | Bin 0 -> 782 bytes .../tab-bar-settings@2x.png | Bin 0 -> 1835 bytes Antidote/IncompressibleView.swift | 13 + Antidote/InterfaceIdiom.swift | 21 + Antidote/KeyboardNotificationController.swift | 70 + Antidote/KeyboardObserver.swift | 36 + Antidote/KeychainManager.swift | 182 + Antidote/Launch Screen.storyboard | 99 + Antidote/LaunchPlaceholderBoard.storyboard | 100 + Antidote/LaunchPlaceholderController.swift | 8 + Antidote/LinearProgressBar.swift | 163 + Antidote/LoadingImageView.swift | 199 + Antidote/LocationManager.swift | 193 + Antidote/Logger.swift | 10 + Antidote/LoginBaseController.swift | 63 + Antidote/LoginChoiceController.swift | 95 + Antidote/LoginCoordinator.swift | 313 + Antidote/LoginCreateAccountController.swift | 80 + Antidote/LoginCreateAccountCoordinator.swift | 98 + Antidote/LoginCreatePasswordController.swift | 46 + Antidote/LoginFormController.swift | 339 + Antidote/LoginGenericCreateController.swift | 154 + Antidote/LoginLogoController.swift | 89 + Antidote/NSDateFormatterExtension.swift | 35 + Antidote/NSTimerExtension.swift | 30 + Antidote/NSURLExtension.swift | 29 + Antidote/NotificationCoordinator.swift | 398 ++ Antidote/NotificationObject.swift | 82 + Antidote/NotificationWindow.swift | 133 + .../OCTManagerConfigurationExtension.swift | 25 + Antidote/OCTManagerMock.swift | 198 + Antidote/OCTSubmanagerBootstrapMock.swift | 19 + Antidote/OCTSubmanagerCallsMock.swift | 50 + Antidote/OCTSubmanagerCallsSnapshotMock.swift | 50 + Antidote/OCTSubmanagerChatsMock.swift | 40 + Antidote/OCTSubmanagerFilesMock.swift | 39 + Antidote/OCTSubmanagerFriendsMock.swift | 23 + Antidote/OCTSubmanagerObjectsExtension.swift | 77 + Antidote/OCTSubmanagerObjectsMock.swift | 58 + Antidote/OCTSubmanagerUserMock.swift | 48 + Antidote/PinAuthorizationCoordinator.swift | 241 + Antidote/PinInputView.swift | 353 + Antidote/PortraitNavigationController.swift | 15 + Antidote/PrimaryIpadController.swift | 160 + Antidote/ProfileDetailsController.swift | 200 + Antidote/ProfileMainController.swift | 322 + Antidote/ProfileManager.swift | 85 + Antidote/ProfileSettings.swift | 58 + Antidote/ProfileTabCoordinator.swift | 202 + Antidote/ProgressCircleView.swift | 71 + Antidote/QRScannerAimView.swift | 38 + Antidote/QRScannerController.swift | 179 + Antidote/QRViewerController.swift | 99 + Antidote/QuickLookPreviewController.swift | 14 + Antidote/Reach.swift | 119 + Antidote/Results.swift | 82 + Antidote/ResultsChange.swift | 12 + Antidote/ResultsExtension.swift | 21 + Antidote/RoundedButton.swift | 52 + Antidote/RunningCoordinator.swift | 92 + Antidote/SettingsAboutController.swift | 61 + Antidote/SettingsAdvancedController.swift | 60 + Antidote/SettingsMainController.swift | 149 + Antidote/SettingsTabCoordinator.swift | 95 + Antidote/StaticBackgroundView.swift | 21 + Antidote/StaticTableAvatarCell.swift | 95 + Antidote/StaticTableAvatarCellModel.swift | 16 + Antidote/StaticTableBaseCell.swift | 68 + Antidote/StaticTableBaseCellModel.swift | 9 + Antidote/StaticTableButtonCell.swift | 66 + Antidote/StaticTableButtonCellModel.swift | 9 + Antidote/StaticTableChatButtonsCell.swift | 138 + .../StaticTableChatButtonsCellModel.swift | 15 + Antidote/StaticTableController.swift | 169 + Antidote/StaticTableDefaultCell.swift | 258 + Antidote/StaticTableDefaultCellModel.swift | 28 + Antidote/StaticTableInfoCell.swift | 123 + Antidote/StaticTableInfoCellModel.swift | 12 + .../StaticTableMultiChoiceButtonCell.swift | 91 + ...taticTableMultiChoiceButtonCellModel.swift | 21 + Antidote/StaticTableSelectableCellModel.swift | 9 + Antidote/StaticTableSwitchCell.swift | 122 + Antidote/StaticTableSwitchCellModel.swift | 14 + Antidote/StringExtension.swift | 70 + Antidote/TabBarAbstractItem.swift | 33 + Antidote/TabBarBadgeItem.swift | 184 + Antidote/TabBarController.swift | 163 + Antidote/TabBarProfileItem.swift | 110 + Antidote/TextEditController.swift | 93 + Antidote/TextViewController.swift | 82 + Antidote/Theme.swift | 242 + Antidote/TopCoordinatorProtocol.swift | 23 + Antidote/ToxFactory.swift | 22 + Antidote/UIAlertControllerExtension.swift | 63 + Antidote/UIApplicationExtension.swift | 20 + Antidote/UIColorExtension.swift | 59 + Antidote/UIFontExtension.swift | 47 + Antidote/UIImageExtension.swift | 86 + Antidote/UIViewControllerExtension.swift | 14 + Antidote/UserDefaultsManager.swift | 139 + Antidote/UserStatus.swift | 38 + Antidote/UserStatusView.swift | 114 + Antidote/ViewPassingGestures.swift | 19 + Antidote/antidote-acknowledgements.html | 578 ++ Antidote/appstore-512_orig.png | Bin 0 -> 10027 bytes Antidote/appstore.png | Bin 0 -> 77165 bytes Antidote/appstore.svg | 1 + Antidote/ar.lproj/InfoPlist.strings | Bin 0 -> 978 bytes Antidote/ar.lproj/Localizable.strings | 415 ++ Antidote/ar.lproj/import-profile.html | 9 + Antidote/br.lproj/InfoPlist.strings | Bin 0 -> 1092 bytes Antidote/br.lproj/Localizable.strings | 415 ++ Antidote/br.lproj/import-profile.html | 9 + Antidote/ca.lproj/AppStoreLocalizable.strings | 54 + Antidote/ca.lproj/InfoPlist.strings | 16 + Antidote/ca.lproj/Localizable.strings | 404 ++ Antidote/ca.lproj/import-profile.html | 10 + Antidote/cs.lproj/InfoPlist.strings | Bin 0 -> 998 bytes Antidote/cs.lproj/Localizable.strings | 411 ++ Antidote/cs.lproj/import-profile.html | 9 + Antidote/da.lproj/AppStoreLocalizable.strings | Bin 0 -> 7646 bytes Antidote/da.lproj/InfoPlist.strings | Bin 0 -> 982 bytes Antidote/da.lproj/Localizable.strings | 411 ++ Antidote/da.lproj/import-profile.html | 9 + Antidote/de.lproj/AppStoreLocalizable.strings | Bin 0 -> 7588 bytes Antidote/de.lproj/InfoPlist.strings | Bin 0 -> 1050 bytes Antidote/de.lproj/Localizable.strings | 411 ++ Antidote/de.lproj/import-profile.html | 9 + Antidote/default-theme.yaml | 86 + Antidote/dummy-photo.jpg | Bin 0 -> 6266 bytes Antidote/el.lproj/Localizable.strings | 404 ++ Antidote/en.lproj/AppStoreLocalizable.strings | 54 + Antidote/en.lproj/InfoPlist.strings | 16 + Antidote/en.lproj/Localizable.strings | 410 ++ Antidote/en.lproj/import-profile.html | 10 + Antidote/enm.lproj/Localizable.strings | 1 + Antidote/es.lproj/AppStoreLocalizable.strings | Bin 0 -> 7612 bytes Antidote/es.lproj/InfoPlist.strings | Bin 0 -> 978 bytes Antidote/es.lproj/Localizable.strings | 415 ++ Antidote/es.lproj/import-profile.html | 9 + Antidote/fr.lproj/AppStoreLocalizable.strings | Bin 0 -> 7690 bytes Antidote/fr.lproj/InfoPlist.strings | Bin 0 -> 978 bytes Antidote/fr.lproj/Localizable.strings | 415 ++ Antidote/fr.lproj/import-profile.html | 9 + Antidote/iPadFriendsButton.swift | 91 + Antidote/iPadNavigationView.swift | 73 + Antidote/icons8-key-1024.png | Bin 0 -> 36420 bytes Antidote/isotoxin_Calltone.aac | Bin 0 -> 60757 bytes Antidote/isotoxin_Hangup.aac | Bin 0 -> 38229 bytes Antidote/isotoxin_NewMessage.aac | Bin 0 -> 8874 bytes Antidote/isotoxin_Ringtone.aac | Bin 0 -> 79530 bytes Antidote/isotoxin_RingtoneWhileCall.aac | Bin 0 -> 79872 bytes Antidote/it.lproj/AppStoreLocalizable.strings | 54 + Antidote/it.lproj/InfoPlist.strings | 16 + Antidote/it.lproj/Localizable.strings | 404 ++ Antidote/ko.lproj/AppStoreLocalizable.strings | 54 + Antidote/ko.lproj/InfoPlist.strings | 16 + Antidote/ko.lproj/Localizable.strings | 410 ++ Antidote/ko.lproj/import-profile.html | 10 + Antidote/lt.lproj/InfoPlist.strings | Bin 0 -> 1074 bytes Antidote/lt.lproj/Localizable.strings | 415 ++ Antidote/lt.lproj/import-profile.html | 9 + Antidote/nb.lproj/AppStoreLocalizable.strings | 54 + Antidote/nb.lproj/InfoPlist.strings | 16 + Antidote/nb.lproj/Localizable.strings | 398 ++ Antidote/nb.lproj/import-profile.html | 10 + Antidote/nl.lproj/AppStoreLocalizable.strings | Bin 0 -> 7612 bytes Antidote/nl.lproj/InfoPlist.strings | Bin 0 -> 978 bytes Antidote/nl.lproj/Localizable.strings | 415 ++ Antidote/nl.lproj/import-profile.html | 9 + Antidote/old_antidote_logo_with_text.png | Bin 0 -> 38036 bytes Antidote/pl.lproj/InfoPlist.strings | Bin 0 -> 978 bytes Antidote/pl.lproj/Localizable.strings | 415 ++ Antidote/pl.lproj/import-profile.html | 9 + .../pt-BR.lproj/AppStoreLocalizable.strings | 54 + Antidote/pt-BR.lproj/InfoPlist.strings | 16 + Antidote/pt-BR.lproj/Localizable.strings | 404 ++ Antidote/pt-BR.lproj/import-profile.html | 10 + Antidote/pt.lproj/AppStoreLocalizable.strings | Bin 0 -> 7612 bytes Antidote/pt.lproj/InfoPlist.strings | Bin 0 -> 978 bytes Antidote/pt.lproj/Localizable.strings | 415 ++ Antidote/pt.lproj/import-profile.html | 9 + Antidote/ru.lproj/AppStoreLocalizable.strings | Bin 0 -> 7612 bytes Antidote/ru.lproj/InfoPlist.strings | Bin 0 -> 1028 bytes Antidote/ru.lproj/Localizable.strings | 415 ++ Antidote/ru.lproj/import-profile.html | 9 + Antidote/sv.lproj/Localizable.strings | 34 + Antidote/tr.lproj/Localizable.strings | 14 + Antidote/zgh.lproj/Localizable.strings | 404 ++ Antidote/zh.lproj/AppStoreLocalizable.strings | Bin 0 -> 7612 bytes Antidote/zh.lproj/InfoPlist.strings | Bin 0 -> 978 bytes Antidote/zh.lproj/Localizable.strings | 415 ++ Antidote/zh.lproj/import-profile.html | 9 + AntidoteTests/AntidoteTests-Bridging-Header.h | 45 + AntidoteTests/CellSnapshotTest.swift | 15 + .../ChatIncomingCallCellSnapshotTest.swift | 37 + .../ChatIncomingFileCellSnapshotTest.swift | 109 + .../ChatIncomingTextCellSnapshotTest.swift | 67 + AntidoteTests/ChatListCellSnapshotTest.swift | 62 + .../ChatMovableDateCellSnapshotTest.swift | 36 + .../ChatOutgoingCallCellSnapshotTest.swift | 37 + .../ChatOutgoingFileCellSnapshotTest.swift | 179 + .../ChatOutgoingTextCellSnapshotTest.swift | 83 + AntidoteTests/FriendListDataSourceTest.swift | 159 + AntidoteTests/Info.plist | 24 + AntidoteTests/KeychainManagerTests.swift | 52 + .../LoginChoiceViewSnapshotTest.swift | 18 + .../MockedChatProgressProtocol.swift | 10 + .../testAnsweredCall_normal@2x.png | Bin 0 -> 4437 bytes .../testAnsweredCall_right-to-left@2x.png | Bin 0 -> 4508 bytes .../testNonAnsweredCall_normal@2x.png | Bin 0 -> 4978 bytes .../testNonAnsweredCall_right-to-left@2x.png | Bin 0 -> 5049 bytes .../testCancelled_normal@2x.png | Bin 0 -> 13493 bytes .../testCancelled_right-to-left@2x.png | Bin 0 -> 13553 bytes .../testDoneWithImage_normal@2x.png | Bin 0 -> 20365 bytes .../testDoneWithImage_right-to-left@2x.png | Bin 0 -> 20610 bytes .../testDone_normal@2x.png | Bin 0 -> 11603 bytes .../testDone_right-to-left@2x.png | Bin 0 -> 11681 bytes .../testLoading_normal@2x.png | Bin 0 -> 17863 bytes .../testLoading_right-to-left@2x.png | Bin 0 -> 18041 bytes .../testPaused_normal@2x.png | Bin 0 -> 14146 bytes .../testPaused_right-to-left@2x.png | Bin 0 -> 14377 bytes .../testWaitingState_normal@2x.png | Bin 0 -> 16254 bytes .../testWaitingState_right-to-left@2x.png | Bin 0 -> 16451 bytes .../testHugeMessage_normal@2x.png | Bin 0 -> 90942 bytes .../testHugeMessage_right-to-left@2x.png | Bin 0 -> 90940 bytes .../testMediumMessage_normal@2x.png | Bin 0 -> 8591 bytes .../testMediumMessage_right-to-left@2x.png | Bin 0 -> 8591 bytes .../testSmallMessage_normal@2x.png | Bin 0 -> 2793 bytes .../testSmallMessage_right-to-left@2x.png | Bin 0 -> 2769 bytes .../testWithLink_normal@2x.png | Bin 0 -> 24126 bytes .../testWithLink_right-to-left@2x.png | Bin 0 -> 24123 bytes .../testDefault_normal@2x.png | Bin 0 -> 12582 bytes .../testDefault_right-to-left@2x.png | Bin 0 -> 13229 bytes .../testLongMessage_normal@2x.png | Bin 0 -> 15382 bytes .../testLongMessage_right-to-left@2x.png | Bin 0 -> 14536 bytes .../testUnread_normal@2x.png | Bin 0 -> 12262 bytes .../testUnread_right-to-left@2x.png | Bin 0 -> 12722 bytes .../testDefault_normal@2x.png | Bin 0 -> 22534 bytes .../testDefault_right-to-left@2x.png | Bin 0 -> 22534 bytes .../testPanned_normal@2x.png | Bin 0 -> 23766 bytes .../testPanned_right-to-left@2x.png | Bin 0 -> 23998 bytes .../testAnsweredCall_normal@2x.png | Bin 0 -> 4439 bytes .../testAnsweredCall_right-to-left@2x.png | Bin 0 -> 4504 bytes .../testNonAnsweredCall_normal@2x.png | Bin 0 -> 5995 bytes .../testNonAnsweredCall_right-to-left@2x.png | Bin 0 -> 5717 bytes .../testCancelledWithImage_normal@2x.png | Bin 0 -> 23967 bytes ...estCancelledWithImage_right-to-left@2x.png | Bin 0 -> 23650 bytes .../testCancelled_normal@2x.png | Bin 0 -> 13245 bytes .../testCancelled_right-to-left@2x.png | Bin 0 -> 13226 bytes .../testDoneWithImage_normal@2x.png | Bin 0 -> 20610 bytes .../testDoneWithImage_right-to-left@2x.png | Bin 0 -> 20365 bytes .../testDone_normal@2x.png | Bin 0 -> 11651 bytes .../testDone_right-to-left@2x.png | Bin 0 -> 11636 bytes .../testLoadingWithImage_normal@2x.png | Bin 0 -> 25592 bytes .../testLoadingWithImage_right-to-left@2x.png | Bin 0 -> 25420 bytes .../testLoading_normal@2x.png | Bin 0 -> 16426 bytes .../testLoading_right-to-left@2x.png | Bin 0 -> 16403 bytes .../testPausedWithImage_normal@2x.png | Bin 0 -> 22815 bytes .../testPausedWithImage_right-to-left@2x.png | Bin 0 -> 22603 bytes .../testPaused_normal@2x.png | Bin 0 -> 12660 bytes .../testPaused_right-to-left@2x.png | Bin 0 -> 12596 bytes .../testWaitingStateWithImage_normal@2x.png | Bin 0 -> 22115 bytes ...WaitingStateWithImage_right-to-left@2x.png | Bin 0 -> 21694 bytes .../testWaitingState_normal@2x.png | Bin 0 -> 13678 bytes .../testWaitingState_right-to-left@2x.png | Bin 0 -> 13596 bytes .../testHugeMessage_normal@2x.png | Bin 0 -> 86549 bytes .../testHugeMessage_right-to-left@2x.png | Bin 0 -> 86622 bytes ...testMediumMessageUndelivered_normal@2x.png | Bin 0 -> 8585 bytes ...iumMessageUndelivered_right-to-left@2x.png | Bin 0 -> 8585 bytes .../testMediumMessage_normal@2x.png | Bin 0 -> 8242 bytes .../testMediumMessage_right-to-left@2x.png | Bin 0 -> 8242 bytes .../testSmallMessage_normal@2x.png | Bin 0 -> 2767 bytes .../testSmallMessage_right-to-left@2x.png | Bin 0 -> 2792 bytes .../testWithLink_normal@2x.png | Bin 0 -> 23757 bytes .../testWithLink_right-to-left@2x.png | Bin 0 -> 23810 bytes .../testDefault_normal@2x.png | Bin 0 -> 126358 bytes .../testDefault_right-to-left@2x.png | Bin 0 -> 126358 bytes AntidoteTests/SnapshotBaseTest.swift | 44 + AntidoteTests/SwiftSupport.swift | 125 + AntidoteTests/ThemeTest.swift | 197 + AntidoteTests/icon.png | Bin 0 -> 2756 bytes CHANGELOG.md | 365 + FAQ/en.md | 78 + Gemfile | 4 + LICENSE | 373 ++ PRIVACY_POLICY.md | 66 + Podfile | 32 + README.md | 90 + ScreenshotsUITests/Info.plist | 24 + .../ScreenshotUITests-Bridging-Header.h | 46 + ScreenshotsUITests/ScreenshotsUITests.swift | 178 + XOLDX_fastlane/Appfile | 7 + XOLDX_fastlane/Deliverfile | 10 + XOLDX_fastlane/Fastfile | 70 + XOLDX_fastlane/README.md | 60 + XOLDX_fastlane/Snapfile | 20 + XOLDX_fastlane/SnapshotHelper.swift | 138 + XOLDX_fastlane/SnapshotHelper2-3.swift | 140 + XOLDX_fastlane/metadata/app_icon.png | Bin 0 -> 33119 bytes XOLDX_fastlane/metadata/copyright.txt | 1 + .../metadata/default/marketing_url.txt | 1 + XOLDX_fastlane/metadata/default/name.txt | 1 + .../metadata/default/privacy_url.txt | 1 + .../metadata/default/release_notes.txt | 3 + .../metadata/default/support_url.txt | 1 + XOLDX_fastlane/metadata/en-US/description.txt | 29 + XOLDX_fastlane/metadata/en-US/keywords.txt | 1 + XOLDX_fastlane/metadata/fr-FR/description.txt | 29 + XOLDX_fastlane/metadata/fr-FR/keywords.txt | 1 + XOLDX_fastlane/metadata/primary_category.txt | 1 + .../metadata/primary_first_sub_category.txt | 1 + .../metadata/primary_second_sub_category.txt | 1 + .../metadata/secondary_category.txt | 1 + .../metadata/secondary_first_sub_category.txt | 1 + .../secondary_second_sub_category.txt | 1 + docs/app001.png | Bin 0 -> 103141 bytes docs/app002.png | Bin 0 -> 43297 bytes docs/app003.png | Bin 0 -> 40132 bytes docs/app004.png | Bin 0 -> 96162 bytes docs/applewatch_push.jpg | Bin 0 -> 345261 bytes docs/appstore-badge.png | Bin 0 -> 4714 bytes docs/iphone_send_crashreports.png | Bin 0 -> 269738 bytes docs/release_checklist.md | 17 + fastlane/.gitignore | 3 + fastlane/Appfile | 7 + fastlane/Fastfile | 24 + local_pod_repo/cmp/.gitignore | 32 + local_pod_repo/cmp/LICENSE | 22 + local_pod_repo/cmp/cmp.podspec | 30 + local_pod_repo/cmp/cmp/.gitignore | 54 + local_pod_repo/cmp/cmp/CMakeLists.txt | 4 + local_pod_repo/cmp/cmp/CODE_OF_CONDUCT.md | 50 + local_pod_repo/cmp/cmp/LICENSE | 22 + local_pod_repo/cmp/cmp/Makefile | 123 + local_pod_repo/cmp/cmp/README.md | 223 + local_pod_repo/cmp/cmp/TODO.md | 14 + local_pod_repo/cmp/cmp/cmp.c | 3561 ++++++++++ local_pod_repo/cmp/cmp/cmp.h | 572 ++ local_pod_repo/cmp/cmp/examples/example1.c | 116 + local_pod_repo/cmp/cmp/examples/example2.c | 531 ++ local_pod_repo/cmp/cmp/test/buf.c | 569 ++ local_pod_repo/cmp/cmp/test/buf.h | 138 + local_pod_repo/cmp/cmp/test/cases.mpac | Bin 0 -> 213 bytes local_pod_repo/cmp/cmp/test/profile.c | 55 + local_pod_repo/cmp/cmp/test/test.c | 67 + local_pod_repo/cmp/cmp/test/tests.c | 5951 +++++++++++++++++ local_pod_repo/cmp/cmp/test/tests.h | 45 + local_pod_repo/cmp/cmp/test/utils.c | 58 + local_pod_repo/cmp/cmp/test/utils.h | 52 + local_pod_repo/msgpack-c/.gitignore | 32 + local_pod_repo/msgpack-c/LICENSE | 674 ++ local_pod_repo/msgpack-c/msgpack-c.podspec | 35 + local_pod_repo/msgpack-c/msgpack-c/.gitignore | 51 + .../msgpack-c/msgpack-c/CHANGELOG.md | 424 ++ .../msgpack-c/msgpack-c/CMakeLists.txt | 333 + local_pod_repo/msgpack-c/msgpack-c/COPYING | 5 + local_pod_repo/msgpack-c/msgpack-c/Doxyfile | 1552 +++++ .../msgpack-c/msgpack-c/Files.cmake | 41 + .../msgpack-c/msgpack-c/LICENSE_1_0.txt | 23 + local_pod_repo/msgpack-c/msgpack-c/NOTICE | 14 + .../msgpack-c/msgpack-c/QUICKSTART-C.md | 193 + local_pod_repo/msgpack-c/msgpack-c/README.md | 139 + .../msgpack-c/msgpack-c/appveyor.yml | 43 + .../msgpack-c/msgpack-c/codecov.yml | 36 + .../msgpack-c/msgpack-c/include/msgpack.h | 24 + .../msgpack-c/include/msgpack/fbuffer.h | 42 + .../msgpack-c/include/msgpack/gcc_atomic.h | 25 + .../include/msgpack/msgpack_version.h | 38 + .../msgpack-c/include/msgpack/object.h | 118 + .../msgpack-c/include/msgpack/pack.h | 174 + .../msgpack-c/include/msgpack/pack_define.h | 18 + .../msgpack-c/include/msgpack/pack_template.h | 952 +++ .../msgpack-c/include/msgpack/sbuffer.h | 115 + .../msgpack-c/include/msgpack/sysdep.h | 228 + .../msgpack-c/include/msgpack/timestamp.h | 58 + .../msgpack-c/include/msgpack/unpack.h | 281 + .../msgpack-c/include/msgpack/unpack_define.h | 89 + .../include/msgpack/unpack_template.h | 471 ++ .../msgpack-c/include/msgpack/util.h | 15 + .../include/msgpack/version_master.h | 3 + .../msgpack-c/include/msgpack/vrefbuffer.h | 146 + .../msgpack-c/include/msgpack/zbuffer.h | 205 + .../msgpack-c/include/msgpack/zone.h | 163 + .../msgpack-c/msgpack-config.cmake.in | 19 + .../msgpack-c/msgpack-c/msgpack.pc.in | 10 + .../msgpack-c/msgpack-c/src/objectc.c | 484 ++ .../msgpack-c/msgpack-c/src/unpack.c | 702 ++ .../msgpack-c/msgpack-c/src/version.c | 22 + .../msgpack-c/msgpack-c/src/vrefbuffer.c | 250 + local_pod_repo/msgpack-c/msgpack-c/src/zone.c | 222 + local_pod_repo/objcTox/.gitignore | 31 + .../Manager/Audio/OCTAudioEngine+Private.h | 33 + .../Private/Manager/Audio/OCTAudioEngine.h | 92 + .../Private/Manager/Audio/OCTAudioEngine.m | 191 + .../Private/Manager/Audio/OCTAudioQueue.h | 74 + .../Private/Manager/Audio/OCTAudioQueue.m | 425 ++ .../Configuration/OCTDefaultFileStorage.m | 77 + .../Configuration/OCTManagerConfiguration.m | 51 + .../Manager/Database/OCTRealmManager.h | 112 + .../Manager/Database/OCTRealmManager.m | 665 ++ .../Private/Manager/Files/NSError+OCTFile.h | 31 + .../Private/Manager/Files/NSError+OCTFile.m | 189 + .../Files/OCTFileBaseOperation+Private.h | 42 + .../Manager/Files/OCTFileBaseOperation.h | 85 + .../Manager/Files/OCTFileBaseOperation.m | 286 + .../Private/Manager/Files/OCTFileDataInput.h | 15 + .../Private/Manager/Files/OCTFileDataInput.m | 50 + .../Private/Manager/Files/OCTFileDataOutput.h | 15 + .../Private/Manager/Files/OCTFileDataOutput.m | 42 + .../Manager/Files/OCTFileDownloadOperation.h | 45 + .../Manager/Files/OCTFileDownloadOperation.m | 111 + .../Manager/Files/OCTFileInputProtocol.h | 27 + .../Manager/Files/OCTFileOutputProtocol.h | 37 + .../Private/Manager/Files/OCTFilePathInput.h | 15 + .../Private/Manager/Files/OCTFilePathInput.m | 61 + .../Private/Manager/Files/OCTFilePathOutput.h | 19 + .../Private/Manager/Files/OCTFilePathOutput.m | 100 + .../Private/Manager/Files/OCTFileTools.h | 20 + .../Private/Manager/Files/OCTFileTools.m | 77 + .../Manager/Files/OCTFileUploadOperation.h | 39 + .../Manager/Files/OCTFileUploadOperation.m | 109 + .../Messages/OCTSendMessageOperation.h | 42 + .../Messages/OCTSendMessageOperation.m | 80 + .../Private/Manager/OCTManagerConstants.m | 8 + .../Private/Manager/OCTManagerFactory.m | 475 ++ .../Classes/Private/Manager/OCTManagerImpl.h | 27 + .../Classes/Private/Manager/OCTManagerImpl.m | 347 + .../Manager/Objects/OCTCall+Utilities.h | 11 + .../Manager/Objects/OCTCall+Utilities.m | 14 + .../Classes/Private/Manager/Objects/OCTCall.m | 28 + .../Private/Manager/Objects/OCTCallTimer.h | 25 + .../Private/Manager/Objects/OCTCallTimer.m | 87 + .../Classes/Private/Manager/Objects/OCTChat.m | 39 + .../Private/Manager/Objects/OCTFriend.m | 41 + .../Manager/Objects/OCTFriendRequest.m | 33 + .../Manager/Objects/OCTMessageAbstract.m | 49 + .../Private/Manager/Objects/OCTMessageCall.m | 34 + .../Private/Manager/Objects/OCTMessageFile.m | 36 + .../Private/Manager/Objects/OCTMessageText.m | 31 + .../Classes/Private/Manager/Objects/OCTNode.h | 30 + .../Classes/Private/Manager/Objects/OCTNode.m | 71 + .../Private/Manager/Objects/OCTObject.m | 55 + .../Objects/OCTSettingsStorageObject.h | 22 + .../Objects/OCTSettingsStorageObject.m | 17 + .../Submanagers/OCTSubmanagerBootstrapImpl.h | 10 + .../Submanagers/OCTSubmanagerBootstrapImpl.m | 255 + .../Submanagers/OCTSubmanagerCallsImpl.h | 27 + .../Submanagers/OCTSubmanagerCallsImpl.m | 564 ++ .../Submanagers/OCTSubmanagerChatsImpl.h | 10 + .../Submanagers/OCTSubmanagerChatsImpl.m | 529 ++ .../Submanagers/OCTSubmanagerDataSource.h | 46 + .../Submanagers/OCTSubmanagerFilesImpl.h | 10 + .../Submanagers/OCTSubmanagerFilesImpl.m | 1000 +++ .../Submanagers/OCTSubmanagerFriendsImpl.h | 10 + .../Submanagers/OCTSubmanagerFriendsImpl.m | 361 + .../Submanagers/OCTSubmanagerObjectsImpl.h | 10 + .../Submanagers/OCTSubmanagerObjectsImpl.m | 103 + .../Submanagers/OCTSubmanagerProtocol.h | 16 + .../Submanagers/OCTSubmanagerUserImpl.h | 10 + .../Submanagers/OCTSubmanagerUserImpl.m | 132 + .../Manager/Video/OCTPixelBufferPool.h | 23 + .../Manager/Video/OCTPixelBufferPool.m | 103 + .../Private/Manager/Video/OCTVideoEngine.h | 118 + .../Private/Manager/Video/OCTVideoEngine.m | 489 ++ .../Private/Manager/Video/OCTVideoView.h | 22 + .../Private/Manager/Video/OCTVideoView.m | 100 + .../Classes/Private/Wrapper/OCTLogging.h | 25 + .../Classes/Private/Wrapper/OCTTox+Private.h | 63 + .../objcTox/Classes/Private/Wrapper/OCTTox.m | 2250 +++++++ .../Private/Wrapper/OCTToxAV+Private.h | 51 + .../Classes/Private/Wrapper/OCTToxAV.m | 648 ++ .../Private/Wrapper/OCTToxAVConstants.m | 9 + .../Classes/Private/Wrapper/OCTToxConstants.m | 25 + .../Private/Wrapper/OCTToxEncryptSave.m | 272 + .../Private/Wrapper/OCTToxOptions+Private.h | 11 + .../Classes/Private/Wrapper/OCTToxOptions.m | 212 + .../Configuration/OCTDefaultFileStorage.h | 39 + .../Configuration/OCTFileStorageProtocol.h | 66 + .../Configuration/OCTManagerConfiguration.h | 60 + .../Classes/Public/Manager/OCTManager.h | 95 + .../Public/Manager/OCTManagerConstants.h | 326 + .../Public/Manager/OCTManagerFactory.h | 35 + .../Classes/Public/Manager/Objects/OCTCall.h | 84 + .../Classes/Public/Manager/Objects/OCTChat.h | 74 + .../Public/Manager/Objects/OCTFriend.h | 110 + .../Public/Manager/Objects/OCTFriendRequest.h | 35 + .../Manager/Objects/OCTMessageAbstract.h | 67 + .../Public/Manager/Objects/OCTMessageCall.h | 20 + .../Public/Manager/Objects/OCTMessageFile.h | 61 + .../Public/Manager/Objects/OCTMessageText.h | 49 + .../Public/Manager/Objects/OCTObject.h | 33 + .../Classes/Public/Manager/Objects/OCTView.h | 17 + .../Submanagers/OCTSubmanagerBootstrap.h | 57 + .../Manager/Submanagers/OCTSubmanagerCalls.h | 145 + .../Submanagers/OCTSubmanagerCallsDelegate.h | 15 + .../Manager/Submanagers/OCTSubmanagerChats.h | 84 + .../Manager/Submanagers/OCTSubmanagerFiles.h | 124 + .../OCTSubmanagerFilesProgressSubscriber.h | 30 + .../Submanagers/OCTSubmanagerFriends.h | 53 + .../Submanagers/OCTSubmanagerObjects.h | 72 + .../Manager/Submanagers/OCTSubmanagerUser.h | 104 + .../objcTox/Classes/Public/Manager/nodes.json | 776 +++ .../objcTox/Classes/Public/Wrapper/OCTTox.h | 567 ++ .../objcTox/Classes/Public/Wrapper/OCTToxAV.h | 148 + .../Public/Wrapper/OCTToxAVConstants.h | 339 + .../Classes/Public/Wrapper/OCTToxAVDelegate.h | 95 + .../Classes/Public/Wrapper/OCTToxConstants.h | 557 ++ .../Classes/Public/Wrapper/OCTToxDelegate.h | 219 + .../Public/Wrapper/OCTToxEncryptSave.h | 93 + .../Wrapper/OCTToxEncryptSaveConstants.h | 41 + .../Classes/Public/Wrapper/OCTToxOptions.h | 103 + local_pod_repo/objcTox/Gemfile | 5 + local_pod_repo/objcTox/OSXDemo/AppDelegate.h | 10 + local_pod_repo/objcTox/OSXDemo/AppDelegate.m | 34 + .../objcTox/OSXDemo/Base.lproj/MainMenu.xib | 667 ++ .../AppIcon.appiconset/Contents.json | 58 + local_pod_repo/objcTox/OSXDemo/Info.plist | 34 + local_pod_repo/objcTox/OSXDemo/MainWindow.xib | 72 + .../objcTox/OSXDemo/OCTBootStrap.xib | 67 + .../OSXDemo/OCTBootStrapViewController.h | 21 + .../OSXDemo/OCTBootStrapViewController.m | 42 + .../objcTox/OSXDemo/OCTCallsViewController.h | 13 + .../objcTox/OSXDemo/OCTCallsViewController.m | 203 + .../OSXDemo/OCTCallsViewController.xib | 152 + .../OSXDemo/OCTConversationViewController.h | 12 + .../OSXDemo/OCTConversationViewController.m | 270 + .../OSXDemo/OCTConversationViewController.xib | 230 + .../objcTox/OSXDemo/OCTFilesViewController.h | 13 + .../objcTox/OSXDemo/OCTFilesViewController.m | 236 + .../OSXDemo/OCTFilesViewController.xib | 176 + .../OSXDemo/OCTFriendsViewController.h | 12 + .../OSXDemo/OCTFriendsViewController.m | 255 + .../OSXDemo/OCTFriendsViewController.xib | 295 + .../objcTox/OSXDemo/OCTMainWindowController.h | 9 + .../objcTox/OSXDemo/OCTMainWindowController.m | 100 + .../objcTox/OSXDemo/OCTUserViewController.h | 12 + .../objcTox/OSXDemo/OCTUserViewController.m | 268 + .../objcTox/OSXDemo/OCTUserViewController.xib | 163 + .../OSXDemo/RLMCollectionChange+IndexSet.h | 14 + .../OSXDemo/RLMCollectionChange+IndexSet.m | 39 + local_pod_repo/objcTox/OSXDemo/main.m | 10 + .../objcTox/OSXDemoTests/Info.plist | 24 + local_pod_repo/objcTox/Podfile | 45 + local_pod_repo/objcTox/README.md | 12 + local_pod_repo/objcTox/Tests/CoreAudioMocks.h | 25 + .../objcTox/Tests/OCTAudioEngineTests.m | 231 + .../objcTox/Tests/OCTAudioQueueTests.m | 450 ++ local_pod_repo/objcTox/Tests/OCTCAsserts.h | 31 + .../objcTox/Tests/OCTCallTimerTests.m | 73 + local_pod_repo/objcTox/Tests/OCTChatTests.m | 76 + .../Tests/OCTDefaultFileStorageTests.m | 49 + .../objcTox/Tests/OCTFileToolsTests.m | 127 + .../objcTox/Tests/OCTFriendRequestTests.m | 37 + .../Tests/OCTManagerConfigurationTests.m | 84 + .../objcTox/Tests/OCTManagerImplTests.m | 514 ++ .../objcTox/Tests/OCTMessageAbstractTests.m | 52 + local_pod_repo/objcTox/Tests/OCTObjectTests.m | 40 + local_pod_repo/objcTox/Tests/OCTRealmTests.h | 28 + local_pod_repo/objcTox/Tests/OCTRealmTests.m | 61 + .../Tests/OCTSubmanagerBootstrapImplTests.m | 211 + .../Tests/OCTSubmanagerCallsImplTests.m | 527 ++ .../Tests/OCTSubmanagerChatsImplTests.m | 486 ++ .../Tests/OCTSubmanagerFilesImplTests.m | 26 + .../Tests/OCTSubmanagerFriendsImplTests.m | 481 ++ .../Tests/OCTSubmanagerObjectsImplTests.m | 195 + .../Tests/OCTSubmanagerUserImplTests.m | 130 + local_pod_repo/objcTox/Tests/OCTToxAVTests.m | 583 ++ .../objcTox/Tests/OCTToxEncryptSaveTests.m | 77 + local_pod_repo/objcTox/Tests/OCTToxTests.m | 784 +++ .../objcTox/Tests/OCTVideoEngineTests.m | 235 + .../Tests/YUVPlanes/test_backwards_3p.h | 77 + .../YUVPlanes/test_backwards_stride13p.h | 77 + .../objcTox/Tests/YUVPlanes/test_good.h | 54 + .../objcTox/Tests/YUVPlanes/test_straight3p.h | 75 + .../objcTox/Tests/YUVPlanes/test_stride13p.h | 74 + .../objcTox/Tests/unencrypted-database.realm | Bin 0 -> 12582912 bytes local_pod_repo/objcTox/codecov.yml | 12 + local_pod_repo/objcTox/iOSDemo/AppDelegate.h | 12 + local_pod_repo/objcTox/iOSDemo/AppDelegate.m | 60 + .../iOSDemo/Base.lproj/LaunchScreen.xib | 41 + .../AppIcon.appiconset/Contents.json | 93 + local_pod_repo/objcTox/iOSDemo/Info.plist | 45 + .../objcTox/iOSDemo/OCTCallsViewController.h | 9 + .../objcTox/iOSDemo/OCTCallsViewController.m | 244 + .../objcTox/iOSDemo/OCTChatsViewController.h | 9 + .../objcTox/iOSDemo/OCTChatsViewController.m | 106 + .../iOSDemo/OCTConversationViewController.h | 13 + .../iOSDemo/OCTConversationViewController.m | 159 + .../iOSDemo/OCTFriendsViewController.h | 9 + .../iOSDemo/OCTFriendsViewController.m | 264 + .../iOSDemo/OCTStartDemoViewController.h | 9 + .../iOSDemo/OCTStartDemoViewController.m | 158 + .../OCTTabBarControllerViewController.h | 10 + .../OCTTabBarControllerViewController.m | 53 + .../objcTox/iOSDemo/OCTTableViewController.h | 32 + .../objcTox/iOSDemo/OCTTableViewController.m | 203 + .../objcTox/iOSDemo/OCTUserViewController.h | 9 + .../objcTox/iOSDemo/OCTUserViewController.m | 189 + .../objcTox/iOSDemo/OCTVideoViewController.h | 14 + .../objcTox/iOSDemo/OCTVideoViewController.m | 248 + local_pod_repo/objcTox/iOSDemo/main.m | 13 + .../objcTox/iOSDemoTests/Info.plist | 24 + local_pod_repo/objcTox/install.sh | 5 + local_pod_repo/objcTox/objcTox.podspec | 37 + .../objcTox/objcTox.xcodeproj/project.pbxproj | 1922 ++++++ .../objcTox/objective-c-style-guide.md | 455 ++ local_pod_repo/objcTox/pre-commit.sh | 66 + local_pod_repo/objcTox/run-uncrustify.sh | 89 + local_pod_repo/objcTox/uncrustify.cfg | 1687 +++++ local_pod_repo/toxcore/.gitignore | 32 + .../toxcore/0002_zoff_tc___capabilites.diff | 187 + local_pod_repo/toxcore/LICENSE | 674 ++ local_pod_repo/toxcore/Podfile | 8 + local_pod_repo/toxcore/README.md | 12 + local_pod_repo/toxcore/build-vpx.sh | 69 + local_pod_repo/toxcore/install-tox.sh | 75 + .../Headers/arm64-darwin-gcc/vpx_config.h | 102 + .../Headers/armv7-darwin-gcc/vpx_config.h | 102 + .../Headers/armv7s-darwin-gcc/vpx_config.h | 102 + .../toxcore/ios/vpx.framework/Headers/vp8.h | 138 + .../toxcore/ios/vpx.framework/Headers/vp8cx.h | 699 ++ .../toxcore/ios/vpx.framework/Headers/vp8dx.h | 159 + .../ios/vpx.framework/Headers/vpx_codec.h | 479 ++ .../ios/vpx.framework/Headers/vpx_config.h | 33 + .../ios/vpx.framework/Headers/vpx_decoder.h | 378 ++ .../ios/vpx.framework/Headers/vpx_encoder.h | 1023 +++ .../vpx.framework/Headers/vpx_frame_buffer.h | 83 + .../ios/vpx.framework/Headers/vpx_image.h | 224 + .../ios/vpx.framework/Headers/vpx_integer.h | 74 + .../ios/vpx.framework/Headers/vpx_version.h | 7 + .../x86-iphonesimulator-gcc/vpx_config.h | 102 + .../x86_64-iphonesimulator-gcc/vpx_config.h | 102 + local_pod_repo/toxcore/ios/vpx.framework/vpx | Bin 0 -> 9422040 bytes local_pod_repo/toxcore/msgv3_addon.patch | 162 + .../toxcore/osx/vpx.framework/Headers/vp8.h | 138 + .../toxcore/osx/vpx.framework/Headers/vp8cx.h | 699 ++ .../toxcore/osx/vpx.framework/Headers/vp8dx.h | 159 + .../osx/vpx.framework/Headers/vpx_codec.h | 479 ++ .../osx/vpx.framework/Headers/vpx_config.h | 21 + .../osx/vpx.framework/Headers/vpx_decoder.h | 378 ++ .../osx/vpx.framework/Headers/vpx_encoder.h | 1023 +++ .../vpx.framework/Headers/vpx_frame_buffer.h | 83 + .../osx/vpx.framework/Headers/vpx_image.h | 224 + .../osx/vpx.framework/Headers/vpx_integer.h | 74 + .../osx/vpx.framework/Headers/vpx_version.h | 7 + .../Headers/x86_64-darwin13-gcc/vpx_config.h | 102 + local_pod_repo/toxcore/osx/vpx.framework/vpx | Bin 0 -> 2522112 bytes local_pod_repo/toxcore/toxcore.podspec | 43 + .../toxcore/toxcore/toxav/Makefile.inc | 50 + local_pod_repo/toxcore/toxcore/toxav/audio.h | 73 + local_pod_repo/toxcore/toxcore/toxav/audio.m | 504 ++ .../toxcore/toxcore/toxav/bwcontroller.h | 23 + .../toxcore/toxcore/toxav/bwcontroller.m | 222 + .../toxcore/toxcore/toxav/groupav.h | 64 + .../toxcore/toxcore/toxav/groupav.m | 657 ++ local_pod_repo/toxcore/toxcore/toxav/msi.h | 147 + local_pod_repo/toxcore/toxcore/toxav/msi.m | 903 +++ .../toxcore/toxcore/toxav/ring_buffer.h | 31 + .../toxcore/toxcore/toxav/ring_buffer.m | 115 + local_pod_repo/toxcore/toxcore/toxav/rtp.h | 210 + local_pod_repo/toxcore/toxcore/toxav/rtp.m | 871 +++ local_pod_repo/toxcore/toxcore/toxav/toxav.h | 849 +++ local_pod_repo/toxcore/toxcore/toxav/toxav.m | 1503 +++++ .../toxcore/toxcore/toxav/toxav_old.m | 86 + local_pod_repo/toxcore/toxcore/toxav/video.h | 54 + local_pod_repo/toxcore/toxcore/toxav/video.m | 446 ++ local_pod_repo/toxcore/toxcore/toxcore/DHT.h | 555 ++ local_pod_repo/toxcore/toxcore/toxcore/DHT.m | 3119 +++++++++ .../toxcore/toxcore/toxcore/LAN_discovery.h | 55 + .../toxcore/toxcore/toxcore/LAN_discovery.m | 386 ++ .../toxcore/toxcore/toxcore/Makefile.inc | 132 + .../toxcore/toxcore/toxcore/Messenger.h | 869 +++ .../toxcore/toxcore/toxcore/Messenger.m | 3414 ++++++++++ .../toxcore/toxcore/toxcore/TCP_client.h | 154 + .../toxcore/toxcore/toxcore/TCP_client.m | 1005 +++ .../toxcore/toxcore/toxcore/TCP_common.h | 109 + .../toxcore/toxcore/toxcore/TCP_common.m | 305 + .../toxcore/toxcore/toxcore/TCP_connection.h | 310 + .../toxcore/toxcore/toxcore/TCP_connection.m | 1709 +++++ .../toxcore/toxcore/toxcore/TCP_server.h | 51 + .../toxcore/toxcore/toxcore/TCP_server.m | 1408 ++++ .../toxcore/toxcore/toxcore/announce.h | 67 + .../toxcore/toxcore/toxcore/announce.m | 689 ++ .../toxcore/toxcore/toxcore/attributes.h | 31 + .../toxcore/toxcore/toxcore/bin_pack.h | 122 + .../toxcore/toxcore/toxcore/bin_pack.m | 161 + .../toxcore/toxcore/toxcore/bin_unpack.h | 100 + .../toxcore/toxcore/toxcore/bin_unpack.m | 185 + .../toxcore/toxcore/toxcore/ccompat.h | 87 + .../toxcore/toxcore/toxcore/ccompat.m | 4 + .../toxcore/toxcore/toxcore/crypto_core.h | 461 ++ .../toxcore/toxcore/toxcore/crypto_core.m | 578 ++ .../toxcore/events/conference_connected.m | 190 + .../toxcore/events/conference_invite.m | 249 + .../toxcore/events/conference_message.m | 266 + .../events/conference_peer_list_changed.m | 195 + .../toxcore/events/conference_peer_name.m | 250 + .../toxcore/toxcore/events/conference_title.m | 248 + .../toxcore/toxcore/events/events_alloc.h | 216 + .../toxcore/toxcore/events/events_alloc.m | 64 + .../toxcore/events/file_chunk_request.m | 243 + .../toxcore/toxcore/events/file_recv.m | 282 + .../toxcore/toxcore/events/file_recv_chunk.m | 265 + .../toxcore/events/file_recv_control.m | 228 + .../toxcore/events/friend_connection_status.m | 215 + .../toxcore/events/friend_lossless_packet.m | 233 + .../toxcore/events/friend_lossy_packet.m | 232 + .../toxcore/toxcore/events/friend_message.m | 248 + .../toxcore/toxcore/events/friend_name.m | 231 + .../toxcore/events/friend_read_receipt.m | 210 + .../toxcore/toxcore/events/friend_request.m | 232 + .../toxcore/toxcore/events/friend_status.m | 211 + .../toxcore/events/friend_status_message.m | 234 + .../toxcore/toxcore/events/friend_typing.m | 208 + .../toxcore/events/self_connection_status.m | 190 + .../toxcore/toxcore/toxcore/forwarding.h | 125 + .../toxcore/toxcore/toxcore/forwarding.m | 395 ++ .../toxcore/toxcore/friend_connection.h | 176 + .../toxcore/toxcore/friend_connection.m | 1024 +++ .../toxcore/toxcore/toxcore/friend_requests.h | 54 + .../toxcore/toxcore/toxcore/friend_requests.m | 171 + .../toxcore/toxcore/toxcore/group.h | 398 ++ .../toxcore/toxcore/toxcore/group.m | 3867 +++++++++++ .../toxcore/toxcore/toxcore/group_announce.h | 218 + .../toxcore/toxcore/toxcore/group_announce.m | 462 ++ .../toxcore/toxcore/group_moderation.h | 288 + .../toxcore/toxcore/group_moderation.m | 864 +++ local_pod_repo/toxcore/toxcore/toxcore/list.h | 74 + local_pod_repo/toxcore/toxcore/toxcore/list.m | 252 + .../toxcore/toxcore/toxcore/logger.h | 103 + .../toxcore/toxcore/toxcore/logger.m | 119 + .../toxcore/toxcore/toxcore/mono_time.h | 96 + .../toxcore/toxcore/toxcore/mono_time.m | 265 + .../toxcore/toxcore/toxcore/net_crypto.h | 414 ++ .../toxcore/toxcore/toxcore/net_crypto.m | 3227 +++++++++ .../toxcore/toxcore/toxcore/network.h | 605 ++ .../toxcore/toxcore/toxcore/network.m | 1953 ++++++ .../toxcore/toxcore/toxcore/onion.h | 155 + .../toxcore/toxcore/toxcore/onion.m | 695 ++ .../toxcore/toxcore/toxcore/onion_announce.h | 138 + .../toxcore/toxcore/toxcore/onion_announce.m | 680 ++ .../toxcore/toxcore/toxcore/onion_client.h | 220 + .../toxcore/toxcore/toxcore/onion_client.m | 1952 ++++++ local_pod_repo/toxcore/toxcore/toxcore/ping.h | 48 + local_pod_repo/toxcore/toxcore/toxcore/ping.m | 386 ++ .../toxcore/toxcore/toxcore/ping_array.h | 64 + .../toxcore/toxcore/toxcore/ping_array.m | 170 + .../toxcore/toxcore/toxcore/state.h | 87 + .../toxcore/toxcore/toxcore/state.m | 154 + .../toxcore/toxcore/toxcore/timed_auth.h | 35 + .../toxcore/toxcore/toxcore/timed_auth.m | 44 + local_pod_repo/toxcore/toxcore/toxcore/tox.h | 3349 ++++++++++ local_pod_repo/toxcore/toxcore/toxcore/tox.m | 2607 ++++++++ .../toxcore/toxcore/toxcore/tox_api.m | 175 + .../toxcore/toxcore/toxcore/tox_dispatch.h | 144 + .../toxcore/toxcore/toxcore/tox_dispatch.m | 484 ++ .../toxcore/toxcore/toxcore/tox_events.h | 354 + .../toxcore/toxcore/toxcore/tox_events.m | 290 + .../toxcore/toxcore/toxcore/tox_private.h | 146 + .../toxcore/toxcore/toxcore/tox_private.m | 149 + .../toxcore/toxcore/toxcore/tox_struct.h | 55 + .../toxcore/toxcore/toxcore/tox_unpack.h | 18 + .../toxcore/toxcore/toxcore/tox_unpack.m | 70 + local_pod_repo/toxcore/toxcore/toxcore/util.h | 81 + local_pod_repo/toxcore/toxcore/toxcore/util.m | 150 + .../toxcore/toxencryptsave/Makefile.inc | 38 + .../toxcore/toxcore/toxencryptsave/defines.h | 12 + .../toxcore/toxencryptsave/toxencryptsave.h | 373 ++ .../toxcore/toxencryptsave/toxencryptsave.m | 388 ++ local_pod_repo/toxcore/vpx-ios.diff | 98 + local_pod_repo/toxcore/vpx-osx.diff | 98 + pushextension/Info.plist | 31 + pushextension/NotificationService.swift | 58 + tools/package-ida.sh | 56 + tools/prepare_new_release_version.sh | 55 + 1108 files changed, 157706 insertions(+) create mode 100644 Antidote.xcodeproj/project.pbxproj create mode 100644 Antidote/ActiveSessionCoordinator.swift create mode 100644 Antidote/ActiveSessionNavigationCoordinator.swift create mode 100644 Antidote/AddFriendController.swift create mode 100644 Antidote/AlertAudioPlayer.swift create mode 100644 Antidote/Antidote-Bridging-Header.h create mode 100644 Antidote/Antidote-Info.plist create mode 100644 Antidote/Antidote-Prefix.pch create mode 100644 Antidote/Antidote.entitlements create mode 100644 Antidote/AppCoordinator.swift create mode 100644 Antidote/AppDelegate.swift create mode 100644 Antidote/AudioPlayer.swift create mode 100644 Antidote/AutomationCoordinator.swift create mode 100644 Antidote/AvatarManager.swift create mode 100644 Antidote/BaseCell.swift create mode 100644 Antidote/BaseCellModel.swift create mode 100644 Antidote/BubbleView.swift create mode 100644 Antidote/Bus.swift create mode 100644 Antidote/CallActiveController.swift create mode 100644 Antidote/CallBaseController.swift create mode 100644 Antidote/CallButton.swift create mode 100644 Antidote/CallCoordinator.swift create mode 100644 Antidote/CallIncomingController.swift create mode 100644 Antidote/CallManagement/Call.swift create mode 100644 Antidote/CallManagement/CallManager.swift create mode 100644 Antidote/CallManagement/ProviderDelegate.swift create mode 100644 Antidote/ChangeAutodownloadImagesController.swift create mode 100644 Antidote/ChangePasswordController.swift create mode 100644 Antidote/ChangePinTimeoutController.swift create mode 100644 Antidote/ChangeUserStatusController.swift create mode 100644 Antidote/ChatBaseTextCell.swift create mode 100644 Antidote/ChatBaseTextCellModel.swift create mode 100644 Antidote/ChatBottomStatusViewManager.swift create mode 100644 Antidote/ChatEditable.swift create mode 100644 Antidote/ChatFauxOfflineHeaderView.swift create mode 100644 Antidote/ChatGenericFileCell.swift create mode 100644 Antidote/ChatGenericFileCellModel.swift create mode 100644 Antidote/ChatIncomingCallCell.swift create mode 100644 Antidote/ChatIncomingCallCellModel.swift create mode 100644 Antidote/ChatIncomingFileCell.swift create mode 100644 Antidote/ChatIncomingFileCellModel.swift create mode 100644 Antidote/ChatIncomingTextCell.swift create mode 100644 Antidote/ChatInputView.swift create mode 100644 Antidote/ChatInputViewManager.swift create mode 100644 Antidote/ChatListCell.swift create mode 100644 Antidote/ChatListCellModel.swift create mode 100644 Antidote/ChatListController.swift create mode 100644 Antidote/ChatListTableManager.swift create mode 100644 Antidote/ChatMovableDateCell.swift create mode 100644 Antidote/ChatMovableDateCellModel.swift create mode 100644 Antidote/ChatOutgoingCallCell.swift create mode 100644 Antidote/ChatOutgoingCallCellModel.swift create mode 100644 Antidote/ChatOutgoingFileCell.swift create mode 100644 Antidote/ChatOutgoingFileCellModel.swift create mode 100644 Antidote/ChatOutgoingTextCell.swift create mode 100644 Antidote/ChatOutgoingTextCellModel.swift create mode 100644 Antidote/ChatPrivateController.swift create mode 100644 Antidote/ChatPrivateTitleView.swift create mode 100644 Antidote/ChatProgressBridge.swift create mode 100644 Antidote/ChatProgressProtocol.swift create mode 100644 Antidote/ChatTypingHeaderView.swift create mode 100644 Antidote/ChatsTabCoordinator.swift create mode 100644 Antidote/ConnectionStatus.swift create mode 100644 Antidote/CoordinatorProtocol.swift create mode 100644 Antidote/CopyLabel.swift create mode 100644 Antidote/EnterPinController.swift create mode 100644 Antidote/ErrorHandling.swift create mode 100644 Antidote/ExceptionHandling.h create mode 100644 Antidote/ExceptionHandling.m create mode 100644 Antidote/ExtendedTextField.swift create mode 100644 Antidote/FAQController.swift create mode 100644 Antidote/FilePreviewControllerDataSource.swift create mode 100644 Antidote/FriendCardController.swift create mode 100644 Antidote/FriendListCell.swift create mode 100644 Antidote/FriendListCellModel.swift create mode 100644 Antidote/FriendListController.swift create mode 100644 Antidote/FriendListDataSource.swift create mode 100644 Antidote/FriendRequestController.swift create mode 100644 Antidote/FriendSelectController.swift create mode 100644 Antidote/FriendsTabCoordinator.swift create mode 100644 Antidote/FullscreenPicker.swift create mode 100644 Antidote/HelperFunctions.swift create mode 100644 Antidote/ImageViewWithStatus.swift create mode 100644 Antidote/Images.xcassets/AppIcon.appiconset/Contents.json create mode 100644 Antidote/Images.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png create mode 100644 Antidote/Images.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png create mode 100644 Antidote/Images.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png create mode 100644 Antidote/Images.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png create mode 100644 Antidote/Images.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png create mode 100644 Antidote/Images.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png create mode 100644 Antidote/Images.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png create mode 100644 Antidote/Images.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png create mode 100644 Antidote/Images.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png create mode 100644 Antidote/Images.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png create mode 100644 Antidote/Images.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png create mode 100644 Antidote/Images.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png create mode 100644 Antidote/Images.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png create mode 100644 Antidote/Images.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png create mode 100644 Antidote/Images.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png create mode 100644 Antidote/Images.xcassets/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Call/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Call/end-call.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Call/end-call.imageset/end-call.png create mode 100644 Antidote/Images.xcassets/Controllers/Call/end-call.imageset/end-call@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Call/location-call-activated-medium.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Call/location-call-activated-medium.imageset/location-call-activated-medium.png create mode 100644 Antidote/Images.xcassets/Controllers/Call/location-call-activated-medium.imageset/location-call-activated-medium@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Call/location-call-medium.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Call/location-call-medium.imageset/location-call-medium.png create mode 100644 Antidote/Images.xcassets/Controllers/Call/location-call-medium.imageset/location-call-medium@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Call/mute-selected.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Call/mute-selected.imageset/mute-selected.png create mode 100644 Antidote/Images.xcassets/Controllers/Call/mute-selected.imageset/mute-selected@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Call/mute.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Call/mute.imageset/mute.png create mode 100644 Antidote/Images.xcassets/Controllers/Call/mute.imageset/mute@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Call/speaker.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Call/speaker.imageset/speaker.png create mode 100644 Antidote/Images.xcassets/Controllers/Call/speaker.imageset/speaker@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Call/start-call-30.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Call/start-call-30.imageset/start-call-30.png create mode 100644 Antidote/Images.xcassets/Controllers/Call/start-call-30.imageset/start-call-30@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Call/start-call-medium.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Call/start-call-medium.imageset/start-call-medium.png create mode 100644 Antidote/Images.xcassets/Controllers/Call/start-call-medium.imageset/start-call-medium@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Call/start-call-small.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Call/start-call-small.imageset/start-call-small.png create mode 100644 Antidote/Images.xcassets/Controllers/Call/start-call-small.imageset/start-call-small@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Call/start-call.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Call/start-call.imageset/start-call.png create mode 100644 Antidote/Images.xcassets/Controllers/Call/start-call.imageset/start-call@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Call/switch-camera.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Call/switch-camera.imageset/switch-camera.png create mode 100644 Antidote/Images.xcassets/Controllers/Call/switch-camera.imageset/switch-camera@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Call/video-call-30.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Call/video-call-30.imageset/video-call-30.png create mode 100644 Antidote/Images.xcassets/Controllers/Call/video-call-30.imageset/video-call-30@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Call/video-call-medium.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Call/video-call-medium.imageset/video-call-medium.png create mode 100644 Antidote/Images.xcassets/Controllers/Call/video-call-medium.imageset/video-call-medium@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Call/video-call.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Call/video-call.imageset/video-call.png create mode 100644 Antidote/Images.xcassets/Controllers/Call/video-call.imageset/video-call@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-camera.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-camera.imageset/chat-camera.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-camera.imageset/chat-camera@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-delivered-checkmark.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-delivered-checkmark.imageset/chat-delivered-checkmark.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-delivered-checkmark.imageset/chat-delivered-checkmark@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-cancel.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-cancel.imageset/chat-file-cancel.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-cancel.imageset/chat-file-cancel@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-download-big.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-download-big.imageset/chat-file-download-big.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-download-big.imageset/chat-file-download-big@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-download.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-download.imageset/chat-file-download.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-download.imageset/chat-file-download@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-pause-big.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-pause-big.imageset/chat-file-pause-big.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-pause-big.imageset/chat-file-pause-big@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-pause.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-pause.imageset/chat-file-pause.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-pause.imageset/chat-file-pause@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-play-big.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-play-big.imageset/chat-file-play-big.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-play-big.imageset/chat-file-play-big@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-play.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-play.imageset/chat-file-play.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-play.imageset/chat-file-play@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-retry.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-retry.imageset/chat-file-retry.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-retry.imageset/chat-file-retry@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-7zip.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-7zip.imageset/chat-file-type-7zip.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-7zip.imageset/chat-file-type-7zip@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-aac.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-aac.imageset/chat-file-type-aac.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-aac.imageset/chat-file-type-aac@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-avi.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-avi.imageset/chat-file-type-avi.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-avi.imageset/chat-file-type-avi@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-basic.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-basic.imageset/chat-file-type-basic.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-basic.imageset/chat-file-type-basic@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-canceled.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-canceled.imageset/chat-file-type-canceled.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-canceled.imageset/chat-file-type-canceled@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-css.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-css.imageset/chat-file-type-css.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-css.imageset/chat-file-type-css@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-csv.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-csv.imageset/chat-file-type-csv.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-csv.imageset/chat-file-type-csv@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-doc.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-doc.imageset/chat-file-type-doc.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-doc.imageset/chat-file-type-doc@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-ebup.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-ebup.imageset/chat-file-type-ebup.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-ebup.imageset/chat-file-type-ebup@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-exe.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-exe.imageset/chat-file-type-exe.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-exe.imageset/chat-file-type-exe@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-fb2.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-fb2.imageset/chat-file-type-fb2.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-fb2.imageset/chat-file-type-fb2@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-flv.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-flv.imageset/chat-file-type-flv.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-flv.imageset/chat-file-type-flv@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-gif.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-gif.imageset/chat-file-type-gif.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-gif.imageset/chat-file-type-gif@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-html.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-html.imageset/chat-file-type-html.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-html.imageset/chat-file-type-html@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-jpg.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-jpg.imageset/chat-file-type-jpg.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-jpg.imageset/chat-file-type-jpg@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-mov.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-mov.imageset/chat-file-type-mov.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-mov.imageset/chat-file-type-mov@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-mp3.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-mp3.imageset/chat-file-type-mp3.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-mp3.imageset/chat-file-type-mp3@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-mpg.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-mpg.imageset/chat-file-type-mpg.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-mpg.imageset/chat-file-type-mpg@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-ogg.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-ogg.imageset/chat-file-type-ogg.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-ogg.imageset/chat-file-type-ogg@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-otf.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-otf.imageset/chat-file-type-otf.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-otf.imageset/chat-file-type-otf@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-pdf.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-pdf.imageset/chat-file-type-pdf.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-pdf.imageset/chat-file-type-pdf@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-png.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-png.imageset/chat-file-type-png.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-png.imageset/chat-file-type-png@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-ppt.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-ppt.imageset/chat-file-type-ppt.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-ppt.imageset/chat-file-type-ppt@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-psd.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-psd.imageset/chat-file-type-psd.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-psd.imageset/chat-file-type-psd@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-rar.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-rar.imageset/chat-file-type-rar.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-rar.imageset/chat-file-type-rar@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-tar.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-tar.imageset/chat-file-type-tar.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-tar.imageset/chat-file-type-tar@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-tif.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-tif.imageset/chat-file-type-tif.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-tif.imageset/chat-file-type-tif@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-ttf.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-ttf.imageset/chat-file-type-ttf.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-ttf.imageset/chat-file-type-ttf@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-txt.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-txt.imageset/chat-file-type-txt.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-txt.imageset/chat-file-type-txt@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-wav.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-wav.imageset/chat-file-type-wav.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-wav.imageset/chat-file-type-wav@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-wma.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-wma.imageset/chat-file-type-wma.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-wma.imageset/chat-file-type-wma@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-xls.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-xls.imageset/chat-file-type-xls.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-xls.imageset/chat-file-type-xls@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-zip.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-zip.imageset/chat-file-type-zip.png create mode 100644 Antidote/Images.xcassets/Controllers/Chat/chat-file-type-zip.imageset/chat-file-type-zip@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/FriendCard/friend-card-chat.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/FriendCard/friend-card-chat.imageset/friend-card-chat.png create mode 100644 Antidote/Images.xcassets/Controllers/FriendCard/friend-card-chat.imageset/friend-card-chat@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Login/login-logo.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Login/login-logo.imageset/login-logo.png create mode 100644 Antidote/Images.xcassets/Controllers/Login/login-logo.imageset/login-logo@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Login/login-logo.imageset/login-logo@3x.png create mode 100644 Antidote/Images.xcassets/Controllers/Login/login-password-icon.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Login/login-password-icon.imageset/login-password-icon.png create mode 100644 Antidote/Images.xcassets/Controllers/Login/login-password-icon.imageset/login-password-icon@2x.png create mode 100644 Antidote/Images.xcassets/Controllers/Login/login-profile-icon.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Controllers/Login/login-profile-icon.imageset/login-profile-icon.png create mode 100644 Antidote/Images.xcassets/Controllers/Login/login-profile-icon.imageset/login-profile-icon@2x.png create mode 100644 Antidote/Images.xcassets/Mocks/Contents.json create mode 100644 Antidote/Images.xcassets/Mocks/female-1.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Mocks/female-1.imageset/female-1.jpg create mode 100644 Antidote/Images.xcassets/Mocks/female-2.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Mocks/female-2.imageset/female-2.jpg create mode 100644 Antidote/Images.xcassets/Mocks/female-3.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Mocks/female-3.imageset/female-3.jpg create mode 100644 Antidote/Images.xcassets/Mocks/female-4.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Mocks/female-4.imageset/female-4.jpg create mode 100644 Antidote/Images.xcassets/Mocks/female-5.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Mocks/female-5.imageset/female-5.jpg create mode 100644 Antidote/Images.xcassets/Mocks/male-1.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Mocks/male-1.imageset/male-1.jpg create mode 100644 Antidote/Images.xcassets/Mocks/male-2.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Mocks/male-2.imageset/male-2.jpg create mode 100644 Antidote/Images.xcassets/Mocks/male-3.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Mocks/male-3.imageset/male-3.jpg create mode 100644 Antidote/Images.xcassets/Mocks/male-4.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Mocks/male-4.imageset/male-4.jpg create mode 100644 Antidote/Images.xcassets/Mocks/male-5.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Mocks/male-5.imageset/male-5.jpg create mode 100644 Antidote/Images.xcassets/Other/Contents.json create mode 100644 Antidote/Images.xcassets/Other/checkmark.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Other/checkmark.imageset/checkmark.png create mode 100644 Antidote/Images.xcassets/Other/checkmark.imageset/checkmark@2x.png create mode 100644 Antidote/Images.xcassets/Other/notification-app-icon.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Other/notification-app-icon.imageset/icon-20.png create mode 100644 Antidote/Images.xcassets/Other/notification-app-icon.imageset/icon-40.png create mode 100644 Antidote/Images.xcassets/Other/notification-app-icon.imageset/icon-80.png create mode 100644 Antidote/Images.xcassets/Other/notification-close.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Other/notification-close.imageset/notification-close.png create mode 100644 Antidote/Images.xcassets/Other/notification-close.imageset/notification-close@2x.png create mode 100644 Antidote/Images.xcassets/Other/right-arrow.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/Other/right-arrow.imageset/right-arrow.png create mode 100644 Antidote/Images.xcassets/Other/right-arrow.imageset/right-arrow@2x.png create mode 100644 Antidote/Images.xcassets/TabBar/tab-bar-chats.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/TabBar/tab-bar-chats.imageset/tab-bar-chats.png create mode 100644 Antidote/Images.xcassets/TabBar/tab-bar-chats.imageset/tab-bar-chats@2x.png create mode 100644 Antidote/Images.xcassets/TabBar/tab-bar-friends.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/TabBar/tab-bar-friends.imageset/tab-bar-friends.png create mode 100644 Antidote/Images.xcassets/TabBar/tab-bar-friends.imageset/tab-bar-friends@2x.png create mode 100644 Antidote/Images.xcassets/TabBar/tab-bar-profile.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/TabBar/tab-bar-profile.imageset/tab-bar-profile.png create mode 100644 Antidote/Images.xcassets/TabBar/tab-bar-profile.imageset/tab-bar-profile@2x.png create mode 100644 Antidote/Images.xcassets/TabBar/tab-bar-settings.imageset/Contents.json create mode 100644 Antidote/Images.xcassets/TabBar/tab-bar-settings.imageset/tab-bar-settings.png create mode 100644 Antidote/Images.xcassets/TabBar/tab-bar-settings.imageset/tab-bar-settings@2x.png create mode 100644 Antidote/IncompressibleView.swift create mode 100644 Antidote/InterfaceIdiom.swift create mode 100644 Antidote/KeyboardNotificationController.swift create mode 100644 Antidote/KeyboardObserver.swift create mode 100644 Antidote/KeychainManager.swift create mode 100644 Antidote/Launch Screen.storyboard create mode 100644 Antidote/LaunchPlaceholderBoard.storyboard create mode 100644 Antidote/LaunchPlaceholderController.swift create mode 100644 Antidote/LinearProgressBar.swift create mode 100644 Antidote/LoadingImageView.swift create mode 100644 Antidote/LocationManager.swift create mode 100644 Antidote/Logger.swift create mode 100644 Antidote/LoginBaseController.swift create mode 100644 Antidote/LoginChoiceController.swift create mode 100644 Antidote/LoginCoordinator.swift create mode 100644 Antidote/LoginCreateAccountController.swift create mode 100644 Antidote/LoginCreateAccountCoordinator.swift create mode 100644 Antidote/LoginCreatePasswordController.swift create mode 100644 Antidote/LoginFormController.swift create mode 100644 Antidote/LoginGenericCreateController.swift create mode 100644 Antidote/LoginLogoController.swift create mode 100644 Antidote/NSDateFormatterExtension.swift create mode 100644 Antidote/NSTimerExtension.swift create mode 100644 Antidote/NSURLExtension.swift create mode 100644 Antidote/NotificationCoordinator.swift create mode 100644 Antidote/NotificationObject.swift create mode 100644 Antidote/NotificationWindow.swift create mode 100644 Antidote/OCTManagerConfigurationExtension.swift create mode 100644 Antidote/OCTManagerMock.swift create mode 100644 Antidote/OCTSubmanagerBootstrapMock.swift create mode 100644 Antidote/OCTSubmanagerCallsMock.swift create mode 100644 Antidote/OCTSubmanagerCallsSnapshotMock.swift create mode 100644 Antidote/OCTSubmanagerChatsMock.swift create mode 100644 Antidote/OCTSubmanagerFilesMock.swift create mode 100644 Antidote/OCTSubmanagerFriendsMock.swift create mode 100644 Antidote/OCTSubmanagerObjectsExtension.swift create mode 100644 Antidote/OCTSubmanagerObjectsMock.swift create mode 100644 Antidote/OCTSubmanagerUserMock.swift create mode 100644 Antidote/PinAuthorizationCoordinator.swift create mode 100644 Antidote/PinInputView.swift create mode 100644 Antidote/PortraitNavigationController.swift create mode 100644 Antidote/PrimaryIpadController.swift create mode 100644 Antidote/ProfileDetailsController.swift create mode 100644 Antidote/ProfileMainController.swift create mode 100644 Antidote/ProfileManager.swift create mode 100644 Antidote/ProfileSettings.swift create mode 100644 Antidote/ProfileTabCoordinator.swift create mode 100644 Antidote/ProgressCircleView.swift create mode 100644 Antidote/QRScannerAimView.swift create mode 100644 Antidote/QRScannerController.swift create mode 100644 Antidote/QRViewerController.swift create mode 100644 Antidote/QuickLookPreviewController.swift create mode 100644 Antidote/Reach.swift create mode 100644 Antidote/Results.swift create mode 100644 Antidote/ResultsChange.swift create mode 100644 Antidote/ResultsExtension.swift create mode 100644 Antidote/RoundedButton.swift create mode 100644 Antidote/RunningCoordinator.swift create mode 100644 Antidote/SettingsAboutController.swift create mode 100644 Antidote/SettingsAdvancedController.swift create mode 100644 Antidote/SettingsMainController.swift create mode 100644 Antidote/SettingsTabCoordinator.swift create mode 100644 Antidote/StaticBackgroundView.swift create mode 100644 Antidote/StaticTableAvatarCell.swift create mode 100644 Antidote/StaticTableAvatarCellModel.swift create mode 100644 Antidote/StaticTableBaseCell.swift create mode 100644 Antidote/StaticTableBaseCellModel.swift create mode 100644 Antidote/StaticTableButtonCell.swift create mode 100644 Antidote/StaticTableButtonCellModel.swift create mode 100644 Antidote/StaticTableChatButtonsCell.swift create mode 100644 Antidote/StaticTableChatButtonsCellModel.swift create mode 100644 Antidote/StaticTableController.swift create mode 100644 Antidote/StaticTableDefaultCell.swift create mode 100644 Antidote/StaticTableDefaultCellModel.swift create mode 100644 Antidote/StaticTableInfoCell.swift create mode 100644 Antidote/StaticTableInfoCellModel.swift create mode 100644 Antidote/StaticTableMultiChoiceButtonCell.swift create mode 100644 Antidote/StaticTableMultiChoiceButtonCellModel.swift create mode 100644 Antidote/StaticTableSelectableCellModel.swift create mode 100644 Antidote/StaticTableSwitchCell.swift create mode 100644 Antidote/StaticTableSwitchCellModel.swift create mode 100644 Antidote/StringExtension.swift create mode 100644 Antidote/TabBarAbstractItem.swift create mode 100644 Antidote/TabBarBadgeItem.swift create mode 100644 Antidote/TabBarController.swift create mode 100644 Antidote/TabBarProfileItem.swift create mode 100644 Antidote/TextEditController.swift create mode 100644 Antidote/TextViewController.swift create mode 100644 Antidote/Theme.swift create mode 100644 Antidote/TopCoordinatorProtocol.swift create mode 100644 Antidote/ToxFactory.swift create mode 100644 Antidote/UIAlertControllerExtension.swift create mode 100644 Antidote/UIApplicationExtension.swift create mode 100644 Antidote/UIColorExtension.swift create mode 100644 Antidote/UIFontExtension.swift create mode 100644 Antidote/UIImageExtension.swift create mode 100644 Antidote/UIViewControllerExtension.swift create mode 100644 Antidote/UserDefaultsManager.swift create mode 100644 Antidote/UserStatus.swift create mode 100644 Antidote/UserStatusView.swift create mode 100644 Antidote/ViewPassingGestures.swift create mode 100644 Antidote/antidote-acknowledgements.html create mode 100644 Antidote/appstore-512_orig.png create mode 100644 Antidote/appstore.png create mode 100644 Antidote/appstore.svg create mode 100644 Antidote/ar.lproj/InfoPlist.strings create mode 100644 Antidote/ar.lproj/Localizable.strings create mode 100644 Antidote/ar.lproj/import-profile.html create mode 100644 Antidote/br.lproj/InfoPlist.strings create mode 100644 Antidote/br.lproj/Localizable.strings create mode 100644 Antidote/br.lproj/import-profile.html create mode 100644 Antidote/ca.lproj/AppStoreLocalizable.strings create mode 100644 Antidote/ca.lproj/InfoPlist.strings create mode 100644 Antidote/ca.lproj/Localizable.strings create mode 100644 Antidote/ca.lproj/import-profile.html create mode 100644 Antidote/cs.lproj/InfoPlist.strings create mode 100644 Antidote/cs.lproj/Localizable.strings create mode 100644 Antidote/cs.lproj/import-profile.html create mode 100644 Antidote/da.lproj/AppStoreLocalizable.strings create mode 100644 Antidote/da.lproj/InfoPlist.strings create mode 100644 Antidote/da.lproj/Localizable.strings create mode 100644 Antidote/da.lproj/import-profile.html create mode 100644 Antidote/de.lproj/AppStoreLocalizable.strings create mode 100644 Antidote/de.lproj/InfoPlist.strings create mode 100644 Antidote/de.lproj/Localizable.strings create mode 100644 Antidote/de.lproj/import-profile.html create mode 100644 Antidote/default-theme.yaml create mode 100644 Antidote/dummy-photo.jpg create mode 100644 Antidote/el.lproj/Localizable.strings create mode 100644 Antidote/en.lproj/AppStoreLocalizable.strings create mode 100644 Antidote/en.lproj/InfoPlist.strings create mode 100644 Antidote/en.lproj/Localizable.strings create mode 100644 Antidote/en.lproj/import-profile.html create mode 100644 Antidote/enm.lproj/Localizable.strings create mode 100644 Antidote/es.lproj/AppStoreLocalizable.strings create mode 100644 Antidote/es.lproj/InfoPlist.strings create mode 100644 Antidote/es.lproj/Localizable.strings create mode 100644 Antidote/es.lproj/import-profile.html create mode 100644 Antidote/fr.lproj/AppStoreLocalizable.strings create mode 100644 Antidote/fr.lproj/InfoPlist.strings create mode 100644 Antidote/fr.lproj/Localizable.strings create mode 100644 Antidote/fr.lproj/import-profile.html create mode 100644 Antidote/iPadFriendsButton.swift create mode 100644 Antidote/iPadNavigationView.swift create mode 100644 Antidote/icons8-key-1024.png create mode 100644 Antidote/isotoxin_Calltone.aac create mode 100644 Antidote/isotoxin_Hangup.aac create mode 100644 Antidote/isotoxin_NewMessage.aac create mode 100644 Antidote/isotoxin_Ringtone.aac create mode 100644 Antidote/isotoxin_RingtoneWhileCall.aac create mode 100644 Antidote/it.lproj/AppStoreLocalizable.strings create mode 100644 Antidote/it.lproj/InfoPlist.strings create mode 100644 Antidote/it.lproj/Localizable.strings create mode 100644 Antidote/ko.lproj/AppStoreLocalizable.strings create mode 100644 Antidote/ko.lproj/InfoPlist.strings create mode 100644 Antidote/ko.lproj/Localizable.strings create mode 100644 Antidote/ko.lproj/import-profile.html create mode 100644 Antidote/lt.lproj/InfoPlist.strings create mode 100644 Antidote/lt.lproj/Localizable.strings create mode 100644 Antidote/lt.lproj/import-profile.html create mode 100644 Antidote/nb.lproj/AppStoreLocalizable.strings create mode 100644 Antidote/nb.lproj/InfoPlist.strings create mode 100644 Antidote/nb.lproj/Localizable.strings create mode 100644 Antidote/nb.lproj/import-profile.html create mode 100644 Antidote/nl.lproj/AppStoreLocalizable.strings create mode 100644 Antidote/nl.lproj/InfoPlist.strings create mode 100644 Antidote/nl.lproj/Localizable.strings create mode 100644 Antidote/nl.lproj/import-profile.html create mode 100644 Antidote/old_antidote_logo_with_text.png create mode 100644 Antidote/pl.lproj/InfoPlist.strings create mode 100644 Antidote/pl.lproj/Localizable.strings create mode 100644 Antidote/pl.lproj/import-profile.html create mode 100644 Antidote/pt-BR.lproj/AppStoreLocalizable.strings create mode 100644 Antidote/pt-BR.lproj/InfoPlist.strings create mode 100644 Antidote/pt-BR.lproj/Localizable.strings create mode 100644 Antidote/pt-BR.lproj/import-profile.html create mode 100644 Antidote/pt.lproj/AppStoreLocalizable.strings create mode 100644 Antidote/pt.lproj/InfoPlist.strings create mode 100644 Antidote/pt.lproj/Localizable.strings create mode 100644 Antidote/pt.lproj/import-profile.html create mode 100644 Antidote/ru.lproj/AppStoreLocalizable.strings create mode 100644 Antidote/ru.lproj/InfoPlist.strings create mode 100644 Antidote/ru.lproj/Localizable.strings create mode 100644 Antidote/ru.lproj/import-profile.html create mode 100644 Antidote/sv.lproj/Localizable.strings create mode 100644 Antidote/tr.lproj/Localizable.strings create mode 100644 Antidote/zgh.lproj/Localizable.strings create mode 100644 Antidote/zh.lproj/AppStoreLocalizable.strings create mode 100644 Antidote/zh.lproj/InfoPlist.strings create mode 100644 Antidote/zh.lproj/Localizable.strings create mode 100644 Antidote/zh.lproj/import-profile.html create mode 100644 AntidoteTests/AntidoteTests-Bridging-Header.h create mode 100644 AntidoteTests/CellSnapshotTest.swift create mode 100644 AntidoteTests/ChatIncomingCallCellSnapshotTest.swift create mode 100644 AntidoteTests/ChatIncomingFileCellSnapshotTest.swift create mode 100644 AntidoteTests/ChatIncomingTextCellSnapshotTest.swift create mode 100644 AntidoteTests/ChatListCellSnapshotTest.swift create mode 100644 AntidoteTests/ChatMovableDateCellSnapshotTest.swift create mode 100644 AntidoteTests/ChatOutgoingCallCellSnapshotTest.swift create mode 100644 AntidoteTests/ChatOutgoingFileCellSnapshotTest.swift create mode 100644 AntidoteTests/ChatOutgoingTextCellSnapshotTest.swift create mode 100644 AntidoteTests/FriendListDataSourceTest.swift create mode 100644 AntidoteTests/Info.plist create mode 100644 AntidoteTests/KeychainManagerTests.swift create mode 100644 AntidoteTests/LoginChoiceViewSnapshotTest.swift create mode 100644 AntidoteTests/MockedChatProgressProtocol.swift create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatIncomingCallCellSnapshotTest/testAnsweredCall_normal@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatIncomingCallCellSnapshotTest/testAnsweredCall_right-to-left@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatIncomingCallCellSnapshotTest/testNonAnsweredCall_normal@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatIncomingCallCellSnapshotTest/testNonAnsweredCall_right-to-left@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatIncomingFileCellSnapshotTest/testCancelled_normal@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatIncomingFileCellSnapshotTest/testCancelled_right-to-left@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatIncomingFileCellSnapshotTest/testDoneWithImage_normal@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatIncomingFileCellSnapshotTest/testDoneWithImage_right-to-left@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatIncomingFileCellSnapshotTest/testDone_normal@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatIncomingFileCellSnapshotTest/testDone_right-to-left@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatIncomingFileCellSnapshotTest/testLoading_normal@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatIncomingFileCellSnapshotTest/testLoading_right-to-left@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatIncomingFileCellSnapshotTest/testPaused_normal@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatIncomingFileCellSnapshotTest/testPaused_right-to-left@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatIncomingFileCellSnapshotTest/testWaitingState_normal@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatIncomingFileCellSnapshotTest/testWaitingState_right-to-left@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatIncomingTextCellSnapshotTest/testHugeMessage_normal@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatIncomingTextCellSnapshotTest/testHugeMessage_right-to-left@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatIncomingTextCellSnapshotTest/testMediumMessage_normal@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatIncomingTextCellSnapshotTest/testMediumMessage_right-to-left@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatIncomingTextCellSnapshotTest/testSmallMessage_normal@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatIncomingTextCellSnapshotTest/testSmallMessage_right-to-left@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatIncomingTextCellSnapshotTest/testWithLink_normal@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatIncomingTextCellSnapshotTest/testWithLink_right-to-left@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatListCellSnapshotTest/testDefault_normal@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatListCellSnapshotTest/testDefault_right-to-left@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatListCellSnapshotTest/testLongMessage_normal@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatListCellSnapshotTest/testLongMessage_right-to-left@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatListCellSnapshotTest/testUnread_normal@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatListCellSnapshotTest/testUnread_right-to-left@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatMovableDateCellSnapshotTest/testDefault_normal@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatMovableDateCellSnapshotTest/testDefault_right-to-left@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatMovableDateCellSnapshotTest/testPanned_normal@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatMovableDateCellSnapshotTest/testPanned_right-to-left@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatOutgoingCallCellSnapshotTest/testAnsweredCall_normal@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatOutgoingCallCellSnapshotTest/testAnsweredCall_right-to-left@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatOutgoingCallCellSnapshotTest/testNonAnsweredCall_normal@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatOutgoingCallCellSnapshotTest/testNonAnsweredCall_right-to-left@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatOutgoingFileCellSnapshotTest/testCancelledWithImage_normal@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatOutgoingFileCellSnapshotTest/testCancelledWithImage_right-to-left@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatOutgoingFileCellSnapshotTest/testCancelled_normal@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatOutgoingFileCellSnapshotTest/testCancelled_right-to-left@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatOutgoingFileCellSnapshotTest/testDoneWithImage_normal@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatOutgoingFileCellSnapshotTest/testDoneWithImage_right-to-left@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatOutgoingFileCellSnapshotTest/testDone_normal@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatOutgoingFileCellSnapshotTest/testDone_right-to-left@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatOutgoingFileCellSnapshotTest/testLoadingWithImage_normal@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatOutgoingFileCellSnapshotTest/testLoadingWithImage_right-to-left@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatOutgoingFileCellSnapshotTest/testLoading_normal@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatOutgoingFileCellSnapshotTest/testLoading_right-to-left@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatOutgoingFileCellSnapshotTest/testPausedWithImage_normal@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatOutgoingFileCellSnapshotTest/testPausedWithImage_right-to-left@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatOutgoingFileCellSnapshotTest/testPaused_normal@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatOutgoingFileCellSnapshotTest/testPaused_right-to-left@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatOutgoingFileCellSnapshotTest/testWaitingStateWithImage_normal@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatOutgoingFileCellSnapshotTest/testWaitingStateWithImage_right-to-left@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatOutgoingFileCellSnapshotTest/testWaitingState_normal@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatOutgoingFileCellSnapshotTest/testWaitingState_right-to-left@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatOutgoingTextCellSnapshotTest/testHugeMessage_normal@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatOutgoingTextCellSnapshotTest/testHugeMessage_right-to-left@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatOutgoingTextCellSnapshotTest/testMediumMessageUndelivered_normal@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatOutgoingTextCellSnapshotTest/testMediumMessageUndelivered_right-to-left@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatOutgoingTextCellSnapshotTest/testMediumMessage_normal@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatOutgoingTextCellSnapshotTest/testMediumMessage_right-to-left@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatOutgoingTextCellSnapshotTest/testSmallMessage_normal@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatOutgoingTextCellSnapshotTest/testSmallMessage_right-to-left@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatOutgoingTextCellSnapshotTest/testWithLink_normal@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.ChatOutgoingTextCellSnapshotTest/testWithLink_right-to-left@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.LoginChoiceViewSnapshotTest/testDefault_normal@2x.png create mode 100644 AntidoteTests/ReferenceImages_64/AntidoteTests.LoginChoiceViewSnapshotTest/testDefault_right-to-left@2x.png create mode 100644 AntidoteTests/SnapshotBaseTest.swift create mode 100644 AntidoteTests/SwiftSupport.swift create mode 100644 AntidoteTests/ThemeTest.swift create mode 100644 AntidoteTests/icon.png create mode 100644 CHANGELOG.md create mode 100644 FAQ/en.md create mode 100644 Gemfile create mode 100644 LICENSE create mode 100644 PRIVACY_POLICY.md create mode 100644 Podfile create mode 100644 README.md create mode 100644 ScreenshotsUITests/Info.plist create mode 100644 ScreenshotsUITests/ScreenshotUITests-Bridging-Header.h create mode 100644 ScreenshotsUITests/ScreenshotsUITests.swift create mode 100644 XOLDX_fastlane/Appfile create mode 100644 XOLDX_fastlane/Deliverfile create mode 100644 XOLDX_fastlane/Fastfile create mode 100644 XOLDX_fastlane/README.md create mode 100644 XOLDX_fastlane/Snapfile create mode 100644 XOLDX_fastlane/SnapshotHelper.swift create mode 100644 XOLDX_fastlane/SnapshotHelper2-3.swift create mode 100644 XOLDX_fastlane/metadata/app_icon.png create mode 100644 XOLDX_fastlane/metadata/copyright.txt create mode 100644 XOLDX_fastlane/metadata/default/marketing_url.txt create mode 100644 XOLDX_fastlane/metadata/default/name.txt create mode 100644 XOLDX_fastlane/metadata/default/privacy_url.txt create mode 100644 XOLDX_fastlane/metadata/default/release_notes.txt create mode 100644 XOLDX_fastlane/metadata/default/support_url.txt create mode 100644 XOLDX_fastlane/metadata/en-US/description.txt create mode 100644 XOLDX_fastlane/metadata/en-US/keywords.txt create mode 100644 XOLDX_fastlane/metadata/fr-FR/description.txt create mode 100644 XOLDX_fastlane/metadata/fr-FR/keywords.txt create mode 100644 XOLDX_fastlane/metadata/primary_category.txt create mode 100644 XOLDX_fastlane/metadata/primary_first_sub_category.txt create mode 100644 XOLDX_fastlane/metadata/primary_second_sub_category.txt create mode 100644 XOLDX_fastlane/metadata/secondary_category.txt create mode 100644 XOLDX_fastlane/metadata/secondary_first_sub_category.txt create mode 100644 XOLDX_fastlane/metadata/secondary_second_sub_category.txt create mode 100644 docs/app001.png create mode 100644 docs/app002.png create mode 100644 docs/app003.png create mode 100644 docs/app004.png create mode 100644 docs/applewatch_push.jpg create mode 100644 docs/appstore-badge.png create mode 100644 docs/iphone_send_crashreports.png create mode 100644 docs/release_checklist.md create mode 100644 fastlane/.gitignore create mode 100644 fastlane/Appfile create mode 100644 fastlane/Fastfile create mode 100644 local_pod_repo/cmp/.gitignore create mode 100644 local_pod_repo/cmp/LICENSE create mode 100644 local_pod_repo/cmp/cmp.podspec create mode 100644 local_pod_repo/cmp/cmp/.gitignore create mode 100644 local_pod_repo/cmp/cmp/CMakeLists.txt create mode 100644 local_pod_repo/cmp/cmp/CODE_OF_CONDUCT.md create mode 100644 local_pod_repo/cmp/cmp/LICENSE create mode 100644 local_pod_repo/cmp/cmp/Makefile create mode 100644 local_pod_repo/cmp/cmp/README.md create mode 100644 local_pod_repo/cmp/cmp/TODO.md create mode 100644 local_pod_repo/cmp/cmp/cmp.c create mode 100644 local_pod_repo/cmp/cmp/cmp.h create mode 100644 local_pod_repo/cmp/cmp/examples/example1.c create mode 100644 local_pod_repo/cmp/cmp/examples/example2.c create mode 100644 local_pod_repo/cmp/cmp/test/buf.c create mode 100644 local_pod_repo/cmp/cmp/test/buf.h create mode 100644 local_pod_repo/cmp/cmp/test/cases.mpac create mode 100644 local_pod_repo/cmp/cmp/test/profile.c create mode 100644 local_pod_repo/cmp/cmp/test/test.c create mode 100644 local_pod_repo/cmp/cmp/test/tests.c create mode 100644 local_pod_repo/cmp/cmp/test/tests.h create mode 100644 local_pod_repo/cmp/cmp/test/utils.c create mode 100644 local_pod_repo/cmp/cmp/test/utils.h create mode 100644 local_pod_repo/msgpack-c/.gitignore create mode 100644 local_pod_repo/msgpack-c/LICENSE create mode 100644 local_pod_repo/msgpack-c/msgpack-c.podspec create mode 100644 local_pod_repo/msgpack-c/msgpack-c/.gitignore create mode 100644 local_pod_repo/msgpack-c/msgpack-c/CHANGELOG.md create mode 100644 local_pod_repo/msgpack-c/msgpack-c/CMakeLists.txt create mode 100644 local_pod_repo/msgpack-c/msgpack-c/COPYING create mode 100644 local_pod_repo/msgpack-c/msgpack-c/Doxyfile create mode 100644 local_pod_repo/msgpack-c/msgpack-c/Files.cmake create mode 100644 local_pod_repo/msgpack-c/msgpack-c/LICENSE_1_0.txt create mode 100644 local_pod_repo/msgpack-c/msgpack-c/NOTICE create mode 100644 local_pod_repo/msgpack-c/msgpack-c/QUICKSTART-C.md create mode 100644 local_pod_repo/msgpack-c/msgpack-c/README.md create mode 100644 local_pod_repo/msgpack-c/msgpack-c/appveyor.yml create mode 100644 local_pod_repo/msgpack-c/msgpack-c/codecov.yml create mode 100644 local_pod_repo/msgpack-c/msgpack-c/include/msgpack.h create mode 100644 local_pod_repo/msgpack-c/msgpack-c/include/msgpack/fbuffer.h create mode 100644 local_pod_repo/msgpack-c/msgpack-c/include/msgpack/gcc_atomic.h create mode 100644 local_pod_repo/msgpack-c/msgpack-c/include/msgpack/msgpack_version.h create mode 100644 local_pod_repo/msgpack-c/msgpack-c/include/msgpack/object.h create mode 100644 local_pod_repo/msgpack-c/msgpack-c/include/msgpack/pack.h create mode 100644 local_pod_repo/msgpack-c/msgpack-c/include/msgpack/pack_define.h create mode 100644 local_pod_repo/msgpack-c/msgpack-c/include/msgpack/pack_template.h create mode 100644 local_pod_repo/msgpack-c/msgpack-c/include/msgpack/sbuffer.h create mode 100644 local_pod_repo/msgpack-c/msgpack-c/include/msgpack/sysdep.h create mode 100644 local_pod_repo/msgpack-c/msgpack-c/include/msgpack/timestamp.h create mode 100644 local_pod_repo/msgpack-c/msgpack-c/include/msgpack/unpack.h create mode 100644 local_pod_repo/msgpack-c/msgpack-c/include/msgpack/unpack_define.h create mode 100644 local_pod_repo/msgpack-c/msgpack-c/include/msgpack/unpack_template.h create mode 100644 local_pod_repo/msgpack-c/msgpack-c/include/msgpack/util.h create mode 100644 local_pod_repo/msgpack-c/msgpack-c/include/msgpack/version_master.h create mode 100644 local_pod_repo/msgpack-c/msgpack-c/include/msgpack/vrefbuffer.h create mode 100644 local_pod_repo/msgpack-c/msgpack-c/include/msgpack/zbuffer.h create mode 100644 local_pod_repo/msgpack-c/msgpack-c/include/msgpack/zone.h create mode 100644 local_pod_repo/msgpack-c/msgpack-c/msgpack-config.cmake.in create mode 100644 local_pod_repo/msgpack-c/msgpack-c/msgpack.pc.in create mode 100644 local_pod_repo/msgpack-c/msgpack-c/src/objectc.c create mode 100644 local_pod_repo/msgpack-c/msgpack-c/src/unpack.c create mode 100644 local_pod_repo/msgpack-c/msgpack-c/src/version.c create mode 100644 local_pod_repo/msgpack-c/msgpack-c/src/vrefbuffer.c create mode 100644 local_pod_repo/msgpack-c/msgpack-c/src/zone.c create mode 100644 local_pod_repo/objcTox/.gitignore create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Audio/OCTAudioEngine+Private.h create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Audio/OCTAudioEngine.h create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Audio/OCTAudioEngine.m create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Audio/OCTAudioQueue.h create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Audio/OCTAudioQueue.m create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Configuration/OCTDefaultFileStorage.m create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Configuration/OCTManagerConfiguration.m create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Database/OCTRealmManager.h create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Database/OCTRealmManager.m create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Files/NSError+OCTFile.h create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Files/NSError+OCTFile.m create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Files/OCTFileBaseOperation+Private.h create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Files/OCTFileBaseOperation.h create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Files/OCTFileBaseOperation.m create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Files/OCTFileDataInput.h create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Files/OCTFileDataInput.m create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Files/OCTFileDataOutput.h create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Files/OCTFileDataOutput.m create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Files/OCTFileDownloadOperation.h create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Files/OCTFileDownloadOperation.m create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Files/OCTFileInputProtocol.h create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Files/OCTFileOutputProtocol.h create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Files/OCTFilePathInput.h create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Files/OCTFilePathInput.m create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Files/OCTFilePathOutput.h create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Files/OCTFilePathOutput.m create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Files/OCTFileTools.h create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Files/OCTFileTools.m create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Files/OCTFileUploadOperation.h create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Files/OCTFileUploadOperation.m create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Messages/OCTSendMessageOperation.h create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Messages/OCTSendMessageOperation.m create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/OCTManagerConstants.m create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/OCTManagerFactory.m create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/OCTManagerImpl.h create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/OCTManagerImpl.m create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Objects/OCTCall+Utilities.h create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Objects/OCTCall+Utilities.m create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Objects/OCTCall.m create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Objects/OCTCallTimer.h create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Objects/OCTCallTimer.m create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Objects/OCTChat.m create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Objects/OCTFriend.m create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Objects/OCTFriendRequest.m create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Objects/OCTMessageAbstract.m create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Objects/OCTMessageCall.m create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Objects/OCTMessageFile.m create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Objects/OCTMessageText.m create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Objects/OCTNode.h create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Objects/OCTNode.m create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Objects/OCTObject.m create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Objects/OCTSettingsStorageObject.h create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Objects/OCTSettingsStorageObject.m create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Submanagers/OCTSubmanagerBootstrapImpl.h create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Submanagers/OCTSubmanagerBootstrapImpl.m create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Submanagers/OCTSubmanagerCallsImpl.h create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Submanagers/OCTSubmanagerCallsImpl.m create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Submanagers/OCTSubmanagerChatsImpl.h create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Submanagers/OCTSubmanagerChatsImpl.m create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Submanagers/OCTSubmanagerDataSource.h create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Submanagers/OCTSubmanagerFilesImpl.h create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Submanagers/OCTSubmanagerFilesImpl.m create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Submanagers/OCTSubmanagerFriendsImpl.h create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Submanagers/OCTSubmanagerFriendsImpl.m create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Submanagers/OCTSubmanagerObjectsImpl.h create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Submanagers/OCTSubmanagerObjectsImpl.m create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Submanagers/OCTSubmanagerProtocol.h create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Submanagers/OCTSubmanagerUserImpl.h create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Submanagers/OCTSubmanagerUserImpl.m create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Video/OCTPixelBufferPool.h create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Video/OCTPixelBufferPool.m create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Video/OCTVideoEngine.h create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Video/OCTVideoEngine.m create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Video/OCTVideoView.h create mode 100644 local_pod_repo/objcTox/Classes/Private/Manager/Video/OCTVideoView.m create mode 100644 local_pod_repo/objcTox/Classes/Private/Wrapper/OCTLogging.h create mode 100644 local_pod_repo/objcTox/Classes/Private/Wrapper/OCTTox+Private.h create mode 100644 local_pod_repo/objcTox/Classes/Private/Wrapper/OCTTox.m create mode 100644 local_pod_repo/objcTox/Classes/Private/Wrapper/OCTToxAV+Private.h create mode 100644 local_pod_repo/objcTox/Classes/Private/Wrapper/OCTToxAV.m create mode 100644 local_pod_repo/objcTox/Classes/Private/Wrapper/OCTToxAVConstants.m create mode 100644 local_pod_repo/objcTox/Classes/Private/Wrapper/OCTToxConstants.m create mode 100644 local_pod_repo/objcTox/Classes/Private/Wrapper/OCTToxEncryptSave.m create mode 100644 local_pod_repo/objcTox/Classes/Private/Wrapper/OCTToxOptions+Private.h create mode 100644 local_pod_repo/objcTox/Classes/Private/Wrapper/OCTToxOptions.m create mode 100644 local_pod_repo/objcTox/Classes/Public/Manager/Configuration/OCTDefaultFileStorage.h create mode 100644 local_pod_repo/objcTox/Classes/Public/Manager/Configuration/OCTFileStorageProtocol.h create mode 100644 local_pod_repo/objcTox/Classes/Public/Manager/Configuration/OCTManagerConfiguration.h create mode 100644 local_pod_repo/objcTox/Classes/Public/Manager/OCTManager.h create mode 100644 local_pod_repo/objcTox/Classes/Public/Manager/OCTManagerConstants.h create mode 100644 local_pod_repo/objcTox/Classes/Public/Manager/OCTManagerFactory.h create mode 100644 local_pod_repo/objcTox/Classes/Public/Manager/Objects/OCTCall.h create mode 100644 local_pod_repo/objcTox/Classes/Public/Manager/Objects/OCTChat.h create mode 100644 local_pod_repo/objcTox/Classes/Public/Manager/Objects/OCTFriend.h create mode 100644 local_pod_repo/objcTox/Classes/Public/Manager/Objects/OCTFriendRequest.h create mode 100644 local_pod_repo/objcTox/Classes/Public/Manager/Objects/OCTMessageAbstract.h create mode 100644 local_pod_repo/objcTox/Classes/Public/Manager/Objects/OCTMessageCall.h create mode 100644 local_pod_repo/objcTox/Classes/Public/Manager/Objects/OCTMessageFile.h create mode 100644 local_pod_repo/objcTox/Classes/Public/Manager/Objects/OCTMessageText.h create mode 100644 local_pod_repo/objcTox/Classes/Public/Manager/Objects/OCTObject.h create mode 100644 local_pod_repo/objcTox/Classes/Public/Manager/Objects/OCTView.h create mode 100644 local_pod_repo/objcTox/Classes/Public/Manager/Submanagers/OCTSubmanagerBootstrap.h create mode 100644 local_pod_repo/objcTox/Classes/Public/Manager/Submanagers/OCTSubmanagerCalls.h create mode 100644 local_pod_repo/objcTox/Classes/Public/Manager/Submanagers/OCTSubmanagerCallsDelegate.h create mode 100644 local_pod_repo/objcTox/Classes/Public/Manager/Submanagers/OCTSubmanagerChats.h create mode 100644 local_pod_repo/objcTox/Classes/Public/Manager/Submanagers/OCTSubmanagerFiles.h create mode 100644 local_pod_repo/objcTox/Classes/Public/Manager/Submanagers/OCTSubmanagerFilesProgressSubscriber.h create mode 100644 local_pod_repo/objcTox/Classes/Public/Manager/Submanagers/OCTSubmanagerFriends.h create mode 100644 local_pod_repo/objcTox/Classes/Public/Manager/Submanagers/OCTSubmanagerObjects.h create mode 100644 local_pod_repo/objcTox/Classes/Public/Manager/Submanagers/OCTSubmanagerUser.h create mode 100644 local_pod_repo/objcTox/Classes/Public/Manager/nodes.json create mode 100644 local_pod_repo/objcTox/Classes/Public/Wrapper/OCTTox.h create mode 100644 local_pod_repo/objcTox/Classes/Public/Wrapper/OCTToxAV.h create mode 100644 local_pod_repo/objcTox/Classes/Public/Wrapper/OCTToxAVConstants.h create mode 100644 local_pod_repo/objcTox/Classes/Public/Wrapper/OCTToxAVDelegate.h create mode 100644 local_pod_repo/objcTox/Classes/Public/Wrapper/OCTToxConstants.h create mode 100644 local_pod_repo/objcTox/Classes/Public/Wrapper/OCTToxDelegate.h create mode 100644 local_pod_repo/objcTox/Classes/Public/Wrapper/OCTToxEncryptSave.h create mode 100644 local_pod_repo/objcTox/Classes/Public/Wrapper/OCTToxEncryptSaveConstants.h create mode 100644 local_pod_repo/objcTox/Classes/Public/Wrapper/OCTToxOptions.h create mode 100644 local_pod_repo/objcTox/Gemfile create mode 100644 local_pod_repo/objcTox/OSXDemo/AppDelegate.h create mode 100644 local_pod_repo/objcTox/OSXDemo/AppDelegate.m create mode 100644 local_pod_repo/objcTox/OSXDemo/Base.lproj/MainMenu.xib create mode 100644 local_pod_repo/objcTox/OSXDemo/Images.xcassets/AppIcon.appiconset/Contents.json create mode 100644 local_pod_repo/objcTox/OSXDemo/Info.plist create mode 100644 local_pod_repo/objcTox/OSXDemo/MainWindow.xib create mode 100644 local_pod_repo/objcTox/OSXDemo/OCTBootStrap.xib create mode 100644 local_pod_repo/objcTox/OSXDemo/OCTBootStrapViewController.h create mode 100644 local_pod_repo/objcTox/OSXDemo/OCTBootStrapViewController.m create mode 100644 local_pod_repo/objcTox/OSXDemo/OCTCallsViewController.h create mode 100644 local_pod_repo/objcTox/OSXDemo/OCTCallsViewController.m create mode 100644 local_pod_repo/objcTox/OSXDemo/OCTCallsViewController.xib create mode 100644 local_pod_repo/objcTox/OSXDemo/OCTConversationViewController.h create mode 100644 local_pod_repo/objcTox/OSXDemo/OCTConversationViewController.m create mode 100644 local_pod_repo/objcTox/OSXDemo/OCTConversationViewController.xib create mode 100644 local_pod_repo/objcTox/OSXDemo/OCTFilesViewController.h create mode 100644 local_pod_repo/objcTox/OSXDemo/OCTFilesViewController.m create mode 100644 local_pod_repo/objcTox/OSXDemo/OCTFilesViewController.xib create mode 100644 local_pod_repo/objcTox/OSXDemo/OCTFriendsViewController.h create mode 100644 local_pod_repo/objcTox/OSXDemo/OCTFriendsViewController.m create mode 100644 local_pod_repo/objcTox/OSXDemo/OCTFriendsViewController.xib create mode 100644 local_pod_repo/objcTox/OSXDemo/OCTMainWindowController.h create mode 100644 local_pod_repo/objcTox/OSXDemo/OCTMainWindowController.m create mode 100644 local_pod_repo/objcTox/OSXDemo/OCTUserViewController.h create mode 100644 local_pod_repo/objcTox/OSXDemo/OCTUserViewController.m create mode 100644 local_pod_repo/objcTox/OSXDemo/OCTUserViewController.xib create mode 100644 local_pod_repo/objcTox/OSXDemo/RLMCollectionChange+IndexSet.h create mode 100644 local_pod_repo/objcTox/OSXDemo/RLMCollectionChange+IndexSet.m create mode 100644 local_pod_repo/objcTox/OSXDemo/main.m create mode 100644 local_pod_repo/objcTox/OSXDemoTests/Info.plist create mode 100644 local_pod_repo/objcTox/Podfile create mode 100644 local_pod_repo/objcTox/README.md create mode 100644 local_pod_repo/objcTox/Tests/CoreAudioMocks.h create mode 100644 local_pod_repo/objcTox/Tests/OCTAudioEngineTests.m create mode 100644 local_pod_repo/objcTox/Tests/OCTAudioQueueTests.m create mode 100644 local_pod_repo/objcTox/Tests/OCTCAsserts.h create mode 100644 local_pod_repo/objcTox/Tests/OCTCallTimerTests.m create mode 100644 local_pod_repo/objcTox/Tests/OCTChatTests.m create mode 100644 local_pod_repo/objcTox/Tests/OCTDefaultFileStorageTests.m create mode 100644 local_pod_repo/objcTox/Tests/OCTFileToolsTests.m create mode 100644 local_pod_repo/objcTox/Tests/OCTFriendRequestTests.m create mode 100644 local_pod_repo/objcTox/Tests/OCTManagerConfigurationTests.m create mode 100644 local_pod_repo/objcTox/Tests/OCTManagerImplTests.m create mode 100644 local_pod_repo/objcTox/Tests/OCTMessageAbstractTests.m create mode 100644 local_pod_repo/objcTox/Tests/OCTObjectTests.m create mode 100644 local_pod_repo/objcTox/Tests/OCTRealmTests.h create mode 100644 local_pod_repo/objcTox/Tests/OCTRealmTests.m create mode 100644 local_pod_repo/objcTox/Tests/OCTSubmanagerBootstrapImplTests.m create mode 100644 local_pod_repo/objcTox/Tests/OCTSubmanagerCallsImplTests.m create mode 100644 local_pod_repo/objcTox/Tests/OCTSubmanagerChatsImplTests.m create mode 100644 local_pod_repo/objcTox/Tests/OCTSubmanagerFilesImplTests.m create mode 100644 local_pod_repo/objcTox/Tests/OCTSubmanagerFriendsImplTests.m create mode 100644 local_pod_repo/objcTox/Tests/OCTSubmanagerObjectsImplTests.m create mode 100644 local_pod_repo/objcTox/Tests/OCTSubmanagerUserImplTests.m create mode 100644 local_pod_repo/objcTox/Tests/OCTToxAVTests.m create mode 100644 local_pod_repo/objcTox/Tests/OCTToxEncryptSaveTests.m create mode 100644 local_pod_repo/objcTox/Tests/OCTToxTests.m create mode 100644 local_pod_repo/objcTox/Tests/OCTVideoEngineTests.m create mode 100644 local_pod_repo/objcTox/Tests/YUVPlanes/test_backwards_3p.h create mode 100644 local_pod_repo/objcTox/Tests/YUVPlanes/test_backwards_stride13p.h create mode 100644 local_pod_repo/objcTox/Tests/YUVPlanes/test_good.h create mode 100644 local_pod_repo/objcTox/Tests/YUVPlanes/test_straight3p.h create mode 100644 local_pod_repo/objcTox/Tests/YUVPlanes/test_stride13p.h create mode 100644 local_pod_repo/objcTox/Tests/unencrypted-database.realm create mode 100644 local_pod_repo/objcTox/codecov.yml create mode 100644 local_pod_repo/objcTox/iOSDemo/AppDelegate.h create mode 100644 local_pod_repo/objcTox/iOSDemo/AppDelegate.m create mode 100644 local_pod_repo/objcTox/iOSDemo/Base.lproj/LaunchScreen.xib create mode 100644 local_pod_repo/objcTox/iOSDemo/Images.xcassets/AppIcon.appiconset/Contents.json create mode 100644 local_pod_repo/objcTox/iOSDemo/Info.plist create mode 100644 local_pod_repo/objcTox/iOSDemo/OCTCallsViewController.h create mode 100644 local_pod_repo/objcTox/iOSDemo/OCTCallsViewController.m create mode 100644 local_pod_repo/objcTox/iOSDemo/OCTChatsViewController.h create mode 100644 local_pod_repo/objcTox/iOSDemo/OCTChatsViewController.m create mode 100644 local_pod_repo/objcTox/iOSDemo/OCTConversationViewController.h create mode 100644 local_pod_repo/objcTox/iOSDemo/OCTConversationViewController.m create mode 100644 local_pod_repo/objcTox/iOSDemo/OCTFriendsViewController.h create mode 100644 local_pod_repo/objcTox/iOSDemo/OCTFriendsViewController.m create mode 100644 local_pod_repo/objcTox/iOSDemo/OCTStartDemoViewController.h create mode 100644 local_pod_repo/objcTox/iOSDemo/OCTStartDemoViewController.m create mode 100644 local_pod_repo/objcTox/iOSDemo/OCTTabBarControllerViewController.h create mode 100644 local_pod_repo/objcTox/iOSDemo/OCTTabBarControllerViewController.m create mode 100644 local_pod_repo/objcTox/iOSDemo/OCTTableViewController.h create mode 100644 local_pod_repo/objcTox/iOSDemo/OCTTableViewController.m create mode 100644 local_pod_repo/objcTox/iOSDemo/OCTUserViewController.h create mode 100644 local_pod_repo/objcTox/iOSDemo/OCTUserViewController.m create mode 100644 local_pod_repo/objcTox/iOSDemo/OCTVideoViewController.h create mode 100644 local_pod_repo/objcTox/iOSDemo/OCTVideoViewController.m create mode 100644 local_pod_repo/objcTox/iOSDemo/main.m create mode 100644 local_pod_repo/objcTox/iOSDemoTests/Info.plist create mode 100755 local_pod_repo/objcTox/install.sh create mode 100644 local_pod_repo/objcTox/objcTox.podspec create mode 100644 local_pod_repo/objcTox/objcTox.xcodeproj/project.pbxproj create mode 100644 local_pod_repo/objcTox/objective-c-style-guide.md create mode 100755 local_pod_repo/objcTox/pre-commit.sh create mode 100755 local_pod_repo/objcTox/run-uncrustify.sh create mode 100644 local_pod_repo/objcTox/uncrustify.cfg create mode 100644 local_pod_repo/toxcore/.gitignore create mode 100644 local_pod_repo/toxcore/0002_zoff_tc___capabilites.diff create mode 100644 local_pod_repo/toxcore/LICENSE create mode 100644 local_pod_repo/toxcore/Podfile create mode 100644 local_pod_repo/toxcore/README.md create mode 100755 local_pod_repo/toxcore/build-vpx.sh create mode 100755 local_pod_repo/toxcore/install-tox.sh create mode 100644 local_pod_repo/toxcore/ios/vpx.framework/Headers/arm64-darwin-gcc/vpx_config.h create mode 100644 local_pod_repo/toxcore/ios/vpx.framework/Headers/armv7-darwin-gcc/vpx_config.h create mode 100644 local_pod_repo/toxcore/ios/vpx.framework/Headers/armv7s-darwin-gcc/vpx_config.h create mode 100644 local_pod_repo/toxcore/ios/vpx.framework/Headers/vp8.h create mode 100644 local_pod_repo/toxcore/ios/vpx.framework/Headers/vp8cx.h create mode 100644 local_pod_repo/toxcore/ios/vpx.framework/Headers/vp8dx.h create mode 100644 local_pod_repo/toxcore/ios/vpx.framework/Headers/vpx_codec.h create mode 100644 local_pod_repo/toxcore/ios/vpx.framework/Headers/vpx_config.h create mode 100644 local_pod_repo/toxcore/ios/vpx.framework/Headers/vpx_decoder.h create mode 100644 local_pod_repo/toxcore/ios/vpx.framework/Headers/vpx_encoder.h create mode 100644 local_pod_repo/toxcore/ios/vpx.framework/Headers/vpx_frame_buffer.h create mode 100644 local_pod_repo/toxcore/ios/vpx.framework/Headers/vpx_image.h create mode 100644 local_pod_repo/toxcore/ios/vpx.framework/Headers/vpx_integer.h create mode 100644 local_pod_repo/toxcore/ios/vpx.framework/Headers/vpx_version.h create mode 100644 local_pod_repo/toxcore/ios/vpx.framework/Headers/x86-iphonesimulator-gcc/vpx_config.h create mode 100644 local_pod_repo/toxcore/ios/vpx.framework/Headers/x86_64-iphonesimulator-gcc/vpx_config.h create mode 100644 local_pod_repo/toxcore/ios/vpx.framework/vpx create mode 100644 local_pod_repo/toxcore/msgv3_addon.patch create mode 100644 local_pod_repo/toxcore/osx/vpx.framework/Headers/vp8.h create mode 100644 local_pod_repo/toxcore/osx/vpx.framework/Headers/vp8cx.h create mode 100644 local_pod_repo/toxcore/osx/vpx.framework/Headers/vp8dx.h create mode 100644 local_pod_repo/toxcore/osx/vpx.framework/Headers/vpx_codec.h create mode 100644 local_pod_repo/toxcore/osx/vpx.framework/Headers/vpx_config.h create mode 100644 local_pod_repo/toxcore/osx/vpx.framework/Headers/vpx_decoder.h create mode 100644 local_pod_repo/toxcore/osx/vpx.framework/Headers/vpx_encoder.h create mode 100644 local_pod_repo/toxcore/osx/vpx.framework/Headers/vpx_frame_buffer.h create mode 100644 local_pod_repo/toxcore/osx/vpx.framework/Headers/vpx_image.h create mode 100644 local_pod_repo/toxcore/osx/vpx.framework/Headers/vpx_integer.h create mode 100644 local_pod_repo/toxcore/osx/vpx.framework/Headers/vpx_version.h create mode 100644 local_pod_repo/toxcore/osx/vpx.framework/Headers/x86_64-darwin13-gcc/vpx_config.h create mode 100644 local_pod_repo/toxcore/osx/vpx.framework/vpx create mode 100644 local_pod_repo/toxcore/toxcore.podspec create mode 100644 local_pod_repo/toxcore/toxcore/toxav/Makefile.inc create mode 100644 local_pod_repo/toxcore/toxcore/toxav/audio.h create mode 100644 local_pod_repo/toxcore/toxcore/toxav/audio.m create mode 100644 local_pod_repo/toxcore/toxcore/toxav/bwcontroller.h create mode 100644 local_pod_repo/toxcore/toxcore/toxav/bwcontroller.m create mode 100644 local_pod_repo/toxcore/toxcore/toxav/groupav.h create mode 100644 local_pod_repo/toxcore/toxcore/toxav/groupav.m create mode 100644 local_pod_repo/toxcore/toxcore/toxav/msi.h create mode 100644 local_pod_repo/toxcore/toxcore/toxav/msi.m create mode 100644 local_pod_repo/toxcore/toxcore/toxav/ring_buffer.h create mode 100644 local_pod_repo/toxcore/toxcore/toxav/ring_buffer.m create mode 100644 local_pod_repo/toxcore/toxcore/toxav/rtp.h create mode 100644 local_pod_repo/toxcore/toxcore/toxav/rtp.m create mode 100644 local_pod_repo/toxcore/toxcore/toxav/toxav.h create mode 100644 local_pod_repo/toxcore/toxcore/toxav/toxav.m create mode 100644 local_pod_repo/toxcore/toxcore/toxav/toxav_old.m create mode 100644 local_pod_repo/toxcore/toxcore/toxav/video.h create mode 100644 local_pod_repo/toxcore/toxcore/toxav/video.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/DHT.h create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/DHT.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/LAN_discovery.h create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/LAN_discovery.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/Makefile.inc create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/Messenger.h create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/Messenger.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/TCP_client.h create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/TCP_client.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/TCP_common.h create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/TCP_common.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/TCP_connection.h create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/TCP_connection.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/TCP_server.h create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/TCP_server.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/announce.h create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/announce.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/attributes.h create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/bin_pack.h create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/bin_pack.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/bin_unpack.h create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/bin_unpack.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/ccompat.h create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/ccompat.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/crypto_core.h create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/crypto_core.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/events/conference_connected.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/events/conference_invite.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/events/conference_message.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/events/conference_peer_list_changed.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/events/conference_peer_name.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/events/conference_title.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/events/events_alloc.h create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/events/events_alloc.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/events/file_chunk_request.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/events/file_recv.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/events/file_recv_chunk.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/events/file_recv_control.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/events/friend_connection_status.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/events/friend_lossless_packet.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/events/friend_lossy_packet.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/events/friend_message.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/events/friend_name.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/events/friend_read_receipt.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/events/friend_request.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/events/friend_status.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/events/friend_status_message.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/events/friend_typing.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/events/self_connection_status.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/forwarding.h create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/forwarding.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/friend_connection.h create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/friend_connection.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/friend_requests.h create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/friend_requests.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/group.h create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/group.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/group_announce.h create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/group_announce.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/group_moderation.h create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/group_moderation.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/list.h create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/list.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/logger.h create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/logger.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/mono_time.h create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/mono_time.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/net_crypto.h create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/net_crypto.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/network.h create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/network.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/onion.h create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/onion.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/onion_announce.h create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/onion_announce.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/onion_client.h create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/onion_client.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/ping.h create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/ping.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/ping_array.h create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/ping_array.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/state.h create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/state.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/timed_auth.h create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/timed_auth.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/tox.h create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/tox.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/tox_api.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/tox_dispatch.h create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/tox_dispatch.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/tox_events.h create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/tox_events.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/tox_private.h create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/tox_private.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/tox_struct.h create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/tox_unpack.h create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/tox_unpack.m create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/util.h create mode 100644 local_pod_repo/toxcore/toxcore/toxcore/util.m create mode 100644 local_pod_repo/toxcore/toxcore/toxencryptsave/Makefile.inc create mode 100644 local_pod_repo/toxcore/toxcore/toxencryptsave/defines.h create mode 100644 local_pod_repo/toxcore/toxcore/toxencryptsave/toxencryptsave.h create mode 100644 local_pod_repo/toxcore/toxcore/toxencryptsave/toxencryptsave.m create mode 100644 local_pod_repo/toxcore/vpx-ios.diff create mode 100644 local_pod_repo/toxcore/vpx-osx.diff create mode 100644 pushextension/Info.plist create mode 100644 pushextension/NotificationService.swift create mode 100755 tools/package-ida.sh create mode 100755 tools/prepare_new_release_version.sh diff --git a/Antidote.xcodeproj/project.pbxproj b/Antidote.xcodeproj/project.pbxproj new file mode 100644 index 0000000..7f1bf66 --- /dev/null +++ b/Antidote.xcodeproj/project.pbxproj @@ -0,0 +1,3062 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 1105B18D1EA09B1A0035B213 /* ChatFauxOfflineHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1105B18C1EA09B1A0035B213 /* ChatFauxOfflineHeaderView.swift */; }; + 1105B18E1EA09B1A0035B213 /* ChatFauxOfflineHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1105B18C1EA09B1A0035B213 /* ChatFauxOfflineHeaderView.swift */; }; + 1105B18F1EA09B1A0035B213 /* ChatFauxOfflineHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1105B18C1EA09B1A0035B213 /* ChatFauxOfflineHeaderView.swift */; }; + 1109019B1D83417500BC5751 /* PinInputView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1109019A1D83417500BC5751 /* PinInputView.swift */; }; + 1109019C1D83417500BC5751 /* PinInputView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1109019A1D83417500BC5751 /* PinInputView.swift */; }; + 110E078F1EB0756C00B2CA9D /* ResultsExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 110E078E1EB0756C00B2CA9D /* ResultsExtension.swift */; }; + 110E07901EB0756C00B2CA9D /* ResultsExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 110E078E1EB0756C00B2CA9D /* ResultsExtension.swift */; }; + 110E07911EB0756C00B2CA9D /* ResultsExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 110E078E1EB0756C00B2CA9D /* ResultsExtension.swift */; }; + 110E425C1C00DC5E001A3CA2 /* StaticTableController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 110E425B1C00DC5E001A3CA2 /* StaticTableController.swift */; }; + 110E49E01BF925FD00D1FE6F /* ActiveSessionNavigationCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 110E49DF1BF925FD00D1FE6F /* ActiveSessionNavigationCoordinator.swift */; }; + 111782781DC52BDB000C1721 /* OCTManagerMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 111782771DC52BDB000C1721 /* OCTManagerMock.swift */; }; + 111782791DC52BDB000C1721 /* OCTManagerMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 111782771DC52BDB000C1721 /* OCTManagerMock.swift */; }; + 1117827B1DC52C3A000C1721 /* OCTSubmanagerBootstrapMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1117827A1DC52C3A000C1721 /* OCTSubmanagerBootstrapMock.swift */; }; + 1117827C1DC52C3A000C1721 /* OCTSubmanagerBootstrapMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1117827A1DC52C3A000C1721 /* OCTSubmanagerBootstrapMock.swift */; }; + 1117827E1DC52CBA000C1721 /* OCTSubmanagerCallsMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1117827D1DC52CBA000C1721 /* OCTSubmanagerCallsMock.swift */; }; + 1117827F1DC52CBA000C1721 /* OCTSubmanagerCallsMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1117827D1DC52CBA000C1721 /* OCTSubmanagerCallsMock.swift */; }; + 1117828D1DC531AD000C1721 /* OCTSubmanagerChatsMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1117828C1DC531AD000C1721 /* OCTSubmanagerChatsMock.swift */; }; + 1117828E1DC531AD000C1721 /* OCTSubmanagerChatsMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1117828C1DC531AD000C1721 /* OCTSubmanagerChatsMock.swift */; }; + 111782931DC53371000C1721 /* OCTSubmanagerFilesMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 111782921DC53371000C1721 /* OCTSubmanagerFilesMock.swift */; }; + 111782941DC53371000C1721 /* OCTSubmanagerFilesMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 111782921DC53371000C1721 /* OCTSubmanagerFilesMock.swift */; }; + 111782961DC53458000C1721 /* OCTSubmanagerFriendsMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 111782951DC53458000C1721 /* OCTSubmanagerFriendsMock.swift */; }; + 111782971DC53458000C1721 /* OCTSubmanagerFriendsMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 111782951DC53458000C1721 /* OCTSubmanagerFriendsMock.swift */; }; + 111782991DC53545000C1721 /* OCTSubmanagerObjectsMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 111782981DC53545000C1721 /* OCTSubmanagerObjectsMock.swift */; }; + 1117829A1DC53545000C1721 /* OCTSubmanagerObjectsMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 111782981DC53545000C1721 /* OCTSubmanagerObjectsMock.swift */; }; + 1117829C1DC5363C000C1721 /* OCTSubmanagerUserMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1117829B1DC5363C000C1721 /* OCTSubmanagerUserMock.swift */; }; + 1117829D1DC5363C000C1721 /* OCTSubmanagerUserMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1117829B1DC5363C000C1721 /* OCTSubmanagerUserMock.swift */; }; + 1117829F1DC53AB4000C1721 /* ToxFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1117829E1DC53AB4000C1721 /* ToxFactory.swift */; }; + 111782A01DC53AB4000C1721 /* ToxFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1117829E1DC53AB4000C1721 /* ToxFactory.swift */; }; + 111782AA1DC64391000C1721 /* ScreenshotsUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 111782A91DC64391000C1721 /* ScreenshotsUITests.swift */; }; + 111782BB1DC643A3000C1721 /* OCTManagerMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 111782771DC52BDB000C1721 /* OCTManagerMock.swift */; }; + 111782BC1DC643A3000C1721 /* OCTSubmanagerBootstrapMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1117827A1DC52C3A000C1721 /* OCTSubmanagerBootstrapMock.swift */; }; + 111782BD1DC643A3000C1721 /* OCTSubmanagerCallsMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1117827D1DC52CBA000C1721 /* OCTSubmanagerCallsMock.swift */; }; + 111782BE1DC643A3000C1721 /* OCTSubmanagerChatsMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1117828C1DC531AD000C1721 /* OCTSubmanagerChatsMock.swift */; }; + 111782C01DC643A3000C1721 /* OCTSubmanagerFilesMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 111782921DC53371000C1721 /* OCTSubmanagerFilesMock.swift */; }; + 111782C11DC643A3000C1721 /* OCTSubmanagerFriendsMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 111782951DC53458000C1721 /* OCTSubmanagerFriendsMock.swift */; }; + 111782C21DC643A3000C1721 /* OCTSubmanagerObjectsMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 111782981DC53545000C1721 /* OCTSubmanagerObjectsMock.swift */; }; + 111782C31DC643A3000C1721 /* OCTSubmanagerUserMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1117829B1DC5363C000C1721 /* OCTSubmanagerUserMock.swift */; }; + 111782D21DC64796000C1721 /* BaseCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1193AB651C1F5694006AA9E5 /* BaseCell.swift */; }; + 111782D31DC64796000C1721 /* BaseCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1193AB671C1F569A006AA9E5 /* BaseCellModel.swift */; }; + 111782D41DC64796000C1721 /* ChatBaseTextCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11F276AD1D3EBEF700C613AA /* ChatBaseTextCell.swift */; }; + 111782D51DC64796000C1721 /* ChatBaseTextCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11F276BA1D3EBF3000C613AA /* ChatBaseTextCellModel.swift */; }; + 111782D61DC64796000C1721 /* ChatEditable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1136605B1CDE5D5E0092C27A /* ChatEditable.swift */; }; + 111782D71DC64796000C1721 /* ChatGenericFileCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11628E711CA580ED008C097E /* ChatGenericFileCell.swift */; }; + 111782D81DC64796000C1721 /* ChatGenericFileCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11628E741CA5811C008C097E /* ChatGenericFileCellModel.swift */; }; + 111782D91DC64796000C1721 /* ChatIncomingCallCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1166349F1C6E8D0F0072C980 /* ChatIncomingCallCell.swift */; }; + 111782DA1DC64796000C1721 /* ChatIncomingCallCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 116634A81C6E8D1A0072C980 /* ChatIncomingCallCellModel.swift */; }; + 111782DB1DC64796000C1721 /* ChatIncomingFileCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1183BCAB1CA1B398000CD310 /* ChatIncomingFileCell.swift */; }; + 111782DC1DC64796000C1721 /* ChatIncomingFileCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1183BCB41CA1B3AE000CD310 /* ChatIncomingFileCellModel.swift */; }; + 111782DD1DC64796000C1721 /* ChatIncomingTextCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B252F91C4A614D0068F47C /* ChatIncomingTextCell.swift */; }; + 111782DE1DC64796000C1721 /* ChatListCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CE0BDEF1C4522BF00DCE357 /* ChatListCell.swift */; }; + 111782DF1DC64796000C1721 /* ChatListCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CE0BDF21C4522C800DCE357 /* ChatListCellModel.swift */; }; + 111782E01DC64796000C1721 /* ChatMovableDateCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B253011C4A61D00068F47C /* ChatMovableDateCell.swift */; }; + 111782E11DC64796000C1721 /* ChatMovableDateCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B253031C4A61D50068F47C /* ChatMovableDateCellModel.swift */; }; + 111782E21DC64796000C1721 /* ChatOutgoingCallCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 116634AB1C6F407D0072C980 /* ChatOutgoingCallCell.swift */; }; + 111782E31DC64796000C1721 /* ChatOutgoingCallCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 116634AE1C6F40820072C980 /* ChatOutgoingCallCellModel.swift */; }; + 111782E41DC64796000C1721 /* ChatOutgoingFileCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11628E621CA57B14008C097E /* ChatOutgoingFileCell.swift */; }; + 111782E51DC64796000C1721 /* ChatOutgoingFileCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11628E6B1CA57B19008C097E /* ChatOutgoingFileCellModel.swift */; }; + 111782E61DC64796000C1721 /* ChatOutgoingTextCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B252FD1C4A615E0068F47C /* ChatOutgoingTextCell.swift */; }; + 111782E71DC64796000C1721 /* ChatProgressBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1183BCDC1CA1FD55000CD310 /* ChatProgressBridge.swift */; }; + 111782E81DC64796000C1721 /* ChatProgressProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1183BCD61CA1FC5B000CD310 /* ChatProgressProtocol.swift */; }; + 111782E91DC64796000C1721 /* FriendListCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1193AB691C1F5C28006AA9E5 /* FriendListCell.swift */; }; + 111782EA1DC64796000C1721 /* FriendListCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1193AB6B1C1F5C31006AA9E5 /* FriendListCellModel.swift */; }; + 111782EB1DC64796000C1721 /* StaticTableAvatarCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1156A4861C10D122005AC8C6 /* StaticTableAvatarCell.swift */; }; + 111782EC1DC64796000C1721 /* StaticTableAvatarCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1156A4841C10D119005AC8C6 /* StaticTableAvatarCellModel.swift */; }; + 111782ED1DC64796000C1721 /* StaticTableBaseCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C04BB6C1C17389200F58488 /* StaticTableBaseCell.swift */; }; + 111782EE1DC64796000C1721 /* StaticTableBaseCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1156A4781C0E478D005AC8C6 /* StaticTableBaseCellModel.swift */; }; + 111782EF1DC64796000C1721 /* StaticTableButtonCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1156A4801C0FA0A4005AC8C6 /* StaticTableButtonCell.swift */; }; + 111782F01DC64796000C1721 /* StaticTableButtonCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1156A47A1C0F6178005AC8C6 /* StaticTableButtonCellModel.swift */; }; + 111782F11DC64796000C1721 /* StaticTableChatButtonsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 116513211C2C74940066AF06 /* StaticTableChatButtonsCell.swift */; }; + 111782F21DC64796000C1721 /* StaticTableChatButtonsCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 116513231C2C749E0066AF06 /* StaticTableChatButtonsCellModel.swift */; }; + 111782F31DC64796000C1721 /* StaticTableDefaultCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 115DFB891C177F5C00F18DB5 /* StaticTableDefaultCell.swift */; }; + 111782F41DC64796000C1721 /* StaticTableDefaultCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 115DFB951C177F6500F18DB5 /* StaticTableDefaultCellModel.swift */; }; + 111782F51DC64796000C1721 /* StaticTableInfoCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 116634DF1C7B8D770072C980 /* StaticTableInfoCell.swift */; }; + 111782F61DC64796000C1721 /* StaticTableInfoCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 116634E81C7B8D7C0072C980 /* StaticTableInfoCellModel.swift */; }; + 111782F71DC64796000C1721 /* StaticTableMultiChoiceButtonCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 116634EE1C7B94530072C980 /* StaticTableMultiChoiceButtonCell.swift */; }; + 111782F81DC64796000C1721 /* StaticTableMultiChoiceButtonCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 116634F11C7B945A0072C980 /* StaticTableMultiChoiceButtonCellModel.swift */; }; + 111782F91DC64796000C1721 /* StaticTableSelectableCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1156A47C1C0F632C005AC8C6 /* StaticTableSelectableCellModel.swift */; }; + 111782FA1DC64796000C1721 /* StaticTableSwitchCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B253FA1C52C0A10068F47C /* StaticTableSwitchCell.swift */; }; + 111782FB1DC64796000C1721 /* StaticTableSwitchCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B253FD1C52C0AA0068F47C /* StaticTableSwitchCellModel.swift */; }; + 111782FC1DC6479E000C1721 /* AlertAudioPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 113F03411CB31DD60009ABE1 /* AlertAudioPlayer.swift */; }; + 111782FD1DC6479E000C1721 /* AudioPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B2534E1C4AD2550068F47C /* AudioPlayer.swift */; }; + 111782FE1DC6479E000C1721 /* AvatarManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1156A4881C15FB2B005AC8C6 /* AvatarManager.swift */; }; + 111782FF1DC6479E000C1721 /* ChatListTableManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C2EF3791C4E2DDE006E7AB1 /* ChatListTableManager.swift */; }; + 111783001DC6479E000C1721 /* FilePreviewControllerDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11628E311CA2FBD1008C097E /* FilePreviewControllerDataSource.swift */; }; + 111783011DC6479E000C1721 /* FriendListDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CDC091A1C34081900DC0D63 /* FriendListDataSource.swift */; }; + 111783021DC6479E000C1721 /* KeychainManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1160B67D1D5F9993002DF75B /* KeychainManager.swift */; }; + 111783031DC6479E000C1721 /* NotificationObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CEE6B1E1C510A1E00A1ECB5 /* NotificationObject.swift */; }; + 111783041DC6479E000C1721 /* ProfileManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CDDB2051BD5376200B65D79 /* ProfileManager.swift */; }; + 111783051DC6479E000C1721 /* ProfileSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C1FEB281D8C10EB008C2ADE /* ProfileSettings.swift */; }; + 111783061DC6479E000C1721 /* Results.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11FC10561D32E54A00CE863E /* Results.swift */; }; + 111783071DC6479E000C1721 /* ResultsChange.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11FC10591D32EED000CE863E /* ResultsChange.swift */; }; + 111783081DC6479E000C1721 /* TabBarAbstractItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B253651C4BAD3C0068F47C /* TabBarAbstractItem.swift */; }; + 111783091DC6479E000C1721 /* TabBarBadgeItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B253691C4BAD560068F47C /* TabBarBadgeItem.swift */; }; + 1117830A1DC6479E000C1721 /* TabBarProfileItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B2536C1C4BAD5D0068F47C /* TabBarProfileItem.swift */; }; + 1117830B1DC6479E000C1721 /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1173F06D1BC5D9BA00B88B7B /* Theme.swift */; }; + 1117830C1DC6479E000C1721 /* ToxFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1117829E1DC53AB4000C1721 /* ToxFactory.swift */; }; + 1117830D1DC6479E000C1721 /* UserDefaultsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1164C8D71BC922EB00B91107 /* UserDefaultsManager.swift */; }; + 1117830E1DC647BD000C1721 /* KeyboardNotificationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 112422651BDD2032004D7926 /* KeyboardNotificationController.swift */; }; + 1117830F1DC647BD000C1721 /* LaunchPlaceholderController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1160B6891D5FD8DE002DF75B /* LaunchPlaceholderController.swift */; }; + 111783101DC647BD000C1721 /* LaunchPlaceholderBoard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 11DDEAFC1D5FD9FE0000E2BE /* LaunchPlaceholderBoard.storyboard */; }; + 111783111DC647BD000C1721 /* PortraitNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C07151C1BCD2E5B003A27B5 /* PortraitNavigationController.swift */; }; + 111783121DC647C1000C1721 /* LoginBaseController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1164C8E61BC929C500B91107 /* LoginBaseController.swift */; }; + 111783131DC647C1000C1721 /* LoginChoiceController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1164C8E81BC929F700B91107 /* LoginChoiceController.swift */; }; + 111783141DC647C1000C1721 /* LoginCreateAccountController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CBBC7C01BDFC62700099A5E /* LoginCreateAccountController.swift */; }; + 111783151DC647C1000C1721 /* LoginCreatePasswordController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 112950861D63AFD800C9CE0F /* LoginCreatePasswordController.swift */; }; + 111783161DC647C1000C1721 /* LoginFormController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C07151E1BCD501D003A27B5 /* LoginFormController.swift */; }; + 111783171DC647C1000C1721 /* LoginGenericCreateController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 112950831D63AFCE00C9CE0F /* LoginGenericCreateController.swift */; }; + 111783181DC647C1000C1721 /* LoginLogoController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1164C8F21BC9880000B91107 /* LoginLogoController.swift */; }; + 111783191DC647CF000C1721 /* AppCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11FA0ED91BC584D900F3DA5B /* AppCoordinator.swift */; }; + 1117831A1DC647CF000C1721 /* CoordinatorProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11FA0EDD1BC58DCC00F3DA5B /* CoordinatorProtocol.swift */; }; + 1117831B1DC647CF000C1721 /* TopCoordinatorProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 116DCE311CAAF47100B693EC /* TopCoordinatorProtocol.swift */; }; + 1117831C1DC647D4000C1721 /* LoginCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11FA0EE81BC5A66D00F3DA5B /* LoginCoordinator.swift */; }; + 1117831D1DC647D4000C1721 /* LoginCreateAccountCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1129508A1D6851EB00C9CE0F /* LoginCreateAccountCoordinator.swift */; }; + 1117831E1DC647D9000C1721 /* ActiveSessionCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11FA0EE61BC59B1400F3DA5B /* ActiveSessionCoordinator.swift */; }; + 1117831F1DC647D9000C1721 /* ActiveSessionNavigationCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 110E49DF1BF925FD00D1FE6F /* ActiveSessionNavigationCoordinator.swift */; }; + 111783201DC647D9000C1721 /* AutomationCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11771E2B1CA5C3F200EC259E /* AutomationCoordinator.swift */; }; + 111783211DC647D9000C1721 /* CallCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1180FD9F1C384E29005F3EA1 /* CallCoordinator.swift */; }; + 111783221DC647D9000C1721 /* ChatsTabCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11FA0EF21BC5A6AF00F3DA5B /* ChatsTabCoordinator.swift */; }; + 111783231DC647D9000C1721 /* FriendsTabCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11FA0EEA1BC5A68600F3DA5B /* FriendsTabCoordinator.swift */; }; + 111783241DC647D9000C1721 /* NotificationCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C2EF3701C4D4D5C006E7AB1 /* NotificationCoordinator.swift */; }; + 111783251DC647D9000C1721 /* PinAuthorizationCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C3271861D79C19C00347490 /* PinAuthorizationCoordinator.swift */; }; + 111783261DC647D9000C1721 /* ProfileTabCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11FA0EEC1BC5A69000F3DA5B /* ProfileTabCoordinator.swift */; }; + 111783271DC647D9000C1721 /* RunningCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CB1F9501D58CA4000105858 /* RunningCoordinator.swift */; }; + 111783281DC647D9000C1721 /* SettingsTabCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11FA0EF01BC5A6A500F3DA5B /* SettingsTabCoordinator.swift */; }; + 111783291DC647DF000C1721 /* InterfaceIdiom.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B253A31C4EA8040068F47C /* InterfaceIdiom.swift */; }; + 1117832A1DC647DF000C1721 /* UserStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11CFCD0A1C2745230046BD94 /* UserStatus.swift */; }; + 1117832B1DC647E4000C1721 /* NSDateFormatterExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1180FD9D1C38497A005F3EA1 /* NSDateFormatterExtension.swift */; }; + 1117832C1DC647E4000C1721 /* NSTimerExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B253B61C503FA10068F47C /* NSTimerExtension.swift */; }; + 1117832D1DC647E4000C1721 /* NSURLExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 116DCE3A1CAAF85300B693EC /* NSURLExtension.swift */; }; + 1117832E1DC647E4000C1721 /* OCTManagerConfigurationExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B9C6821BD598FC0083C2A5 /* OCTManagerConfigurationExtension.swift */; }; + 1117832F1DC647E4000C1721 /* OCTSubmanagerObjectsExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11FC105C1D32F29700CE863E /* OCTSubmanagerObjectsExtension.swift */; }; + 111783301DC647E4000C1721 /* StringExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C7475C41BC698510098B1A4 /* StringExtension.swift */; }; + 111783311DC647E4000C1721 /* UIAlertControllerExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11770D761CBC1C7A00D34D6E /* UIAlertControllerExtension.swift */; }; + 111783321DC647E4000C1721 /* UIApplicationExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 116634B11C7087A80072C980 /* UIApplicationExtension.swift */; }; + 111783331DC647E4000C1721 /* UIColorExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 119AD1CB1BDEDD9C000C5CB8 /* UIColorExtension.swift */; }; + 111783341DC647E4000C1721 /* UIFontExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 113F03321CB2E9C20009ABE1 /* UIFontExtension.swift */; }; + 111783351DC647E4000C1721 /* UIImageExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1164C8EF1BC982FF00B91107 /* UIImageExtension.swift */; }; + 111783361DC647E4000C1721 /* UIViewControllerExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1164C8F51BC98F8300B91107 /* UIViewControllerExtension.swift */; }; + 111783371DC647F8000C1721 /* ErrorHandling.swift in Sources */ = {isa = PBXBuildFile; fileRef = 119AD1C91BDED6E9000C5CB8 /* ErrorHandling.swift */; }; + 111783381DC647F8000C1721 /* ExceptionHandling.m in Sources */ = {isa = PBXBuildFile; fileRef = 9CDC092B1C34102F00DC0D63 /* ExceptionHandling.m */; }; + 111783391DC647F8000C1721 /* HelperFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11E640771C2DC15400D24C6D /* HelperFunctions.swift */; }; + 1117833A1DC647F8000C1721 /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11FA0EE01BC591FC00F3DA5B /* Logger.swift */; }; + 1117833B1DC647FF000C1721 /* Reach.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11771E351CA5C6E900EC259E /* Reach.swift */; }; + 1117833C1DC64810000C1721 /* BubbleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B253131C4A79A50068F47C /* BubbleView.swift */; }; + 1117833D1DC64810000C1721 /* CallButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 112E4EE41C676553004312CF /* CallButton.swift */; }; + 1117833E1DC64810000C1721 /* ChatInputView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11A21EFC1C45BDF200E80A89 /* ChatInputView.swift */; }; + 1117833F1DC64810000C1721 /* ChatPrivateTitleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B253551C4AEA400068F47C /* ChatPrivateTitleView.swift */; }; + 111783401DC64810000C1721 /* CopyLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 116634D81C70F1260072C980 /* CopyLabel.swift */; }; + 111783411DC64810000C1721 /* ExtendedTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CBBC7CC1BDFC6C600099A5E /* ExtendedTextField.swift */; }; + 111783421DC64810000C1721 /* FullscreenPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B9C6961BD80B080083C2A5 /* FullscreenPicker.swift */; }; + 111783431DC64810000C1721 /* ImageViewWithStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11CFCD0C1C27488E0046BD94 /* ImageViewWithStatus.swift */; }; + 111783441DC64810000C1721 /* IncompressibleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B253AD1C4EC47D0068F47C /* IncompressibleView.swift */; }; + 111783451DC64810000C1721 /* iPadFriendsButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 113AD8561CA9C70F00D981B5 /* iPadFriendsButton.swift */; }; + 111783461DC64810000C1721 /* iPadNavigationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 113AD8491CA97A3000D981B5 /* iPadNavigationView.swift */; }; + 111783471DC64810000C1721 /* LoadingImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11628E771CA5819B008C097E /* LoadingImageView.swift */; }; + 111783481DC64810000C1721 /* NotificationWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 116513251C2D636A0066AF06 /* NotificationWindow.swift */; }; + 111783491DC64810000C1721 /* PinInputView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1109019A1D83417500BC5751 /* PinInputView.swift */; }; + 1117834A1DC64810000C1721 /* ProgressCircleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1183BCBF1CA1DB05000CD310 /* ProgressCircleView.swift */; }; + 1117834B1DC64810000C1721 /* QRScannerAimView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 113D564C1C2F437B00B3D3E8 /* QRScannerAimView.swift */; }; + 1117834C1DC64810000C1721 /* RoundedButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1164C8EC1BC9801200B91107 /* RoundedButton.swift */; }; + 1117834D1DC64810000C1721 /* StaticBackgroundView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11CFCD101C2A02350046BD94 /* StaticBackgroundView.swift */; }; + 1117834E1DC64810000C1721 /* UserStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11CFCD0E1C27499D0046BD94 /* UserStatusView.swift */; }; + 1117834F1DC64810000C1721 /* ViewPassingGestures.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11E6406C1C2D6C3500D24C6D /* ViewPassingGestures.swift */; }; + 111783691DC64D50000C1721 /* QuickLookPreviewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11628E3D1CA30C13008C097E /* QuickLookPreviewController.swift */; }; + 1117836A1DC64D5A000C1721 /* CallIncomingController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 112E4ED51C668C02004312CF /* CallIncomingController.swift */; }; + 1117836B1DC64D68000C1721 /* CallBaseController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 114962941C64051A001E5435 /* CallBaseController.swift */; }; + 1117836C1DC64D75000C1721 /* AddFriendController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11E640751C2DBAE200D24C6D /* AddFriendController.swift */; }; + 1117836D1DC64D75000C1721 /* CallActiveController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 112E4EDE1C675C58004312CF /* CallActiveController.swift */; }; + 1117836E1DC64D75000C1721 /* ChangeAutodownloadImagesController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11628E7A1CA5BF1F008C097E /* ChangeAutodownloadImagesController.swift */; }; + 1117836F1DC64D75000C1721 /* ChangePasswordController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 114962911C5E1BE0001E5435 /* ChangePasswordController.swift */; }; + 111783701DC64D75000C1721 /* ChangePinTimeoutController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 116046181D8D434B002287C8 /* ChangePinTimeoutController.swift */; }; + 111783711DC64D75000C1721 /* ChangeUserStatusController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1149626B1C5CE3DF001E5435 /* ChangeUserStatusController.swift */; }; + 111783721DC64D75000C1721 /* ChatListController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CE0BDE51C45229500DCE357 /* ChatListController.swift */; }; + 111783731DC64D75000C1721 /* ChatPrivateController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11A21EFA1C45BDB100E80A89 /* ChatPrivateController.swift */; }; + 111783741DC64D75000C1721 /* EnterPinController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C19367D1D79CF7E005EA0B2 /* EnterPinController.swift */; }; + 111783751DC64D75000C1721 /* FAQController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11AEBE701DA1876F00D04B59 /* FAQController.swift */; }; + 111783761DC64D75000C1721 /* FriendCardController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 116513181C2C6C980066AF06 /* FriendCardController.swift */; }; + 111783771DC64D75000C1721 /* FriendListController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1193AB471C1F4164006AA9E5 /* FriendListController.swift */; }; + 111783781DC64D75000C1721 /* FriendRequestController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 116634EB1C7B90F20072C980 /* FriendRequestController.swift */; }; + 111783791DC64D75000C1721 /* FriendSelectController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11770D691CBC120C00D34D6E /* FriendSelectController.swift */; }; + 1117837A1DC64D75000C1721 /* PrimaryIpadController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CEE6AA11C4E679100A1ECB5 /* PrimaryIpadController.swift */; }; + 1117837B1DC64D75000C1721 /* ProfileDetailsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 114962741C5CEB0B001E5435 /* ProfileDetailsController.swift */; }; + 1117837C1DC64D75000C1721 /* ProfileMainController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C9A07001BE793BA0003D6C7 /* ProfileMainController.swift */; }; + 1117837D1DC64D75000C1721 /* QRScannerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 113D56551C2F459E00B3D3E8 /* QRScannerController.swift */; }; + 1117837E1DC64D75000C1721 /* QRViewerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1193AB411C1E2075006AA9E5 /* QRViewerController.swift */; }; + 1117837F1DC64D75000C1721 /* SettingsAboutController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CEE6B4E1C528AAA00A1ECB5 /* SettingsAboutController.swift */; }; + 111783801DC64D75000C1721 /* SettingsAdvancedController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CEE6B511C528AB600A1ECB5 /* SettingsAdvancedController.swift */; }; + 111783811DC64D75000C1721 /* SettingsMainController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CEE6B451C5289E200A1ECB5 /* SettingsMainController.swift */; }; + 111783821DC64D75000C1721 /* StaticTableController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 110E425B1C00DC5E001A3CA2 /* StaticTableController.swift */; }; + 111783831DC64D75000C1721 /* TabBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B2535C1C4BACDB0068F47C /* TabBarController.swift */; }; + 111783841DC64D75000C1721 /* TextEditController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1193AB351C1DEF2E006AA9E5 /* TextEditController.swift */; }; + 111783851DC64D75000C1721 /* TextViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 119AD1BD1BDED261000C5CB8 /* TextViewController.swift */; }; + 112422661BDD2032004D7926 /* KeyboardNotificationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 112422651BDD2032004D7926 /* KeyboardNotificationController.swift */; }; + 112495371DE7ABFF00EF45C4 /* KeyboardObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 112495361DE7ABFF00EF45C4 /* KeyboardObserver.swift */; }; + 1124953E1DE7AC0300EF45C4 /* KeyboardObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 112495361DE7ABFF00EF45C4 /* KeyboardObserver.swift */; }; + 1124953F1DE7AC0400EF45C4 /* KeyboardObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 112495361DE7ABFF00EF45C4 /* KeyboardObserver.swift */; }; + 112950841D63AFCE00C9CE0F /* LoginGenericCreateController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 112950831D63AFCE00C9CE0F /* LoginGenericCreateController.swift */; }; + 112950851D63AFCE00C9CE0F /* LoginGenericCreateController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 112950831D63AFCE00C9CE0F /* LoginGenericCreateController.swift */; }; + 112950871D63AFD800C9CE0F /* LoginCreatePasswordController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 112950861D63AFD800C9CE0F /* LoginCreatePasswordController.swift */; }; + 112950881D63AFD800C9CE0F /* LoginCreatePasswordController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 112950861D63AFD800C9CE0F /* LoginCreatePasswordController.swift */; }; + 1129508B1D6851EB00C9CE0F /* LoginCreateAccountCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1129508A1D6851EB00C9CE0F /* LoginCreateAccountCoordinator.swift */; }; + 1129508C1D6851EB00C9CE0F /* LoginCreateAccountCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1129508A1D6851EB00C9CE0F /* LoginCreateAccountCoordinator.swift */; }; + 112E4ED61C668C02004312CF /* CallIncomingController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 112E4ED51C668C02004312CF /* CallIncomingController.swift */; }; + 112E4ED71C668C02004312CF /* CallIncomingController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 112E4ED51C668C02004312CF /* CallIncomingController.swift */; }; + 112E4EDF1C675C58004312CF /* CallActiveController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 112E4EDE1C675C58004312CF /* CallActiveController.swift */; }; + 112E4EE01C675C58004312CF /* CallActiveController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 112E4EDE1C675C58004312CF /* CallActiveController.swift */; }; + 112E4EE51C676553004312CF /* CallButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 112E4EE41C676553004312CF /* CallButton.swift */; }; + 112E4EE61C676553004312CF /* CallButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 112E4EE41C676553004312CF /* CallButton.swift */; }; + 113187441DD63B6600E6FAA2 /* ChatOutgoingTextCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 113187431DD63B6600E6FAA2 /* ChatOutgoingTextCellModel.swift */; }; + 113187451DD63B6600E6FAA2 /* ChatOutgoingTextCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 113187431DD63B6600E6FAA2 /* ChatOutgoingTextCellModel.swift */; }; + 113187461DD63B6600E6FAA2 /* ChatOutgoingTextCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 113187431DD63B6600E6FAA2 /* ChatOutgoingTextCellModel.swift */; }; + 1131D6C51CA9D8BC00B4531C /* import-profile.html in Resources */ = {isa = PBXBuildFile; fileRef = 1131D6C71CA9D8BC00B4531C /* import-profile.html */; }; + 1136605C1CDE5D5E0092C27A /* ChatEditable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1136605B1CDE5D5E0092C27A /* ChatEditable.swift */; }; + 113AD84A1CA97A3000D981B5 /* iPadNavigationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 113AD8491CA97A3000D981B5 /* iPadNavigationView.swift */; }; + 113AD84B1CA97A3000D981B5 /* iPadNavigationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 113AD8491CA97A3000D981B5 /* iPadNavigationView.swift */; }; + 113AD8571CA9C70F00D981B5 /* iPadFriendsButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 113AD8561CA9C70F00D981B5 /* iPadFriendsButton.swift */; }; + 113AD8581CA9C70F00D981B5 /* iPadFriendsButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 113AD8561CA9C70F00D981B5 /* iPadFriendsButton.swift */; }; + 113BBBA71EA88EAC00540E6C /* ChatTypingHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 113BBBA61EA88EAC00540E6C /* ChatTypingHeaderView.swift */; }; + 113BBBA81EA88EAC00540E6C /* ChatTypingHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 113BBBA61EA88EAC00540E6C /* ChatTypingHeaderView.swift */; }; + 113BBBA91EA88EAC00540E6C /* ChatTypingHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 113BBBA61EA88EAC00540E6C /* ChatTypingHeaderView.swift */; }; + 113D564D1C2F437B00B3D3E8 /* QRScannerAimView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 113D564C1C2F437B00B3D3E8 /* QRScannerAimView.swift */; }; + 113D56561C2F459E00B3D3E8 /* QRScannerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 113D56551C2F459E00B3D3E8 /* QRScannerController.swift */; }; + 113E96421E4BB302000282FC /* AppStoreLocalizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 113E96461E4BB302000282FC /* AppStoreLocalizable.strings */; }; + 113E96431E4BB302000282FC /* AppStoreLocalizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 113E96461E4BB302000282FC /* AppStoreLocalizable.strings */; }; + 113E96441E4BB302000282FC /* AppStoreLocalizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 113E96461E4BB302000282FC /* AppStoreLocalizable.strings */; }; + 113F03081CAFCC9D0009ABE1 /* default-theme.yaml in Resources */ = {isa = PBXBuildFile; fileRef = 1173F0711BC5D9DA00B88B7B /* default-theme.yaml */; }; + 113F030A1CAFCCB90009ABE1 /* SnapshotBaseTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 113F03091CAFCCB90009ABE1 /* SnapshotBaseTest.swift */; }; + 113F030C1CAFCCDD0009ABE1 /* ChatIncomingCallCellSnapshotTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 113F030B1CAFCCDD0009ABE1 /* ChatIncomingCallCellSnapshotTest.swift */; }; + 113F030F1CAFCE7B0009ABE1 /* ChatIncomingFileCellSnapshotTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 113F030E1CAFCE7B0009ABE1 /* ChatIncomingFileCellSnapshotTest.swift */; }; + 113F03111CAFD1610009ABE1 /* icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 113F03101CAFD1610009ABE1 /* icon.png */; }; + 113F03141CAFD5EE0009ABE1 /* CellSnapshotTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 113F03131CAFD5EE0009ABE1 /* CellSnapshotTest.swift */; }; + 113F03171CAFD9370009ABE1 /* MockedChatProgressProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 113F03161CAFD9370009ABE1 /* MockedChatProgressProtocol.swift */; }; + 113F03191CAFDB0D0009ABE1 /* ChatIncomingTextCellSnapshotTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 113F03181CAFDB0D0009ABE1 /* ChatIncomingTextCellSnapshotTest.swift */; }; + 113F031B1CAFDBF70009ABE1 /* ChatListCellSnapshotTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 113F031A1CAFDBF70009ABE1 /* ChatListCellSnapshotTest.swift */; }; + 113F031D1CAFE0DE0009ABE1 /* ChatMovableDateCellSnapshotTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 113F031C1CAFE0DE0009ABE1 /* ChatMovableDateCellSnapshotTest.swift */; }; + 113F031F1CAFE2130009ABE1 /* ChatOutgoingCallCellSnapshotTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 113F031E1CAFE2130009ABE1 /* ChatOutgoingCallCellSnapshotTest.swift */; }; + 113F03211CAFE2B50009ABE1 /* ChatOutgoingFileCellSnapshotTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 113F03201CAFE2B50009ABE1 /* ChatOutgoingFileCellSnapshotTest.swift */; }; + 113F03231CAFE5190009ABE1 /* ChatOutgoingTextCellSnapshotTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 113F03221CAFE5190009ABE1 /* ChatOutgoingTextCellSnapshotTest.swift */; }; + 113F03331CB2E9C20009ABE1 /* UIFontExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 113F03321CB2E9C20009ABE1 /* UIFontExtension.swift */; }; + 113F03341CB2E9C20009ABE1 /* UIFontExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 113F03321CB2E9C20009ABE1 /* UIFontExtension.swift */; }; + 113F03421CB31DD60009ABE1 /* AlertAudioPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 113F03411CB31DD60009ABE1 /* AlertAudioPlayer.swift */; }; + 113F03431CB31DD60009ABE1 /* AlertAudioPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 113F03411CB31DD60009ABE1 /* AlertAudioPlayer.swift */; }; + 1143E4331DCE1A5600BE7250 /* import-profile.html in Resources */ = {isa = PBXBuildFile; fileRef = 1131D6C71CA9D8BC00B4531C /* import-profile.html */; }; + 1149626C1C5CE3DF001E5435 /* ChangeUserStatusController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1149626B1C5CE3DF001E5435 /* ChangeUserStatusController.swift */; }; + 1149626D1C5CE3DF001E5435 /* ChangeUserStatusController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1149626B1C5CE3DF001E5435 /* ChangeUserStatusController.swift */; }; + 114962751C5CEB0B001E5435 /* ProfileDetailsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 114962741C5CEB0B001E5435 /* ProfileDetailsController.swift */; }; + 114962761C5CEB0B001E5435 /* ProfileDetailsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 114962741C5CEB0B001E5435 /* ProfileDetailsController.swift */; }; + 114962921C5E1BE0001E5435 /* ChangePasswordController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 114962911C5E1BE0001E5435 /* ChangePasswordController.swift */; }; + 114962931C5E1BE0001E5435 /* ChangePasswordController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 114962911C5E1BE0001E5435 /* ChangePasswordController.swift */; }; + 114962951C64051A001E5435 /* CallBaseController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 114962941C64051A001E5435 /* CallBaseController.swift */; }; + 114962961C64051A001E5435 /* CallBaseController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 114962941C64051A001E5435 /* CallBaseController.swift */; }; + 114D2D401E34D6E400662713 /* SnapshotHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 114D2D3F1E34D6E400662713 /* SnapshotHelper.swift */; }; + 1156A4791C0E478D005AC8C6 /* StaticTableBaseCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1156A4781C0E478D005AC8C6 /* StaticTableBaseCellModel.swift */; }; + 1156A47B1C0F6178005AC8C6 /* StaticTableButtonCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1156A47A1C0F6178005AC8C6 /* StaticTableButtonCellModel.swift */; }; + 1156A47D1C0F632C005AC8C6 /* StaticTableSelectableCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1156A47C1C0F632C005AC8C6 /* StaticTableSelectableCellModel.swift */; }; + 1156A4811C0FA0A4005AC8C6 /* StaticTableButtonCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1156A4801C0FA0A4005AC8C6 /* StaticTableButtonCell.swift */; }; + 1156A4851C10D119005AC8C6 /* StaticTableAvatarCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1156A4841C10D119005AC8C6 /* StaticTableAvatarCellModel.swift */; }; + 1156A4871C10D122005AC8C6 /* StaticTableAvatarCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1156A4861C10D122005AC8C6 /* StaticTableAvatarCell.swift */; }; + 1156A4891C15FB2B005AC8C6 /* AvatarManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1156A4881C15FB2B005AC8C6 /* AvatarManager.swift */; }; + 115C3BD61DC6D2B900903A47 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 9C7475C01BC698110098B1A4 /* Localizable.strings */; }; + 115CE3E81EB06F54001C08A0 /* ChatBottomStatusViewManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 115CE3E71EB06F54001C08A0 /* ChatBottomStatusViewManager.swift */; }; + 115CE3E91EB06F54001C08A0 /* ChatBottomStatusViewManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 115CE3E71EB06F54001C08A0 /* ChatBottomStatusViewManager.swift */; }; + 115CE3EA1EB06F54001C08A0 /* ChatBottomStatusViewManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 115CE3E71EB06F54001C08A0 /* ChatBottomStatusViewManager.swift */; }; + 115DFB8A1C177F5C00F18DB5 /* StaticTableDefaultCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 115DFB891C177F5C00F18DB5 /* StaticTableDefaultCell.swift */; }; + 115DFB961C177F6500F18DB5 /* StaticTableDefaultCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 115DFB951C177F6500F18DB5 /* StaticTableDefaultCellModel.swift */; }; + 116046191D8D434B002287C8 /* ChangePinTimeoutController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 116046181D8D434B002287C8 /* ChangePinTimeoutController.swift */; }; + 1160461A1D8D434B002287C8 /* ChangePinTimeoutController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 116046181D8D434B002287C8 /* ChangePinTimeoutController.swift */; }; + 1160B67E1D5F9993002DF75B /* KeychainManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1160B67D1D5F9993002DF75B /* KeychainManager.swift */; }; + 1160B67F1D5F9993002DF75B /* KeychainManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1160B67D1D5F9993002DF75B /* KeychainManager.swift */; }; + 1160B6821D5FC7CC002DF75B /* KeychainManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1160B6801D5FC7CC002DF75B /* KeychainManagerTests.swift */; }; + 1160B68B1D5FD8DE002DF75B /* LaunchPlaceholderController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1160B6891D5FD8DE002DF75B /* LaunchPlaceholderController.swift */; }; + 1160B68C1D5FD8DE002DF75B /* LaunchPlaceholderController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1160B6891D5FD8DE002DF75B /* LaunchPlaceholderController.swift */; }; + 11628E321CA2FBD1008C097E /* FilePreviewControllerDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11628E311CA2FBD1008C097E /* FilePreviewControllerDataSource.swift */; }; + 11628E331CA2FBD1008C097E /* FilePreviewControllerDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11628E311CA2FBD1008C097E /* FilePreviewControllerDataSource.swift */; }; + 11628E3E1CA30C13008C097E /* QuickLookPreviewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11628E3D1CA30C13008C097E /* QuickLookPreviewController.swift */; }; + 11628E3F1CA30C13008C097E /* QuickLookPreviewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11628E3D1CA30C13008C097E /* QuickLookPreviewController.swift */; }; + 11628E631CA57B14008C097E /* ChatOutgoingFileCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11628E621CA57B14008C097E /* ChatOutgoingFileCell.swift */; }; + 11628E641CA57B14008C097E /* ChatOutgoingFileCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11628E621CA57B14008C097E /* ChatOutgoingFileCell.swift */; }; + 11628E6C1CA57B19008C097E /* ChatOutgoingFileCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11628E6B1CA57B19008C097E /* ChatOutgoingFileCellModel.swift */; }; + 11628E6D1CA57B19008C097E /* ChatOutgoingFileCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11628E6B1CA57B19008C097E /* ChatOutgoingFileCellModel.swift */; }; + 11628E721CA580ED008C097E /* ChatGenericFileCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11628E711CA580ED008C097E /* ChatGenericFileCell.swift */; }; + 11628E731CA580ED008C097E /* ChatGenericFileCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11628E711CA580ED008C097E /* ChatGenericFileCell.swift */; }; + 11628E751CA5811C008C097E /* ChatGenericFileCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11628E741CA5811C008C097E /* ChatGenericFileCellModel.swift */; }; + 11628E761CA5811C008C097E /* ChatGenericFileCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11628E741CA5811C008C097E /* ChatGenericFileCellModel.swift */; }; + 11628E781CA5819B008C097E /* LoadingImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11628E771CA5819B008C097E /* LoadingImageView.swift */; }; + 11628E791CA5819B008C097E /* LoadingImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11628E771CA5819B008C097E /* LoadingImageView.swift */; }; + 11628E7B1CA5BF1F008C097E /* ChangeAutodownloadImagesController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11628E7A1CA5BF1F008C097E /* ChangeAutodownloadImagesController.swift */; }; + 11628E7C1CA5BF1F008C097E /* ChangeAutodownloadImagesController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11628E7A1CA5BF1F008C097E /* ChangeAutodownloadImagesController.swift */; }; + 1164763319794D3300DB20B8 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1164763219794D3300DB20B8 /* Foundation.framework */; }; + 1164763519794D3300DB20B8 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1164763419794D3300DB20B8 /* CoreGraphics.framework */; }; + 1164763719794D3300DB20B8 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1164763619794D3300DB20B8 /* UIKit.framework */; }; + 1164764519794D3300DB20B8 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1164764419794D3300DB20B8 /* Images.xcassets */; }; + 1164C8D81BC922EB00B91107 /* UserDefaultsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1164C8D71BC922EB00B91107 /* UserDefaultsManager.swift */; }; + 1164C8E71BC929C500B91107 /* LoginBaseController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1164C8E61BC929C500B91107 /* LoginBaseController.swift */; }; + 1164C8E91BC929F700B91107 /* LoginChoiceController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1164C8E81BC929F700B91107 /* LoginChoiceController.swift */; }; + 1164C8ED1BC9801200B91107 /* RoundedButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1164C8EC1BC9801200B91107 /* RoundedButton.swift */; }; + 1164C8F01BC982FF00B91107 /* UIImageExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1164C8EF1BC982FF00B91107 /* UIImageExtension.swift */; }; + 1164C8F31BC9880000B91107 /* LoginLogoController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1164C8F21BC9880000B91107 /* LoginLogoController.swift */; }; + 1164C8F61BC98F8300B91107 /* UIViewControllerExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1164C8F51BC98F8300B91107 /* UIViewControllerExtension.swift */; }; + 116513191C2C6C980066AF06 /* FriendCardController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 116513181C2C6C980066AF06 /* FriendCardController.swift */; }; + 116513221C2C74940066AF06 /* StaticTableChatButtonsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 116513211C2C74940066AF06 /* StaticTableChatButtonsCell.swift */; }; + 116513241C2C749E0066AF06 /* StaticTableChatButtonsCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 116513231C2C749E0066AF06 /* StaticTableChatButtonsCellModel.swift */; }; + 116513261C2D636A0066AF06 /* NotificationWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 116513251C2D636A0066AF06 /* NotificationWindow.swift */; }; + 116634A01C6E8D0F0072C980 /* ChatIncomingCallCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1166349F1C6E8D0F0072C980 /* ChatIncomingCallCell.swift */; }; + 116634A11C6E8D0F0072C980 /* ChatIncomingCallCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1166349F1C6E8D0F0072C980 /* ChatIncomingCallCell.swift */; }; + 116634A91C6E8D1A0072C980 /* ChatIncomingCallCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 116634A81C6E8D1A0072C980 /* ChatIncomingCallCellModel.swift */; }; + 116634AA1C6E8D1A0072C980 /* ChatIncomingCallCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 116634A81C6E8D1A0072C980 /* ChatIncomingCallCellModel.swift */; }; + 116634AC1C6F407D0072C980 /* ChatOutgoingCallCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 116634AB1C6F407D0072C980 /* ChatOutgoingCallCell.swift */; }; + 116634AD1C6F407D0072C980 /* ChatOutgoingCallCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 116634AB1C6F407D0072C980 /* ChatOutgoingCallCell.swift */; }; + 116634AF1C6F40820072C980 /* ChatOutgoingCallCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 116634AE1C6F40820072C980 /* ChatOutgoingCallCellModel.swift */; }; + 116634B01C6F40820072C980 /* ChatOutgoingCallCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 116634AE1C6F40820072C980 /* ChatOutgoingCallCellModel.swift */; }; + 116634B21C7087A80072C980 /* UIApplicationExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 116634B11C7087A80072C980 /* UIApplicationExtension.swift */; }; + 116634B31C7087A80072C980 /* UIApplicationExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 116634B11C7087A80072C980 /* UIApplicationExtension.swift */; }; + 116634CF1C70E46C0072C980 /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 116634CE1C70E46C0072C980 /* Launch Screen.storyboard */; }; + 116634D91C70F1260072C980 /* CopyLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 116634D81C70F1260072C980 /* CopyLabel.swift */; }; + 116634DA1C70F1260072C980 /* CopyLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 116634D81C70F1260072C980 /* CopyLabel.swift */; }; + 116634E01C7B8D770072C980 /* StaticTableInfoCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 116634DF1C7B8D770072C980 /* StaticTableInfoCell.swift */; }; + 116634E11C7B8D770072C980 /* StaticTableInfoCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 116634DF1C7B8D770072C980 /* StaticTableInfoCell.swift */; }; + 116634E91C7B8D7C0072C980 /* StaticTableInfoCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 116634E81C7B8D7C0072C980 /* StaticTableInfoCellModel.swift */; }; + 116634EA1C7B8D7C0072C980 /* StaticTableInfoCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 116634E81C7B8D7C0072C980 /* StaticTableInfoCellModel.swift */; }; + 116634EC1C7B90F20072C980 /* FriendRequestController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 116634EB1C7B90F20072C980 /* FriendRequestController.swift */; }; + 116634ED1C7B90F20072C980 /* FriendRequestController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 116634EB1C7B90F20072C980 /* FriendRequestController.swift */; }; + 116634EF1C7B94530072C980 /* StaticTableMultiChoiceButtonCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 116634EE1C7B94530072C980 /* StaticTableMultiChoiceButtonCell.swift */; }; + 116634F01C7B94530072C980 /* StaticTableMultiChoiceButtonCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 116634EE1C7B94530072C980 /* StaticTableMultiChoiceButtonCell.swift */; }; + 116634F21C7B945A0072C980 /* StaticTableMultiChoiceButtonCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 116634F11C7B945A0072C980 /* StaticTableMultiChoiceButtonCellModel.swift */; }; + 116634F31C7B945A0072C980 /* StaticTableMultiChoiceButtonCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 116634F11C7B945A0072C980 /* StaticTableMultiChoiceButtonCellModel.swift */; }; + 11687F2E1DC64F0D0029B93F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11FA0ED31BC5842800F3DA5B /* AppDelegate.swift */; }; + 116DCE321CAAF47100B693EC /* TopCoordinatorProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 116DCE311CAAF47100B693EC /* TopCoordinatorProtocol.swift */; }; + 116DCE331CAAF47100B693EC /* TopCoordinatorProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 116DCE311CAAF47100B693EC /* TopCoordinatorProtocol.swift */; }; + 116DCE3B1CAAF85300B693EC /* NSURLExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 116DCE3A1CAAF85300B693EC /* NSURLExtension.swift */; }; + 116DCE3C1CAAF85300B693EC /* NSURLExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 116DCE3A1CAAF85300B693EC /* NSURLExtension.swift */; }; + 1173F06E1BC5D9BA00B88B7B /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1173F06D1BC5D9BA00B88B7B /* Theme.swift */; }; + 1173F0701BC5D9CA00B88B7B /* ThemeTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1173F06F1BC5D9CA00B88B7B /* ThemeTest.swift */; }; + 1173F0721BC5D9DA00B88B7B /* default-theme.yaml in Resources */ = {isa = PBXBuildFile; fileRef = 1173F0711BC5D9DA00B88B7B /* default-theme.yaml */; }; + 11770D6A1CBC120C00D34D6E /* FriendSelectController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11770D691CBC120C00D34D6E /* FriendSelectController.swift */; }; + 11770D6B1CBC120C00D34D6E /* FriendSelectController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11770D691CBC120C00D34D6E /* FriendSelectController.swift */; }; + 11770D771CBC1C7A00D34D6E /* UIAlertControllerExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11770D761CBC1C7A00D34D6E /* UIAlertControllerExtension.swift */; }; + 11770D781CBC1C7A00D34D6E /* UIAlertControllerExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11770D761CBC1C7A00D34D6E /* UIAlertControllerExtension.swift */; }; + 11771E2C1CA5C3F200EC259E /* AutomationCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11771E2B1CA5C3F200EC259E /* AutomationCoordinator.swift */; }; + 11771E2D1CA5C3F200EC259E /* AutomationCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11771E2B1CA5C3F200EC259E /* AutomationCoordinator.swift */; }; + 11771E361CA5C6E900EC259E /* Reach.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11771E351CA5C6E900EC259E /* Reach.swift */; }; + 11771E371CA5C6E900EC259E /* Reach.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11771E351CA5C6E900EC259E /* Reach.swift */; }; + 1180FD9E1C38497A005F3EA1 /* NSDateFormatterExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1180FD9D1C38497A005F3EA1 /* NSDateFormatterExtension.swift */; }; + 1180FDA01C384E29005F3EA1 /* CallCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1180FD9F1C384E29005F3EA1 /* CallCoordinator.swift */; }; + 1183BCAC1CA1B398000CD310 /* ChatIncomingFileCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1183BCAB1CA1B398000CD310 /* ChatIncomingFileCell.swift */; }; + 1183BCAD1CA1B398000CD310 /* ChatIncomingFileCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1183BCAB1CA1B398000CD310 /* ChatIncomingFileCell.swift */; }; + 1183BCB51CA1B3AE000CD310 /* ChatIncomingFileCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1183BCB41CA1B3AE000CD310 /* ChatIncomingFileCellModel.swift */; }; + 1183BCB61CA1B3AE000CD310 /* ChatIncomingFileCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1183BCB41CA1B3AE000CD310 /* ChatIncomingFileCellModel.swift */; }; + 1183BCC01CA1DB05000CD310 /* ProgressCircleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1183BCBF1CA1DB05000CD310 /* ProgressCircleView.swift */; }; + 1183BCC71CA1DB09000CD310 /* ProgressCircleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1183BCBF1CA1DB05000CD310 /* ProgressCircleView.swift */; }; + 1183BCD71CA1FC5B000CD310 /* ChatProgressProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1183BCD61CA1FC5B000CD310 /* ChatProgressProtocol.swift */; }; + 1183BCD81CA1FC5B000CD310 /* ChatProgressProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1183BCD61CA1FC5B000CD310 /* ChatProgressProtocol.swift */; }; + 1183BCDD1CA1FD55000CD310 /* ChatProgressBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1183BCDC1CA1FD55000CD310 /* ChatProgressBridge.swift */; }; + 1183BCDE1CA1FD55000CD310 /* ChatProgressBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1183BCDC1CA1FD55000CD310 /* ChatProgressBridge.swift */; }; + 1193AB361C1DEF2E006AA9E5 /* TextEditController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1193AB351C1DEF2E006AA9E5 /* TextEditController.swift */; }; + 1193AB421C1E2075006AA9E5 /* QRViewerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1193AB411C1E2075006AA9E5 /* QRViewerController.swift */; }; + 1193AB481C1F4164006AA9E5 /* FriendListController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1193AB471C1F4164006AA9E5 /* FriendListController.swift */; }; + 1193AB661C1F5694006AA9E5 /* BaseCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1193AB651C1F5694006AA9E5 /* BaseCell.swift */; }; + 1193AB681C1F569A006AA9E5 /* BaseCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1193AB671C1F569A006AA9E5 /* BaseCellModel.swift */; }; + 1193AB6A1C1F5C28006AA9E5 /* FriendListCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1193AB691C1F5C28006AA9E5 /* FriendListCell.swift */; }; + 1193AB6C1C1F5C31006AA9E5 /* FriendListCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1193AB6B1C1F5C31006AA9E5 /* FriendListCellModel.swift */; }; + 119AD1BE1BDED261000C5CB8 /* TextViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 119AD1BD1BDED261000C5CB8 /* TextViewController.swift */; }; + 119AD1CA1BDED6E9000C5CB8 /* ErrorHandling.swift in Sources */ = {isa = PBXBuildFile; fileRef = 119AD1C91BDED6E9000C5CB8 /* ErrorHandling.swift */; }; + 119AD1CC1BDEDD9C000C5CB8 /* UIColorExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 119AD1CB1BDEDD9C000C5CB8 /* UIColorExtension.swift */; }; + 11A21EFB1C45BDB100E80A89 /* ChatPrivateController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11A21EFA1C45BDB100E80A89 /* ChatPrivateController.swift */; }; + 11A21EFD1C45BDF200E80A89 /* ChatInputView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11A21EFC1C45BDF200E80A89 /* ChatInputView.swift */; }; + 11AEBE711DA1876F00D04B59 /* FAQController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11AEBE701DA1876F00D04B59 /* FAQController.swift */; }; + 11AEBE721DA1876F00D04B59 /* FAQController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11AEBE701DA1876F00D04B59 /* FAQController.swift */; }; + 11B252FA1C4A614D0068F47C /* ChatIncomingTextCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B252F91C4A614D0068F47C /* ChatIncomingTextCell.swift */; }; + 11B252FE1C4A615E0068F47C /* ChatOutgoingTextCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B252FD1C4A615E0068F47C /* ChatOutgoingTextCell.swift */; }; + 11B253021C4A61D00068F47C /* ChatMovableDateCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B253011C4A61D00068F47C /* ChatMovableDateCell.swift */; }; + 11B253041C4A61D50068F47C /* ChatMovableDateCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B253031C4A61D50068F47C /* ChatMovableDateCellModel.swift */; }; + 11B253141C4A79A50068F47C /* BubbleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B253131C4A79A50068F47C /* BubbleView.swift */; }; + 11B2534F1C4AD2550068F47C /* AudioPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B2534E1C4AD2550068F47C /* AudioPlayer.swift */; }; + 11B253501C4AD9CF0068F47C /* isotoxin_Calltone.aac in Resources */ = {isa = PBXBuildFile; fileRef = 11B253491C4AD2200068F47C /* isotoxin_Calltone.aac */; }; + 11B253511C4AD9CF0068F47C /* isotoxin_Hangup.aac in Resources */ = {isa = PBXBuildFile; fileRef = 11B2534A1C4AD23A0068F47C /* isotoxin_Hangup.aac */; }; + 11B253521C4AD9CF0068F47C /* isotoxin_NewMessage.aac in Resources */ = {isa = PBXBuildFile; fileRef = 11B2534B1C4AD23A0068F47C /* isotoxin_NewMessage.aac */; }; + 11B253531C4AD9CF0068F47C /* isotoxin_Ringtone.aac in Resources */ = {isa = PBXBuildFile; fileRef = 11B2534C1C4AD23A0068F47C /* isotoxin_Ringtone.aac */; }; + 11B253541C4AD9CF0068F47C /* isotoxin_RingtoneWhileCall.aac in Resources */ = {isa = PBXBuildFile; fileRef = 11B2534D1C4AD23A0068F47C /* isotoxin_RingtoneWhileCall.aac */; }; + 11B253561C4AEA400068F47C /* ChatPrivateTitleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B253551C4AEA400068F47C /* ChatPrivateTitleView.swift */; }; + 11B2535D1C4BACDB0068F47C /* TabBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B2535C1C4BACDB0068F47C /* TabBarController.swift */; }; + 11B253661C4BAD3C0068F47C /* TabBarAbstractItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B253651C4BAD3C0068F47C /* TabBarAbstractItem.swift */; }; + 11B2536A1C4BAD560068F47C /* TabBarBadgeItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B253691C4BAD560068F47C /* TabBarBadgeItem.swift */; }; + 11B2536D1C4BAD5D0068F47C /* TabBarProfileItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B2536C1C4BAD5D0068F47C /* TabBarProfileItem.swift */; }; + 11B253A41C4EA8040068F47C /* InterfaceIdiom.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B253A31C4EA8040068F47C /* InterfaceIdiom.swift */; }; + 11B253A51C4EA8040068F47C /* InterfaceIdiom.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B253A31C4EA8040068F47C /* InterfaceIdiom.swift */; }; + 11B253AE1C4EC47D0068F47C /* IncompressibleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B253AD1C4EC47D0068F47C /* IncompressibleView.swift */; }; + 11B253AF1C4EC47D0068F47C /* IncompressibleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B253AD1C4EC47D0068F47C /* IncompressibleView.swift */; }; + 11B253B71C503FA10068F47C /* NSTimerExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B253B61C503FA10068F47C /* NSTimerExtension.swift */; }; + 11B253B81C503FA10068F47C /* NSTimerExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B253B61C503FA10068F47C /* NSTimerExtension.swift */; }; + 11B253FB1C52C0A10068F47C /* StaticTableSwitchCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B253FA1C52C0A10068F47C /* StaticTableSwitchCell.swift */; }; + 11B253FC1C52C0A10068F47C /* StaticTableSwitchCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B253FA1C52C0A10068F47C /* StaticTableSwitchCell.swift */; }; + 11B253FE1C52C0AA0068F47C /* StaticTableSwitchCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B253FD1C52C0AA0068F47C /* StaticTableSwitchCellModel.swift */; }; + 11B253FF1C52C0AA0068F47C /* StaticTableSwitchCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B253FD1C52C0AA0068F47C /* StaticTableSwitchCellModel.swift */; }; + 11B3F8701CE095D2001927D8 /* ChatEditable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1136605B1CDE5D5E0092C27A /* ChatEditable.swift */; }; + 11B9C6831BD598FC0083C2A5 /* OCTManagerConfigurationExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B9C6821BD598FC0083C2A5 /* OCTManagerConfigurationExtension.swift */; }; + 11B9C6971BD80B080083C2A5 /* FullscreenPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B9C6961BD80B080083C2A5 /* FullscreenPicker.swift */; }; + 11C33AC41DC961DC008DBC49 /* LoginChoiceViewSnapshotTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11C33AC31DC961DC008DBC49 /* LoginChoiceViewSnapshotTest.swift */; }; + 11CFCD0B1C2745230046BD94 /* UserStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11CFCD0A1C2745230046BD94 /* UserStatus.swift */; }; + 11CFCD0D1C27488E0046BD94 /* ImageViewWithStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11CFCD0C1C27488E0046BD94 /* ImageViewWithStatus.swift */; }; + 11CFCD0F1C27499D0046BD94 /* UserStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11CFCD0E1C27499D0046BD94 /* UserStatusView.swift */; }; + 11CFCD111C2A02350046BD94 /* StaticBackgroundView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11CFCD101C2A02350046BD94 /* StaticBackgroundView.swift */; }; + 11D17CDD1DD11E58006B2910 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1164764419794D3300DB20B8 /* Images.xcassets */; }; + 11D17CE91DD11F10006B2910 /* dummy-photo.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 11D17CE81DD11F10006B2910 /* dummy-photo.jpg */; }; + 11D17CEA1DD11F10006B2910 /* dummy-photo.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 11D17CE81DD11F10006B2910 /* dummy-photo.jpg */; }; + 11DDEAFD1D5FD9FE0000E2BE /* LaunchPlaceholderBoard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 11DDEAFC1D5FD9FE0000E2BE /* LaunchPlaceholderBoard.storyboard */; }; + 11E6406D1C2D6C3500D24C6D /* ViewPassingGestures.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11E6406C1C2D6C3500D24C6D /* ViewPassingGestures.swift */; }; + 11E640761C2DBAE200D24C6D /* AddFriendController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11E640751C2DBAE200D24C6D /* AddFriendController.swift */; }; + 11E640781C2DC15400D24C6D /* HelperFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11E640771C2DC15400D24C6D /* HelperFunctions.swift */; }; + 11F08D131DE0610B00F80F5F /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 11F08D171DE0610B00F80F5F /* InfoPlist.strings */; }; + 11F08D141DE0610B00F80F5F /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 11F08D171DE0610B00F80F5F /* InfoPlist.strings */; }; + 11F08D151DE0610B00F80F5F /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 11F08D171DE0610B00F80F5F /* InfoPlist.strings */; }; + 11F276AE1D3EBEF700C613AA /* ChatBaseTextCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11F276AD1D3EBEF700C613AA /* ChatBaseTextCell.swift */; }; + 11F276AF1D3EBEF700C613AA /* ChatBaseTextCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11F276AD1D3EBEF700C613AA /* ChatBaseTextCell.swift */; }; + 11F276BB1D3EBF3000C613AA /* ChatBaseTextCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11F276BA1D3EBF3000C613AA /* ChatBaseTextCellModel.swift */; }; + 11F276BC1D3EBF3000C613AA /* ChatBaseTextCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11F276BA1D3EBF3000C613AA /* ChatBaseTextCellModel.swift */; }; + 11F83BDB1CAFB2A20074FE11 /* SwiftSupport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11F83BDA1CAFB2A20074FE11 /* SwiftSupport.swift */; }; + 11FA0ED41BC5842800F3DA5B /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11FA0ED31BC5842800F3DA5B /* AppDelegate.swift */; }; + 11FA0EDA1BC584D900F3DA5B /* AppCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11FA0ED91BC584D900F3DA5B /* AppCoordinator.swift */; }; + 11FA0EDE1BC58DCC00F3DA5B /* CoordinatorProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11FA0EDD1BC58DCC00F3DA5B /* CoordinatorProtocol.swift */; }; + 11FA0EE11BC591FC00F3DA5B /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11FA0EE01BC591FC00F3DA5B /* Logger.swift */; }; + 11FA0EE71BC59B1400F3DA5B /* ActiveSessionCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11FA0EE61BC59B1400F3DA5B /* ActiveSessionCoordinator.swift */; }; + 11FA0EE91BC5A66D00F3DA5B /* LoginCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11FA0EE81BC5A66D00F3DA5B /* LoginCoordinator.swift */; }; + 11FA0EEB1BC5A68600F3DA5B /* FriendsTabCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11FA0EEA1BC5A68600F3DA5B /* FriendsTabCoordinator.swift */; }; + 11FA0EED1BC5A69000F3DA5B /* ProfileTabCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11FA0EEC1BC5A69000F3DA5B /* ProfileTabCoordinator.swift */; }; + 11FA0EF11BC5A6A500F3DA5B /* SettingsTabCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11FA0EF01BC5A6A500F3DA5B /* SettingsTabCoordinator.swift */; }; + 11FA0EF31BC5A6AF00F3DA5B /* ChatsTabCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11FA0EF21BC5A6AF00F3DA5B /* ChatsTabCoordinator.swift */; }; + 11FC10571D32E54A00CE863E /* Results.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11FC10561D32E54A00CE863E /* Results.swift */; }; + 11FC10581D32E54A00CE863E /* Results.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11FC10561D32E54A00CE863E /* Results.swift */; }; + 11FC105A1D32EED000CE863E /* ResultsChange.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11FC10591D32EED000CE863E /* ResultsChange.swift */; }; + 11FC105B1D32EED000CE863E /* ResultsChange.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11FC10591D32EED000CE863E /* ResultsChange.swift */; }; + 11FC105D1D32F29700CE863E /* OCTSubmanagerObjectsExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11FC105C1D32F29700CE863E /* OCTSubmanagerObjectsExtension.swift */; }; + 11FC105E1D32F29700CE863E /* OCTSubmanagerObjectsExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11FC105C1D32F29700CE863E /* OCTSubmanagerObjectsExtension.swift */; }; + 4E3D0F9527C9751300D5A068 /* LinearProgressBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E3D0F9427C9751300D5A068 /* LinearProgressBar.swift */; }; + 4E4B267F27C0DCAE00E07A66 /* Call.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E4B267E27C0DCAE00E07A66 /* Call.swift */; }; + 4E4B268527C0DCB500E07A66 /* CallManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E4B268427C0DCB500E07A66 /* CallManager.swift */; }; + 4E4B268B27C0DCBC00E07A66 /* ProviderDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E4B268A27C0DCBC00E07A66 /* ProviderDelegate.swift */; }; + 4E4EEA1927DCEC67008B0E77 /* LocationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E4EEA1827DCEC67008B0E77 /* LocationManager.swift */; }; + 4E4EEA1F27DCECD3008B0E77 /* Bus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E4EEA1E27DCECD3008B0E77 /* Bus.swift */; }; + 8B8E9C45924FB18EB2C8044E /* libPods-ScreenshotsUITests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 6A1B3D525D11BDD4F3E9B831 /* libPods-ScreenshotsUITests.a */; }; + 96166DAAD67996D5A6819984 /* libPods-AntidoteTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 72586F4D098584EF43024224 /* libPods-AntidoteTests.a */; }; + 9C04BB6D1C17389200F58488 /* StaticTableBaseCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C04BB6C1C17389200F58488 /* StaticTableBaseCell.swift */; }; + 9C07151D1BCD2E5B003A27B5 /* PortraitNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C07151C1BCD2E5B003A27B5 /* PortraitNavigationController.swift */; }; + 9C07151F1BCD501D003A27B5 /* LoginFormController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C07151E1BCD501D003A27B5 /* LoginFormController.swift */; }; + 9C19367E1D79CF7E005EA0B2 /* EnterPinController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C19367D1D79CF7E005EA0B2 /* EnterPinController.swift */; }; + 9C19367F1D79CF7E005EA0B2 /* EnterPinController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C19367D1D79CF7E005EA0B2 /* EnterPinController.swift */; }; + 9C1FEB291D8C10EB008C2ADE /* ProfileSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C1FEB281D8C10EB008C2ADE /* ProfileSettings.swift */; }; + 9C1FEB2A1D8C10EB008C2ADE /* ProfileSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C1FEB281D8C10EB008C2ADE /* ProfileSettings.swift */; }; + 9C2EF3711C4D4D5C006E7AB1 /* NotificationCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C2EF3701C4D4D5C006E7AB1 /* NotificationCoordinator.swift */; }; + 9C2EF37A1C4E2DDE006E7AB1 /* ChatListTableManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C2EF3791C4E2DDE006E7AB1 /* ChatListTableManager.swift */; }; + 9C3271871D79C19C00347490 /* PinAuthorizationCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C3271861D79C19C00347490 /* PinAuthorizationCoordinator.swift */; }; + 9C3271881D79C19C00347490 /* PinAuthorizationCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C3271861D79C19C00347490 /* PinAuthorizationCoordinator.swift */; }; + 9C7475BE1BC698110098B1A4 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 9C7475C01BC698110098B1A4 /* Localizable.strings */; }; + 9C7475C51BC698510098B1A4 /* StringExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C7475C41BC698510098B1A4 /* StringExtension.swift */; }; + 9C9A07011BE793BA0003D6C7 /* ProfileMainController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C9A07001BE793BA0003D6C7 /* ProfileMainController.swift */; }; + 9CB1F9511D58CA4000105858 /* RunningCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CB1F9501D58CA4000105858 /* RunningCoordinator.swift */; }; + 9CB1F9521D58CA4000105858 /* RunningCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CB1F9501D58CA4000105858 /* RunningCoordinator.swift */; }; + 9CBBC7C11BDFC62700099A5E /* LoginCreateAccountController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CBBC7C01BDFC62700099A5E /* LoginCreateAccountController.swift */; }; + 9CBBC7CD1BDFC6C600099A5E /* ExtendedTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CBBC7CC1BDFC6C600099A5E /* ExtendedTextField.swift */; }; + 9CDC091B1C34081900DC0D63 /* FriendListDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CDC091A1C34081900DC0D63 /* FriendListDataSource.swift */; }; + 9CDC09251C34083100DC0D63 /* FriendListDataSourceTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CDC09241C34083100DC0D63 /* FriendListDataSourceTest.swift */; }; + 9CDC092C1C34102F00DC0D63 /* ExceptionHandling.m in Sources */ = {isa = PBXBuildFile; fileRef = 9CDC092B1C34102F00DC0D63 /* ExceptionHandling.m */; }; + 9CDC092D1C34102F00DC0D63 /* ExceptionHandling.m in Sources */ = {isa = PBXBuildFile; fileRef = 9CDC092B1C34102F00DC0D63 /* ExceptionHandling.m */; }; + 9CDDB2061BD5376200B65D79 /* ProfileManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CDDB2051BD5376200B65D79 /* ProfileManager.swift */; }; + 9CDE31E61E489B2700333E0D /* ChatInputViewManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CDE31E51E489B2700333E0D /* ChatInputViewManager.swift */; }; + 9CDE31E71E489B2700333E0D /* ChatInputViewManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CDE31E51E489B2700333E0D /* ChatInputViewManager.swift */; }; + 9CDE31E81E489B2700333E0D /* ChatInputViewManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CDE31E51E489B2700333E0D /* ChatInputViewManager.swift */; }; + 9CE0BDE61C45229500DCE357 /* ChatListController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CE0BDE51C45229500DCE357 /* ChatListController.swift */; }; + 9CE0BDF01C4522BF00DCE357 /* ChatListCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CE0BDEF1C4522BF00DCE357 /* ChatListCell.swift */; }; + 9CE0BDF31C4522C800DCE357 /* ChatListCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CE0BDF21C4522C800DCE357 /* ChatListCellModel.swift */; }; + 9CEA6A1F1D957EFC0045F000 /* antidote-acknowledgements.html in Resources */ = {isa = PBXBuildFile; fileRef = 9CEA6A1E1D957EFC0045F000 /* antidote-acknowledgements.html */; }; + 9CEA6A201D957EFC0045F000 /* antidote-acknowledgements.html in Resources */ = {isa = PBXBuildFile; fileRef = 9CEA6A1E1D957EFC0045F000 /* antidote-acknowledgements.html */; }; + 9CEE6AA21C4E679100A1ECB5 /* PrimaryIpadController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CEE6AA11C4E679100A1ECB5 /* PrimaryIpadController.swift */; }; + 9CEE6AB81C4E8FDC00A1ECB5 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11FA0ED31BC5842800F3DA5B /* AppDelegate.swift */; }; + 9CEE6AB91C4E8FDC00A1ECB5 /* BaseCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1193AB651C1F5694006AA9E5 /* BaseCell.swift */; }; + 9CEE6ABA1C4E8FDC00A1ECB5 /* BaseCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1193AB671C1F569A006AA9E5 /* BaseCellModel.swift */; }; + 9CEE6ABB1C4E8FDC00A1ECB5 /* ChatIncomingTextCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B252F91C4A614D0068F47C /* ChatIncomingTextCell.swift */; }; + 9CEE6ABD1C4E8FDC00A1ECB5 /* ChatListCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CE0BDEF1C4522BF00DCE357 /* ChatListCell.swift */; }; + 9CEE6ABE1C4E8FDC00A1ECB5 /* ChatListCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CE0BDF21C4522C800DCE357 /* ChatListCellModel.swift */; }; + 9CEE6ABF1C4E8FDC00A1ECB5 /* ChatMovableDateCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B253011C4A61D00068F47C /* ChatMovableDateCell.swift */; }; + 9CEE6AC01C4E8FDC00A1ECB5 /* ChatMovableDateCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B253031C4A61D50068F47C /* ChatMovableDateCellModel.swift */; }; + 9CEE6AC11C4E8FDC00A1ECB5 /* ChatOutgoingTextCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B252FD1C4A615E0068F47C /* ChatOutgoingTextCell.swift */; }; + 9CEE6AC31C4E8FDC00A1ECB5 /* FriendListCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1193AB691C1F5C28006AA9E5 /* FriendListCell.swift */; }; + 9CEE6AC41C4E8FDC00A1ECB5 /* FriendListCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1193AB6B1C1F5C31006AA9E5 /* FriendListCellModel.swift */; }; + 9CEE6AC51C4E8FDC00A1ECB5 /* StaticTableAvatarCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1156A4861C10D122005AC8C6 /* StaticTableAvatarCell.swift */; }; + 9CEE6AC61C4E8FDC00A1ECB5 /* StaticTableAvatarCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1156A4841C10D119005AC8C6 /* StaticTableAvatarCellModel.swift */; }; + 9CEE6AC71C4E8FDC00A1ECB5 /* StaticTableBaseCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C04BB6C1C17389200F58488 /* StaticTableBaseCell.swift */; }; + 9CEE6AC81C4E8FDC00A1ECB5 /* StaticTableBaseCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1156A4781C0E478D005AC8C6 /* StaticTableBaseCellModel.swift */; }; + 9CEE6AC91C4E8FDC00A1ECB5 /* StaticTableButtonCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1156A4801C0FA0A4005AC8C6 /* StaticTableButtonCell.swift */; }; + 9CEE6ACA1C4E8FDC00A1ECB5 /* StaticTableButtonCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1156A47A1C0F6178005AC8C6 /* StaticTableButtonCellModel.swift */; }; + 9CEE6ACB1C4E8FDC00A1ECB5 /* StaticTableChatButtonsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 116513211C2C74940066AF06 /* StaticTableChatButtonsCell.swift */; }; + 9CEE6ACC1C4E8FDC00A1ECB5 /* StaticTableChatButtonsCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 116513231C2C749E0066AF06 /* StaticTableChatButtonsCellModel.swift */; }; + 9CEE6ACD1C4E8FDC00A1ECB5 /* StaticTableDefaultCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 115DFB891C177F5C00F18DB5 /* StaticTableDefaultCell.swift */; }; + 9CEE6ACE1C4E8FDC00A1ECB5 /* StaticTableDefaultCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 115DFB951C177F6500F18DB5 /* StaticTableDefaultCellModel.swift */; }; + 9CEE6ACF1C4E8FDC00A1ECB5 /* StaticTableSelectableCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1156A47C1C0F632C005AC8C6 /* StaticTableSelectableCellModel.swift */; }; + 9CEE6AD01C4E8FDC00A1ECB5 /* AudioPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B2534E1C4AD2550068F47C /* AudioPlayer.swift */; }; + 9CEE6AD11C4E8FDC00A1ECB5 /* AvatarManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1156A4881C15FB2B005AC8C6 /* AvatarManager.swift */; }; + 9CEE6AD21C4E8FDC00A1ECB5 /* ChatListTableManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C2EF3791C4E2DDE006E7AB1 /* ChatListTableManager.swift */; }; + 9CEE6AD31C4E8FDC00A1ECB5 /* FriendListDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CDC091A1C34081900DC0D63 /* FriendListDataSource.swift */; }; + 9CEE6AD61C4E8FDC00A1ECB5 /* ProfileManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CDDB2051BD5376200B65D79 /* ProfileManager.swift */; }; + 9CEE6AD71C4E8FDC00A1ECB5 /* TabBarAbstractItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B253651C4BAD3C0068F47C /* TabBarAbstractItem.swift */; }; + 9CEE6AD81C4E8FDC00A1ECB5 /* TabBarBadgeItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B253691C4BAD560068F47C /* TabBarBadgeItem.swift */; }; + 9CEE6AD91C4E8FDC00A1ECB5 /* TabBarProfileItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B2536C1C4BAD5D0068F47C /* TabBarProfileItem.swift */; }; + 9CEE6ADA1C4E8FDC00A1ECB5 /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1173F06D1BC5D9BA00B88B7B /* Theme.swift */; }; + 9CEE6ADB1C4E8FDC00A1ECB5 /* UserDefaultsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1164C8D71BC922EB00B91107 /* UserDefaultsManager.swift */; }; + 9CEE6ADC1C4E8FDC00A1ECB5 /* KeyboardNotificationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 112422651BDD2032004D7926 /* KeyboardNotificationController.swift */; }; + 9CEE6ADD1C4E8FDC00A1ECB5 /* PortraitNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C07151C1BCD2E5B003A27B5 /* PortraitNavigationController.swift */; }; + 9CEE6ADE1C4E8FDC00A1ECB5 /* LoginBaseController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1164C8E61BC929C500B91107 /* LoginBaseController.swift */; }; + 9CEE6ADF1C4E8FDC00A1ECB5 /* LoginChoiceController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1164C8E81BC929F700B91107 /* LoginChoiceController.swift */; }; + 9CEE6AE01C4E8FDC00A1ECB5 /* LoginCreateAccountController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CBBC7C01BDFC62700099A5E /* LoginCreateAccountController.swift */; }; + 9CEE6AE11C4E8FDC00A1ECB5 /* LoginFormController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C07151E1BCD501D003A27B5 /* LoginFormController.swift */; }; + 9CEE6AE21C4E8FDC00A1ECB5 /* LoginLogoController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1164C8F21BC9880000B91107 /* LoginLogoController.swift */; }; + 9CEE6AE51C4E8FDC00A1ECB5 /* AddFriendController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11E640751C2DBAE200D24C6D /* AddFriendController.swift */; }; + 9CEE6AE71C4E8FDC00A1ECB5 /* ChatListController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CE0BDE51C45229500DCE357 /* ChatListController.swift */; }; + 9CEE6AE81C4E8FDC00A1ECB5 /* ChatPrivateController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11A21EFA1C45BDB100E80A89 /* ChatPrivateController.swift */; }; + 9CEE6AEA1C4E8FDC00A1ECB5 /* FriendCardController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 116513181C2C6C980066AF06 /* FriendCardController.swift */; }; + 9CEE6AEB1C4E8FDC00A1ECB5 /* FriendListController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1193AB471C1F4164006AA9E5 /* FriendListController.swift */; }; + 9CEE6AEC1C4E8FDC00A1ECB5 /* PrimaryIpadController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CEE6AA11C4E679100A1ECB5 /* PrimaryIpadController.swift */; }; + 9CEE6AED1C4E8FDC00A1ECB5 /* ProfileMainController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C9A07001BE793BA0003D6C7 /* ProfileMainController.swift */; }; + 9CEE6AEE1C4E8FDC00A1ECB5 /* QRScannerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 113D56551C2F459E00B3D3E8 /* QRScannerController.swift */; }; + 9CEE6AEF1C4E8FDC00A1ECB5 /* QRViewerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1193AB411C1E2075006AA9E5 /* QRViewerController.swift */; }; + 9CEE6AF11C4E8FDC00A1ECB5 /* StaticTableController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 110E425B1C00DC5E001A3CA2 /* StaticTableController.swift */; }; + 9CEE6AF21C4E8FDC00A1ECB5 /* TabBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B2535C1C4BACDB0068F47C /* TabBarController.swift */; }; + 9CEE6AF31C4E8FDC00A1ECB5 /* TextEditController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1193AB351C1DEF2E006AA9E5 /* TextEditController.swift */; }; + 9CEE6AF41C4E8FDC00A1ECB5 /* TextViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 119AD1BD1BDED261000C5CB8 /* TextViewController.swift */; }; + 9CEE6AF61C4E8FDC00A1ECB5 /* CoordinatorProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11FA0EDD1BC58DCC00F3DA5B /* CoordinatorProtocol.swift */; }; + 9CEE6AF71C4E8FDC00A1ECB5 /* AppCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11FA0ED91BC584D900F3DA5B /* AppCoordinator.swift */; }; + 9CEE6AF81C4E8FDC00A1ECB5 /* LoginCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11FA0EE81BC5A66D00F3DA5B /* LoginCoordinator.swift */; }; + 9CEE6AF91C4E8FDC00A1ECB5 /* ActiveSessionCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11FA0EE61BC59B1400F3DA5B /* ActiveSessionCoordinator.swift */; }; + 9CEE6AFA1C4E8FDC00A1ECB5 /* CallCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1180FD9F1C384E29005F3EA1 /* CallCoordinator.swift */; }; + 9CEE6AFC1C4E8FDC00A1ECB5 /* ChatsTabCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11FA0EF21BC5A6AF00F3DA5B /* ChatsTabCoordinator.swift */; }; + 9CEE6AFD1C4E8FDC00A1ECB5 /* FriendsTabCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11FA0EEA1BC5A68600F3DA5B /* FriendsTabCoordinator.swift */; }; + 9CEE6AFE1C4E8FDC00A1ECB5 /* NotificationCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C2EF3701C4D4D5C006E7AB1 /* NotificationCoordinator.swift */; }; + 9CEE6AFF1C4E8FDC00A1ECB5 /* ProfileTabCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11FA0EEC1BC5A69000F3DA5B /* ProfileTabCoordinator.swift */; }; + 9CEE6B001C4E8FDC00A1ECB5 /* ActiveSessionNavigationCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 110E49DF1BF925FD00D1FE6F /* ActiveSessionNavigationCoordinator.swift */; }; + 9CEE6B011C4E8FDC00A1ECB5 /* SettingsTabCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11FA0EF01BC5A6A500F3DA5B /* SettingsTabCoordinator.swift */; }; + 9CEE6B021C4E8FDC00A1ECB5 /* UserStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11CFCD0A1C2745230046BD94 /* UserStatus.swift */; }; + 9CEE6B031C4E8FDC00A1ECB5 /* UIImageExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1164C8EF1BC982FF00B91107 /* UIImageExtension.swift */; }; + 9CEE6B041C4E8FDC00A1ECB5 /* NSDateFormatterExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1180FD9D1C38497A005F3EA1 /* NSDateFormatterExtension.swift */; }; + 9CEE6B051C4E8FDC00A1ECB5 /* OCTManagerConfigurationExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B9C6821BD598FC0083C2A5 /* OCTManagerConfigurationExtension.swift */; }; + 9CEE6B071C4E8FDC00A1ECB5 /* StringExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C7475C41BC698510098B1A4 /* StringExtension.swift */; }; + 9CEE6B091C4E8FDC00A1ECB5 /* UIColorExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 119AD1CB1BDEDD9C000C5CB8 /* UIColorExtension.swift */; }; + 9CEE6B0A1C4E8FDC00A1ECB5 /* UIViewControllerExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1164C8F51BC98F8300B91107 /* UIViewControllerExtension.swift */; }; + 9CEE6B0B1C4E8FDC00A1ECB5 /* ErrorHandling.swift in Sources */ = {isa = PBXBuildFile; fileRef = 119AD1C91BDED6E9000C5CB8 /* ErrorHandling.swift */; }; + 9CEE6B0C1C4E8FDC00A1ECB5 /* HelperFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11E640771C2DC15400D24C6D /* HelperFunctions.swift */; }; + 9CEE6B0D1C4E8FDC00A1ECB5 /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11FA0EE01BC591FC00F3DA5B /* Logger.swift */; }; + 9CEE6B0E1C4E8FDC00A1ECB5 /* BubbleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B253131C4A79A50068F47C /* BubbleView.swift */; }; + 9CEE6B0F1C4E8FDC00A1ECB5 /* ChatInputView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11A21EFC1C45BDF200E80A89 /* ChatInputView.swift */; }; + 9CEE6B101C4E8FDC00A1ECB5 /* ChatPrivateTitleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B253551C4AEA400068F47C /* ChatPrivateTitleView.swift */; }; + 9CEE6B111C4E8FDC00A1ECB5 /* FullscreenPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B9C6961BD80B080083C2A5 /* FullscreenPicker.swift */; }; + 9CEE6B121C4E8FDC00A1ECB5 /* ImageViewWithStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11CFCD0C1C27488E0046BD94 /* ImageViewWithStatus.swift */; }; + 9CEE6B131C4E8FDC00A1ECB5 /* NotificationWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 116513251C2D636A0066AF06 /* NotificationWindow.swift */; }; + 9CEE6B141C4E8FDC00A1ECB5 /* QRScannerAimView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 113D564C1C2F437B00B3D3E8 /* QRScannerAimView.swift */; }; + 9CEE6B151C4E8FDC00A1ECB5 /* StaticBackgroundView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11CFCD101C2A02350046BD94 /* StaticBackgroundView.swift */; }; + 9CEE6B161C4E8FDC00A1ECB5 /* UserStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11CFCD0E1C27499D0046BD94 /* UserStatusView.swift */; }; + 9CEE6B171C4E8FDC00A1ECB5 /* ViewPassingGestures.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11E6406C1C2D6C3500D24C6D /* ViewPassingGestures.swift */; }; + 9CEE6B181C4E8FDC00A1ECB5 /* RoundedButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1164C8EC1BC9801200B91107 /* RoundedButton.swift */; }; + 9CEE6B191C4E8FDC00A1ECB5 /* ExtendedTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CBBC7CC1BDFC6C600099A5E /* ExtendedTextField.swift */; }; + 9CEE6B1F1C510A1E00A1ECB5 /* NotificationObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CEE6B1E1C510A1E00A1ECB5 /* NotificationObject.swift */; }; + 9CEE6B201C510A1E00A1ECB5 /* NotificationObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CEE6B1E1C510A1E00A1ECB5 /* NotificationObject.swift */; }; + 9CEE6B461C5289E200A1ECB5 /* SettingsMainController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CEE6B451C5289E200A1ECB5 /* SettingsMainController.swift */; }; + 9CEE6B471C5289E200A1ECB5 /* SettingsMainController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CEE6B451C5289E200A1ECB5 /* SettingsMainController.swift */; }; + 9CEE6B4F1C528AAA00A1ECB5 /* SettingsAboutController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CEE6B4E1C528AAA00A1ECB5 /* SettingsAboutController.swift */; }; + 9CEE6B501C528AAA00A1ECB5 /* SettingsAboutController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CEE6B4E1C528AAA00A1ECB5 /* SettingsAboutController.swift */; }; + 9CEE6B521C528AB600A1ECB5 /* SettingsAdvancedController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CEE6B511C528AB600A1ECB5 /* SettingsAdvancedController.swift */; }; + 9CEE6B531C528AB600A1ECB5 /* SettingsAdvancedController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CEE6B511C528AB600A1ECB5 /* SettingsAdvancedController.swift */; }; + AF2C929D279AB3F10094C08D /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF2C929C279AB3F10094C08D /* NotificationService.swift */; }; + AF2C92A1279AB3F10094C08D /* pushextension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = AF2C929A279AB3F10094C08D /* pushextension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + AFA023F4274C069100FBFCC0 /* ConnectionStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFA023F3274C069100FBFCC0 /* ConnectionStatus.swift */; }; + AFA024022753CC9000FBFCC0 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = AFA024012753CC9000FBFCC0 /* GoogleService-Info.plist */; }; + D4F896D05F7EAA7C321A2AA8 /* libPods-Antidote.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 034E57B3AE56E352BBAA0487 /* libPods-Antidote.a */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 111782AC1DC64391000C1721 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 1164762719794D3300DB20B8 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 1164762E19794D3300DB20B8; + remoteInfo = Antidote; + }; + 113F02EF1CAFC9830009ABE1 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 1173EFE41BC5CF5D00B88B7B /* Yaml.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 8313C4291C8DC2CB00DEF215; + remoteInfo = "Yaml tvOS"; + }; + 113F02F11CAFC9830009ABE1 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 1173EFE41BC5CF5D00B88B7B /* Yaml.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 8313C4321C8DC2CB00DEF215; + remoteInfo = "Tests tvOS"; + }; + 1173EFCF1BC5C6B300B88B7B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 1173EFC81BC5C6B300B88B7B /* SnapKit.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = EEBCC9D819CC627D0083B827; + remoteInfo = "SnapKit iOS"; + }; + 1173EFD31BC5C6B300B88B7B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 1173EFC81BC5C6B300B88B7B /* SnapKit.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = EEBCC9E219CC627E0083B827; + remoteInfo = "SnapKit iOS Tests"; + }; + 1173EFEB1BC5CF5D00B88B7B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 1173EFE41BC5CF5D00B88B7B /* Yaml.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 8E1D76211B258FEE0022C013; + remoteInfo = "Yaml OSX"; + }; + 1173EFED1BC5CF5D00B88B7B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 1173EFE41BC5CF5D00B88B7B /* Yaml.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 8E1D762C1B258FEE0022C013; + remoteInfo = "YamlTests OSX"; + }; + 1173EFEF1BC5CF5D00B88B7B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 1173EFE41BC5CF5D00B88B7B /* Yaml.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = F32DF2581B73054C0011046A; + remoteInfo = "Yaml iOS"; + }; + 1173EFF11BC5CF5D00B88B7B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 1173EFE41BC5CF5D00B88B7B /* Yaml.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = F32DF2611B73054C0011046A; + remoteInfo = "YamlTests iOS"; + }; + 1173F05B1BC5D94400B88B7B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 1164762719794D3300DB20B8 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 1164762E19794D3300DB20B8; + remoteInfo = Antidote; + }; + AF2C929F279AB3F10094C08D /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 1164762719794D3300DB20B8 /* Project object */; + proxyType = 1; + remoteGlobalIDString = AF2C9299279AB3F10094C08D; + remoteInfo = pushextension; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + AF2C92A2279AB3F10094C08D /* Embed App Extensions */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 13; + files = ( + AF2C92A1279AB3F10094C08D /* pushextension.appex in Embed App Extensions */, + ); + name = "Embed App Extensions"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 02404DE3D3BB1BF461C45EA0 /* Pods-ScreenshotsUITests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ScreenshotsUITests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-ScreenshotsUITests/Pods-ScreenshotsUITests.debug.xcconfig"; sourceTree = ""; }; + 034E57B3AE56E352BBAA0487 /* libPods-Antidote.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Antidote.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 1105B18C1EA09B1A0035B213 /* ChatFauxOfflineHeaderView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatFauxOfflineHeaderView.swift; sourceTree = ""; }; + 1109019A1D83417500BC5751 /* PinInputView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PinInputView.swift; sourceTree = ""; }; + 110E078E1EB0756C00B2CA9D /* ResultsExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ResultsExtension.swift; sourceTree = ""; }; + 110E425B1C00DC5E001A3CA2 /* StaticTableController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StaticTableController.swift; sourceTree = ""; }; + 110E49DF1BF925FD00D1FE6F /* ActiveSessionNavigationCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActiveSessionNavigationCoordinator.swift; sourceTree = ""; }; + 111782771DC52BDB000C1721 /* OCTManagerMock.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OCTManagerMock.swift; sourceTree = ""; }; + 1117827A1DC52C3A000C1721 /* OCTSubmanagerBootstrapMock.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OCTSubmanagerBootstrapMock.swift; sourceTree = ""; }; + 1117827D1DC52CBA000C1721 /* OCTSubmanagerCallsMock.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OCTSubmanagerCallsMock.swift; sourceTree = ""; }; + 1117828C1DC531AD000C1721 /* OCTSubmanagerChatsMock.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OCTSubmanagerChatsMock.swift; sourceTree = ""; }; + 111782921DC53371000C1721 /* OCTSubmanagerFilesMock.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OCTSubmanagerFilesMock.swift; sourceTree = ""; }; + 111782951DC53458000C1721 /* OCTSubmanagerFriendsMock.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OCTSubmanagerFriendsMock.swift; sourceTree = ""; }; + 111782981DC53545000C1721 /* OCTSubmanagerObjectsMock.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OCTSubmanagerObjectsMock.swift; sourceTree = ""; }; + 1117829B1DC5363C000C1721 /* OCTSubmanagerUserMock.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OCTSubmanagerUserMock.swift; sourceTree = ""; }; + 1117829E1DC53AB4000C1721 /* ToxFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ToxFactory.swift; sourceTree = ""; }; + 111782A71DC64391000C1721 /* ScreenshotsUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ScreenshotsUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 111782A91DC64391000C1721 /* ScreenshotsUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenshotsUITests.swift; sourceTree = ""; }; + 111782AB1DC64391000C1721 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 1117835E1DC64C89000C1721 /* ScreenshotUITests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ScreenshotUITests-Bridging-Header.h"; sourceTree = ""; }; + 112422651BDD2032004D7926 /* KeyboardNotificationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyboardNotificationController.swift; sourceTree = ""; }; + 112495361DE7ABFF00EF45C4 /* KeyboardObserver.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyboardObserver.swift; sourceTree = ""; }; + 112950831D63AFCE00C9CE0F /* LoginGenericCreateController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginGenericCreateController.swift; sourceTree = ""; }; + 112950861D63AFD800C9CE0F /* LoginCreatePasswordController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginCreatePasswordController.swift; sourceTree = ""; }; + 1129508A1D6851EB00C9CE0F /* LoginCreateAccountCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginCreateAccountCoordinator.swift; sourceTree = ""; }; + 112E4ED51C668C02004312CF /* CallIncomingController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallIncomingController.swift; sourceTree = ""; }; + 112E4EDE1C675C58004312CF /* CallActiveController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallActiveController.swift; sourceTree = ""; }; + 112E4EE41C676553004312CF /* CallButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallButton.swift; sourceTree = ""; }; + 113187371DD290DD00E6FAA2 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.html; name = pl; path = "pl.lproj/import-profile.html"; sourceTree = ""; }; + 113187381DD290DE00E6FAA2 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/Localizable.strings; sourceTree = ""; }; + 113187431DD63B6600E6FAA2 /* ChatOutgoingTextCellModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatOutgoingTextCellModel.swift; sourceTree = ""; }; + 1131D6C41CA9D64500B4531C /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = ""; }; + 1131D6C61CA9D8BC00B4531C /* en */ = {isa = PBXFileReference; lastKnownFileType = text.html; name = en; path = "en.lproj/import-profile.html"; sourceTree = ""; }; + 1131D6C91CA9DA1500B4531C /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.html; name = ru; path = "ru.lproj/import-profile.html"; sourceTree = ""; }; + 1136605B1CDE5D5E0092C27A /* ChatEditable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatEditable.swift; sourceTree = ""; }; + 113AD8491CA97A3000D981B5 /* iPadNavigationView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = iPadNavigationView.swift; sourceTree = ""; }; + 113AD8561CA9C70F00D981B5 /* iPadFriendsButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = iPadFriendsButton.swift; sourceTree = ""; }; + 113BBBA61EA88EAC00540E6C /* ChatTypingHeaderView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatTypingHeaderView.swift; sourceTree = ""; }; + 113D564C1C2F437B00B3D3E8 /* QRScannerAimView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QRScannerAimView.swift; sourceTree = ""; }; + 113D56551C2F459E00B3D3E8 /* QRScannerController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QRScannerController.swift; sourceTree = ""; }; + 113E96451E4BB302000282FC /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/AppStoreLocalizable.strings; sourceTree = ""; }; + 113E96471E4BB314000282FC /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/AppStoreLocalizable.strings; sourceTree = ""; }; + 113E96481E4BB318000282FC /* zh */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = zh; path = zh.lproj/AppStoreLocalizable.strings; sourceTree = ""; }; + 113E96491E4BB31F000282FC /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = da.lproj/AppStoreLocalizable.strings; sourceTree = ""; }; + 113E964A1E4BB322000282FC /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/AppStoreLocalizable.strings; sourceTree = ""; }; + 113E964B1E4BB327000282FC /* pt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pt; path = pt.lproj/AppStoreLocalizable.strings; sourceTree = ""; }; + 113E964C1E4BB32B000282FC /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/AppStoreLocalizable.strings; sourceTree = ""; }; + 113E964E1E4BB371000282FC /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/AppStoreLocalizable.strings; sourceTree = ""; }; + 113E964F1E4BB37B000282FC /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/AppStoreLocalizable.strings; sourceTree = ""; }; + 113F03091CAFCCB90009ABE1 /* SnapshotBaseTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SnapshotBaseTest.swift; sourceTree = ""; }; + 113F030B1CAFCCDD0009ABE1 /* ChatIncomingCallCellSnapshotTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatIncomingCallCellSnapshotTest.swift; sourceTree = ""; }; + 113F030E1CAFCE7B0009ABE1 /* ChatIncomingFileCellSnapshotTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatIncomingFileCellSnapshotTest.swift; sourceTree = ""; }; + 113F03101CAFD1610009ABE1 /* icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = icon.png; sourceTree = ""; }; + 113F03131CAFD5EE0009ABE1 /* CellSnapshotTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CellSnapshotTest.swift; sourceTree = ""; }; + 113F03161CAFD9370009ABE1 /* MockedChatProgressProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockedChatProgressProtocol.swift; sourceTree = ""; }; + 113F03181CAFDB0D0009ABE1 /* ChatIncomingTextCellSnapshotTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatIncomingTextCellSnapshotTest.swift; sourceTree = ""; }; + 113F031A1CAFDBF70009ABE1 /* ChatListCellSnapshotTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatListCellSnapshotTest.swift; sourceTree = ""; }; + 113F031C1CAFE0DE0009ABE1 /* ChatMovableDateCellSnapshotTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatMovableDateCellSnapshotTest.swift; sourceTree = ""; }; + 113F031E1CAFE2130009ABE1 /* ChatOutgoingCallCellSnapshotTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatOutgoingCallCellSnapshotTest.swift; sourceTree = ""; }; + 113F03201CAFE2B50009ABE1 /* ChatOutgoingFileCellSnapshotTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatOutgoingFileCellSnapshotTest.swift; sourceTree = ""; }; + 113F03221CAFE5190009ABE1 /* ChatOutgoingTextCellSnapshotTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatOutgoingTextCellSnapshotTest.swift; sourceTree = ""; }; + 113F03321CB2E9C20009ABE1 /* UIFontExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIFontExtension.swift; sourceTree = ""; }; + 113F03411CB31DD60009ABE1 /* AlertAudioPlayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlertAudioPlayer.swift; sourceTree = ""; }; + 113F035C1CB458D10009ABE1 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.html; name = ar; path = "ar.lproj/import-profile.html"; sourceTree = ""; }; + 113F035D1CB458D10009ABE1 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/Localizable.strings; sourceTree = ""; }; + 1143E4311DCE1A2500BE7250 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.html; name = nl; path = "nl.lproj/import-profile.html"; sourceTree = ""; }; + 1143E4321DCE1A2600BE7250 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Localizable.strings; sourceTree = ""; }; + 1149626B1C5CE3DF001E5435 /* ChangeUserStatusController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeUserStatusController.swift; sourceTree = ""; }; + 114962741C5CEB0B001E5435 /* ProfileDetailsController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProfileDetailsController.swift; sourceTree = ""; }; + 114962911C5E1BE0001E5435 /* ChangePasswordController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangePasswordController.swift; sourceTree = ""; }; + 114962941C64051A001E5435 /* CallBaseController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallBaseController.swift; sourceTree = ""; }; + 114D2D3F1E34D6E400662713 /* SnapshotHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SnapshotHelper.swift; path = fastlane/SnapshotHelper.swift; sourceTree = SOURCE_ROOT; }; + 1156A4781C0E478D005AC8C6 /* StaticTableBaseCellModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StaticTableBaseCellModel.swift; sourceTree = ""; }; + 1156A47A1C0F6178005AC8C6 /* StaticTableButtonCellModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StaticTableButtonCellModel.swift; sourceTree = ""; }; + 1156A47C1C0F632C005AC8C6 /* StaticTableSelectableCellModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StaticTableSelectableCellModel.swift; sourceTree = ""; }; + 1156A4801C0FA0A4005AC8C6 /* StaticTableButtonCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StaticTableButtonCell.swift; sourceTree = ""; }; + 1156A4841C10D119005AC8C6 /* StaticTableAvatarCellModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StaticTableAvatarCellModel.swift; sourceTree = ""; }; + 1156A4861C10D122005AC8C6 /* StaticTableAvatarCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StaticTableAvatarCell.swift; sourceTree = ""; }; + 1156A4881C15FB2B005AC8C6 /* AvatarManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AvatarManager.swift; sourceTree = ""; }; + 115CE3E71EB06F54001C08A0 /* ChatBottomStatusViewManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatBottomStatusViewManager.swift; sourceTree = ""; }; + 115DFB891C177F5C00F18DB5 /* StaticTableDefaultCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StaticTableDefaultCell.swift; sourceTree = ""; }; + 115DFB951C177F6500F18DB5 /* StaticTableDefaultCellModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StaticTableDefaultCellModel.swift; sourceTree = ""; }; + 116046181D8D434B002287C8 /* ChangePinTimeoutController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangePinTimeoutController.swift; sourceTree = ""; }; + 1160B67D1D5F9993002DF75B /* KeychainManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeychainManager.swift; sourceTree = ""; }; + 1160B6801D5FC7CC002DF75B /* KeychainManagerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeychainManagerTests.swift; sourceTree = ""; }; + 1160B6891D5FD8DE002DF75B /* LaunchPlaceholderController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LaunchPlaceholderController.swift; sourceTree = ""; }; + 11628E311CA2FBD1008C097E /* FilePreviewControllerDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FilePreviewControllerDataSource.swift; sourceTree = ""; }; + 11628E3D1CA30C13008C097E /* QuickLookPreviewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QuickLookPreviewController.swift; sourceTree = ""; }; + 11628E621CA57B14008C097E /* ChatOutgoingFileCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatOutgoingFileCell.swift; sourceTree = ""; }; + 11628E6B1CA57B19008C097E /* ChatOutgoingFileCellModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatOutgoingFileCellModel.swift; sourceTree = ""; }; + 11628E711CA580ED008C097E /* ChatGenericFileCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatGenericFileCell.swift; sourceTree = ""; }; + 11628E741CA5811C008C097E /* ChatGenericFileCellModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatGenericFileCellModel.swift; sourceTree = ""; }; + 11628E771CA5819B008C097E /* LoadingImageView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoadingImageView.swift; sourceTree = ""; }; + 11628E7A1CA5BF1F008C097E /* ChangeAutodownloadImagesController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeAutodownloadImagesController.swift; sourceTree = ""; }; + 1164762F19794D3300DB20B8 /* Antidote.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Antidote.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 1164763219794D3300DB20B8 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 1164763419794D3300DB20B8 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; + 1164763619794D3300DB20B8 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; + 1164763A19794D3300DB20B8 /* Antidote-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Antidote-Info.plist"; sourceTree = ""; }; + 1164764419794D3300DB20B8 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; + 1164764B19794D3300DB20B8 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; + 1164C8D71BC922EB00B91107 /* UserDefaultsManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserDefaultsManager.swift; sourceTree = ""; }; + 1164C8E61BC929C500B91107 /* LoginBaseController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginBaseController.swift; sourceTree = ""; }; + 1164C8E81BC929F700B91107 /* LoginChoiceController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginChoiceController.swift; sourceTree = ""; }; + 1164C8EC1BC9801200B91107 /* RoundedButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoundedButton.swift; sourceTree = ""; }; + 1164C8EF1BC982FF00B91107 /* UIImageExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIImageExtension.swift; sourceTree = ""; }; + 1164C8F21BC9880000B91107 /* LoginLogoController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginLogoController.swift; sourceTree = ""; }; + 1164C8F51BC98F8300B91107 /* UIViewControllerExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIViewControllerExtension.swift; sourceTree = ""; }; + 116513181C2C6C980066AF06 /* FriendCardController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FriendCardController.swift; sourceTree = ""; }; + 116513211C2C74940066AF06 /* StaticTableChatButtonsCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StaticTableChatButtonsCell.swift; sourceTree = ""; }; + 116513231C2C749E0066AF06 /* StaticTableChatButtonsCellModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StaticTableChatButtonsCellModel.swift; sourceTree = ""; }; + 116513251C2D636A0066AF06 /* NotificationWindow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationWindow.swift; sourceTree = ""; }; + 1166349F1C6E8D0F0072C980 /* ChatIncomingCallCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatIncomingCallCell.swift; sourceTree = ""; }; + 116634A81C6E8D1A0072C980 /* ChatIncomingCallCellModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatIncomingCallCellModel.swift; sourceTree = ""; }; + 116634AB1C6F407D0072C980 /* ChatOutgoingCallCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatOutgoingCallCell.swift; sourceTree = ""; }; + 116634AE1C6F40820072C980 /* ChatOutgoingCallCellModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatOutgoingCallCellModel.swift; sourceTree = ""; }; + 116634B11C7087A80072C980 /* UIApplicationExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIApplicationExtension.swift; sourceTree = ""; }; + 116634CE1C70E46C0072C980 /* Launch Screen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = "Launch Screen.storyboard"; sourceTree = ""; }; + 116634D81C70F1260072C980 /* CopyLabel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CopyLabel.swift; sourceTree = ""; }; + 116634DF1C7B8D770072C980 /* StaticTableInfoCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StaticTableInfoCell.swift; sourceTree = ""; }; + 116634E81C7B8D7C0072C980 /* StaticTableInfoCellModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StaticTableInfoCellModel.swift; sourceTree = ""; }; + 116634EB1C7B90F20072C980 /* FriendRequestController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FriendRequestController.swift; sourceTree = ""; }; + 116634EE1C7B94530072C980 /* StaticTableMultiChoiceButtonCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StaticTableMultiChoiceButtonCell.swift; sourceTree = ""; }; + 116634F11C7B945A0072C980 /* StaticTableMultiChoiceButtonCellModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StaticTableMultiChoiceButtonCellModel.swift; sourceTree = ""; }; + 116DCE311CAAF47100B693EC /* TopCoordinatorProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TopCoordinatorProtocol.swift; sourceTree = ""; }; + 116DCE3A1CAAF85300B693EC /* NSURLExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSURLExtension.swift; sourceTree = ""; }; + 1173EFC81BC5C6B300B88B7B /* SnapKit.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = SnapKit.xcodeproj; path = submodules/SnapKit/SnapKit.xcodeproj; sourceTree = ""; }; + 1173EFE41BC5CF5D00B88B7B /* Yaml.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Yaml.xcodeproj; path = submodules/YamlSwift/Yaml.xcodeproj; sourceTree = ""; }; + 1173F0561BC5D94400B88B7B /* AntidoteTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AntidoteTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 1173F05A1BC5D94400B88B7B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 1173F06D1BC5D9BA00B88B7B /* Theme.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Theme.swift; sourceTree = ""; }; + 1173F06F1BC5D9CA00B88B7B /* ThemeTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThemeTest.swift; sourceTree = ""; }; + 1173F0711BC5D9DA00B88B7B /* default-theme.yaml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "default-theme.yaml"; sourceTree = ""; }; + 11763ADF1D9C54640035B4C9 /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.html; name = cs; path = "cs.lproj/import-profile.html"; sourceTree = ""; }; + 11763AEA1D9C54680035B4C9 /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cs; path = cs.lproj/Localizable.strings; sourceTree = ""; }; + 11770D691CBC120C00D34D6E /* FriendSelectController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FriendSelectController.swift; sourceTree = ""; }; + 11770D761CBC1C7A00D34D6E /* UIAlertControllerExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIAlertControllerExtension.swift; sourceTree = ""; }; + 11771E2B1CA5C3F200EC259E /* AutomationCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AutomationCoordinator.swift; sourceTree = ""; }; + 11771E351CA5C6E900EC259E /* Reach.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Reach.swift; sourceTree = ""; }; + 1180FD9D1C38497A005F3EA1 /* NSDateFormatterExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSDateFormatterExtension.swift; sourceTree = ""; }; + 1180FD9F1C384E29005F3EA1 /* CallCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallCoordinator.swift; sourceTree = ""; }; + 1183BCAB1CA1B398000CD310 /* ChatIncomingFileCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatIncomingFileCell.swift; sourceTree = ""; }; + 1183BCB41CA1B3AE000CD310 /* ChatIncomingFileCellModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatIncomingFileCellModel.swift; sourceTree = ""; }; + 1183BCBF1CA1DB05000CD310 /* ProgressCircleView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProgressCircleView.swift; sourceTree = ""; }; + 1183BCD61CA1FC5B000CD310 /* ChatProgressProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatProgressProtocol.swift; sourceTree = ""; }; + 1183BCDC1CA1FD55000CD310 /* ChatProgressBridge.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatProgressBridge.swift; sourceTree = ""; }; + 1193AB351C1DEF2E006AA9E5 /* TextEditController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextEditController.swift; sourceTree = ""; }; + 1193AB411C1E2075006AA9E5 /* QRViewerController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QRViewerController.swift; sourceTree = ""; }; + 1193AB471C1F4164006AA9E5 /* FriendListController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FriendListController.swift; sourceTree = ""; }; + 1193AB651C1F5694006AA9E5 /* BaseCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseCell.swift; sourceTree = ""; }; + 1193AB671C1F569A006AA9E5 /* BaseCellModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseCellModel.swift; sourceTree = ""; }; + 1193AB691C1F5C28006AA9E5 /* FriendListCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FriendListCell.swift; sourceTree = ""; }; + 1193AB6B1C1F5C31006AA9E5 /* FriendListCellModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FriendListCellModel.swift; sourceTree = ""; }; + 119AD1BD1BDED261000C5CB8 /* TextViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextViewController.swift; sourceTree = ""; }; + 119AD1C91BDED6E9000C5CB8 /* ErrorHandling.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ErrorHandling.swift; sourceTree = ""; }; + 119AD1CB1BDEDD9C000C5CB8 /* UIColorExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIColorExtension.swift; sourceTree = ""; }; + 11A21EFA1C45BDB100E80A89 /* ChatPrivateController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatPrivateController.swift; sourceTree = ""; }; + 11A21EFC1C45BDF200E80A89 /* ChatInputView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatInputView.swift; sourceTree = ""; }; + 11AEBE701DA1876F00D04B59 /* FAQController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FAQController.swift; sourceTree = ""; }; + 11B252F91C4A614D0068F47C /* ChatIncomingTextCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatIncomingTextCell.swift; sourceTree = ""; }; + 11B252FD1C4A615E0068F47C /* ChatOutgoingTextCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatOutgoingTextCell.swift; sourceTree = ""; }; + 11B253011C4A61D00068F47C /* ChatMovableDateCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatMovableDateCell.swift; sourceTree = ""; }; + 11B253031C4A61D50068F47C /* ChatMovableDateCellModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatMovableDateCellModel.swift; sourceTree = ""; }; + 11B253131C4A79A50068F47C /* BubbleView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BubbleView.swift; sourceTree = ""; }; + 11B253491C4AD2200068F47C /* isotoxin_Calltone.aac */ = {isa = PBXFileReference; lastKnownFileType = file; path = isotoxin_Calltone.aac; sourceTree = ""; }; + 11B2534A1C4AD23A0068F47C /* isotoxin_Hangup.aac */ = {isa = PBXFileReference; lastKnownFileType = file; path = isotoxin_Hangup.aac; sourceTree = ""; }; + 11B2534B1C4AD23A0068F47C /* isotoxin_NewMessage.aac */ = {isa = PBXFileReference; lastKnownFileType = file; path = isotoxin_NewMessage.aac; sourceTree = ""; }; + 11B2534C1C4AD23A0068F47C /* isotoxin_Ringtone.aac */ = {isa = PBXFileReference; lastKnownFileType = file; path = isotoxin_Ringtone.aac; sourceTree = ""; }; + 11B2534D1C4AD23A0068F47C /* isotoxin_RingtoneWhileCall.aac */ = {isa = PBXFileReference; lastKnownFileType = file; path = isotoxin_RingtoneWhileCall.aac; sourceTree = ""; }; + 11B2534E1C4AD2550068F47C /* AudioPlayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioPlayer.swift; sourceTree = ""; }; + 11B253551C4AEA400068F47C /* ChatPrivateTitleView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatPrivateTitleView.swift; sourceTree = ""; }; + 11B2535C1C4BACDB0068F47C /* TabBarController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TabBarController.swift; sourceTree = ""; }; + 11B253651C4BAD3C0068F47C /* TabBarAbstractItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TabBarAbstractItem.swift; sourceTree = ""; }; + 11B253691C4BAD560068F47C /* TabBarBadgeItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TabBarBadgeItem.swift; sourceTree = ""; }; + 11B2536C1C4BAD5D0068F47C /* TabBarProfileItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TabBarProfileItem.swift; sourceTree = ""; }; + 11B253A31C4EA8040068F47C /* InterfaceIdiom.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InterfaceIdiom.swift; sourceTree = ""; }; + 11B253AD1C4EC47D0068F47C /* IncompressibleView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IncompressibleView.swift; sourceTree = ""; }; + 11B253B61C503FA10068F47C /* NSTimerExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSTimerExtension.swift; sourceTree = ""; }; + 11B253FA1C52C0A10068F47C /* StaticTableSwitchCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StaticTableSwitchCell.swift; sourceTree = ""; }; + 11B253FD1C52C0AA0068F47C /* StaticTableSwitchCellModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StaticTableSwitchCellModel.swift; sourceTree = ""; }; + 11B9C6821BD598FC0083C2A5 /* OCTManagerConfigurationExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OCTManagerConfigurationExtension.swift; sourceTree = ""; }; + 11B9C6961BD80B080083C2A5 /* FullscreenPicker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FullscreenPicker.swift; sourceTree = ""; }; + 11C33AC31DC961DC008DBC49 /* LoginChoiceViewSnapshotTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginChoiceViewSnapshotTest.swift; sourceTree = ""; }; + 11CFCD0A1C2745230046BD94 /* UserStatus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserStatus.swift; sourceTree = ""; }; + 11CFCD0C1C27488E0046BD94 /* ImageViewWithStatus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageViewWithStatus.swift; sourceTree = ""; }; + 11CFCD0E1C27499D0046BD94 /* UserStatusView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserStatusView.swift; sourceTree = ""; }; + 11CFCD101C2A02350046BD94 /* StaticBackgroundView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StaticBackgroundView.swift; sourceTree = ""; }; + 11D15D741D53CDAA0042FD4A /* br */ = {isa = PBXFileReference; lastKnownFileType = text.html; name = br; path = "br.lproj/import-profile.html"; sourceTree = ""; }; + 11D15D751D53CDAA0042FD4A /* br */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = br; path = br.lproj/Localizable.strings; sourceTree = ""; }; + 11D15D761D53CECC0042FD4A /* lt */ = {isa = PBXFileReference; lastKnownFileType = text.html; name = lt; path = "lt.lproj/import-profile.html"; sourceTree = ""; }; + 11D15D771D53CECC0042FD4A /* lt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = lt; path = lt.lproj/Localizable.strings; sourceTree = ""; }; + 11D15D7A1D53D26A0042FD4A /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.html; name = fr; path = "fr.lproj/import-profile.html"; sourceTree = ""; }; + 11D15D7B1D53D26A0042FD4A /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = ""; }; + 11D17CE81DD11F10006B2910 /* dummy-photo.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "dummy-photo.jpg"; sourceTree = ""; }; + 11DDEAFC1D5FD9FE0000E2BE /* LaunchPlaceholderBoard.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = LaunchPlaceholderBoard.storyboard; sourceTree = ""; }; + 11E6406C1C2D6C3500D24C6D /* ViewPassingGestures.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewPassingGestures.swift; sourceTree = ""; }; + 11E640751C2DBAE200D24C6D /* AddFriendController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddFriendController.swift; sourceTree = ""; }; + 11E640771C2DC15400D24C6D /* HelperFunctions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HelperFunctions.swift; sourceTree = ""; }; + 11F08D161DE0610B00F80F5F /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; + 11F08D1E1DE0611700F80F5F /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/InfoPlist.strings; sourceTree = ""; }; + 11F08D1F1DE0611800F80F5F /* zh */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = zh; path = zh.lproj/InfoPlist.strings; sourceTree = ""; }; + 11F08D201DE0611800F80F5F /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = da.lproj/InfoPlist.strings; sourceTree = ""; }; + 11F08D211DE0611900F80F5F /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/InfoPlist.strings; sourceTree = ""; }; + 11F08D221DE0611A00F80F5F /* pt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pt; path = pt.lproj/InfoPlist.strings; sourceTree = ""; }; + 11F08D231DE0611B00F80F5F /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/InfoPlist.strings; sourceTree = ""; }; + 11F08D241DE0611B00F80F5F /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/InfoPlist.strings; sourceTree = ""; }; + 11F08D251DE0611C00F80F5F /* lt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = lt; path = lt.lproj/InfoPlist.strings; sourceTree = ""; }; + 11F08D261DE0611D00F80F5F /* br */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = br; path = br.lproj/InfoPlist.strings; sourceTree = ""; }; + 11F08D281DE0612200F80F5F /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/InfoPlist.strings; sourceTree = ""; }; + 11F08D291DE0612200F80F5F /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cs; path = cs.lproj/InfoPlist.strings; sourceTree = ""; }; + 11F08D2B1DE0612400F80F5F /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/InfoPlist.strings; sourceTree = ""; }; + 11F08D2C1DE0612700F80F5F /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/InfoPlist.strings; sourceTree = ""; }; + 11F276AD1D3EBEF700C613AA /* ChatBaseTextCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatBaseTextCell.swift; sourceTree = ""; }; + 11F276BA1D3EBF3000C613AA /* ChatBaseTextCellModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatBaseTextCellModel.swift; sourceTree = ""; }; + 11F83B751CADC9260074FE11 /* zh */ = {isa = PBXFileReference; lastKnownFileType = text.html; name = zh; path = "zh.lproj/import-profile.html"; sourceTree = ""; }; + 11F83B7C1CADC9270074FE11 /* zh */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = zh; path = zh.lproj/Localizable.strings; sourceTree = ""; }; + 11F83B7D1CADC9330074FE11 /* da */ = {isa = PBXFileReference; lastKnownFileType = text.html; name = da; path = "da.lproj/import-profile.html"; sourceTree = ""; }; + 11F83B7E1CADC9330074FE11 /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = da.lproj/Localizable.strings; sourceTree = ""; }; + 11F83B821CADC9460074FE11 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.html; name = de; path = "de.lproj/import-profile.html"; sourceTree = ""; }; + 11F83B831CADC9460074FE11 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = ""; }; + 11F83B841CADC9790074FE11 /* pt */ = {isa = PBXFileReference; lastKnownFileType = text.html; name = pt; path = "pt.lproj/import-profile.html"; sourceTree = ""; }; + 11F83B851CADC9790074FE11 /* pt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pt; path = pt.lproj/Localizable.strings; sourceTree = ""; }; + 11F83B861CADC9820074FE11 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.html; name = es; path = "es.lproj/import-profile.html"; sourceTree = ""; }; + 11F83B871CADC9820074FE11 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = ""; }; + 11F83BD31CAFB0F30074FE11 /* AntidoteTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "AntidoteTests-Bridging-Header.h"; sourceTree = ""; }; + 11F83BDA1CAFB2A20074FE11 /* SwiftSupport.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftSupport.swift; sourceTree = ""; }; + 11FA0ED21BC5842800F3DA5B /* Antidote-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Antidote-Bridging-Header.h"; sourceTree = ""; }; + 11FA0ED31BC5842800F3DA5B /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 11FA0ED91BC584D900F3DA5B /* AppCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppCoordinator.swift; sourceTree = ""; }; + 11FA0EDD1BC58DCC00F3DA5B /* CoordinatorProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoordinatorProtocol.swift; sourceTree = ""; }; + 11FA0EE01BC591FC00F3DA5B /* Logger.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Logger.swift; sourceTree = ""; }; + 11FA0EE61BC59B1400F3DA5B /* ActiveSessionCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActiveSessionCoordinator.swift; sourceTree = ""; }; + 11FA0EE81BC5A66D00F3DA5B /* LoginCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginCoordinator.swift; sourceTree = ""; }; + 11FA0EEA1BC5A68600F3DA5B /* FriendsTabCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FriendsTabCoordinator.swift; sourceTree = ""; }; + 11FA0EEC1BC5A69000F3DA5B /* ProfileTabCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProfileTabCoordinator.swift; sourceTree = ""; }; + 11FA0EF01BC5A6A500F3DA5B /* SettingsTabCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsTabCoordinator.swift; sourceTree = ""; }; + 11FA0EF21BC5A6AF00F3DA5B /* ChatsTabCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatsTabCoordinator.swift; sourceTree = ""; }; + 11FC10561D32E54A00CE863E /* Results.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Results.swift; sourceTree = ""; }; + 11FC10591D32EED000CE863E /* ResultsChange.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ResultsChange.swift; sourceTree = ""; }; + 11FC105C1D32F29700CE863E /* OCTSubmanagerObjectsExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OCTSubmanagerObjectsExtension.swift; sourceTree = ""; }; + 22DCF57E8F127B60BD096DD1 /* Pods-ScreenshotsUITests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ScreenshotsUITests.release.xcconfig"; path = "Pods/Target Support Files/Pods-ScreenshotsUITests/Pods-ScreenshotsUITests.release.xcconfig"; sourceTree = ""; }; + 2D5B916CEDBEC1B69CD1EFA4 /* Pods-Antidote.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Antidote.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Antidote/Pods-Antidote.debug.xcconfig"; sourceTree = ""; }; + 43C533DEE94E80C981FEC348 /* Pods-AntidoteTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AntidoteTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-AntidoteTests/Pods-AntidoteTests.debug.xcconfig"; sourceTree = ""; }; + 4E3D0F9427C9751300D5A068 /* LinearProgressBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinearProgressBar.swift; sourceTree = ""; }; + 4E4B267E27C0DCAE00E07A66 /* Call.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Call.swift; sourceTree = ""; }; + 4E4B268427C0DCB500E07A66 /* CallManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallManager.swift; sourceTree = ""; }; + 4E4B268A27C0DCBC00E07A66 /* ProviderDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProviderDelegate.swift; sourceTree = ""; }; + 4E4EEA1827DCEC67008B0E77 /* LocationManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocationManager.swift; sourceTree = ""; }; + 4E4EEA1E27DCECD3008B0E77 /* Bus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Bus.swift; sourceTree = ""; }; + 6A1B3D525D11BDD4F3E9B831 /* libPods-ScreenshotsUITests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-ScreenshotsUITests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 72586F4D098584EF43024224 /* libPods-AntidoteTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-AntidoteTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 9C04BB6C1C17389200F58488 /* StaticTableBaseCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StaticTableBaseCell.swift; sourceTree = ""; }; + 9C07151C1BCD2E5B003A27B5 /* PortraitNavigationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PortraitNavigationController.swift; sourceTree = ""; }; + 9C07151E1BCD501D003A27B5 /* LoginFormController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginFormController.swift; sourceTree = ""; }; + 9C19367D1D79CF7E005EA0B2 /* EnterPinController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnterPinController.swift; sourceTree = ""; }; + 9C1FEB281D8C10EB008C2ADE /* ProfileSettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProfileSettings.swift; sourceTree = ""; }; + 9C2EF3701C4D4D5C006E7AB1 /* NotificationCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationCoordinator.swift; sourceTree = ""; }; + 9C2EF3791C4E2DDE006E7AB1 /* ChatListTableManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatListTableManager.swift; sourceTree = ""; }; + 9C3271861D79C19C00347490 /* PinAuthorizationCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PinAuthorizationCoordinator.swift; sourceTree = ""; }; + 9C7475BF1BC698110098B1A4 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; + 9C7475C41BC698510098B1A4 /* StringExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StringExtension.swift; sourceTree = ""; }; + 9C89D83C1DDB36770040C67B /* Antidote.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Antidote.entitlements; sourceTree = ""; }; + 9C9A07001BE793BA0003D6C7 /* ProfileMainController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProfileMainController.swift; sourceTree = ""; }; + 9CB1F9501D58CA4000105858 /* RunningCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RunningCoordinator.swift; sourceTree = ""; }; + 9CBBC7C01BDFC62700099A5E /* LoginCreateAccountController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginCreateAccountController.swift; sourceTree = ""; }; + 9CBBC7CC1BDFC6C600099A5E /* ExtendedTextField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExtendedTextField.swift; sourceTree = ""; }; + 9CDC091A1C34081900DC0D63 /* FriendListDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FriendListDataSource.swift; sourceTree = ""; }; + 9CDC09241C34083100DC0D63 /* FriendListDataSourceTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FriendListDataSourceTest.swift; sourceTree = ""; }; + 9CDC092A1C34102F00DC0D63 /* ExceptionHandling.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExceptionHandling.h; sourceTree = ""; }; + 9CDC092B1C34102F00DC0D63 /* ExceptionHandling.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ExceptionHandling.m; sourceTree = ""; }; + 9CDC093D1C3415DE00DC0D63 /* Antidote-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Antidote-Prefix.pch"; sourceTree = ""; }; + 9CDDB2051BD5376200B65D79 /* ProfileManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProfileManager.swift; sourceTree = ""; }; + 9CDE31E51E489B2700333E0D /* ChatInputViewManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatInputViewManager.swift; sourceTree = ""; }; + 9CE0BDE51C45229500DCE357 /* ChatListController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatListController.swift; sourceTree = ""; }; + 9CE0BDEF1C4522BF00DCE357 /* ChatListCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatListCell.swift; sourceTree = ""; }; + 9CE0BDF21C4522C800DCE357 /* ChatListCellModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatListCellModel.swift; sourceTree = ""; }; + 9CEA6A1E1D957EFC0045F000 /* antidote-acknowledgements.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "antidote-acknowledgements.html"; sourceTree = ""; }; + 9CEE6AA11C4E679100A1ECB5 /* PrimaryIpadController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrimaryIpadController.swift; sourceTree = ""; }; + 9CEE6B1E1C510A1E00A1ECB5 /* NotificationObject.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationObject.swift; sourceTree = ""; }; + 9CEE6B451C5289E200A1ECB5 /* SettingsMainController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsMainController.swift; sourceTree = ""; }; + 9CEE6B4E1C528AAA00A1ECB5 /* SettingsAboutController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsAboutController.swift; sourceTree = ""; }; + 9CEE6B511C528AB600A1ECB5 /* SettingsAdvancedController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsAdvancedController.swift; sourceTree = ""; }; + AF2C929A279AB3F10094C08D /* pushextension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = pushextension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; + AF2C929C279AB3F10094C08D /* NotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = ""; }; + AF2C929E279AB3F10094C08D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + AF6AB23329156C5800019362 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/InfoPlist.strings; sourceTree = ""; }; + AF6AB23429156C6000019362 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/AppStoreLocalizable.strings; sourceTree = ""; }; + AF6AB23A29256F0000019362 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = ""; }; + AF6AB23529156EDA00019362 /* ca */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ca; path = ca.lproj/InfoPlist.strings; sourceTree = ""; }; + AF6AB23629156EDA00019362 /* ca */ = {isa = PBXFileReference; lastKnownFileType = text.html; name = ca; path = "ca.lproj/import-profile.html"; sourceTree = ""; }; + AF6AB23A29257F0000019362 /* ca */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ca; path = ca.lproj/Localizable.strings; sourceTree = ""; }; + AF6AB23729156EDC00019362 /* ca */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ca; path = ca.lproj/AppStoreLocalizable.strings; sourceTree = ""; }; + AF6AB23829156F0000019362 /* ko */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ko; path = ko.lproj/InfoPlist.strings; sourceTree = ""; }; + AF6AB23929156F0000019362 /* ko */ = {isa = PBXFileReference; lastKnownFileType = text.html; name = ko; path = "ko.lproj/import-profile.html"; sourceTree = ""; }; + AF6AB23A29156F0000019362 /* ko */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ko; path = ko.lproj/Localizable.strings; sourceTree = ""; }; + AF6AB23B29156F0000019362 /* ko */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ko; path = ko.lproj/AppStoreLocalizable.strings; sourceTree = ""; }; + AF6AB23C29156F0A00019362 /* nb */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nb; path = nb.lproj/InfoPlist.strings; sourceTree = ""; }; + AF6AB23D29156F0A00019362 /* nb */ = {isa = PBXFileReference; lastKnownFileType = text.html; name = nb; path = "nb.lproj/import-profile.html"; sourceTree = ""; }; + AF6AB23A29258F0000019362 /* nb */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nb; path = nb.lproj/Localizable.strings; sourceTree = ""; }; + AF6AB23F29156F0B00019362 /* nb */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nb; path = nb.lproj/AppStoreLocalizable.strings; sourceTree = ""; }; + AF6AB24029156F1C00019362 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/InfoPlist.strings"; sourceTree = ""; }; + AF6AB24129156F1C00019362 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.html; name = "pt-BR"; path = "pt-BR.lproj/import-profile.html"; sourceTree = ""; }; + AF6AB24229156F1E00019362 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/AppStoreLocalizable.strings"; sourceTree = ""; }; + AF6AB23A29259F0000019362 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Localizable.strings"; sourceTree = ""; }; + AF6AB24129156F1C00019362 /* el */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "el"; path = "el.lproj/Localizable.strings"; sourceTree = ""; }; + AFA023F3274C069100FBFCC0 /* ConnectionStatus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConnectionStatus.swift; sourceTree = ""; }; + AFA024012753CC9000FBFCC0 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; + B3C17AF8CE3B4AD1B68F2B5B /* Pods-Antidote.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Antidote.release.xcconfig"; path = "Pods/Target Support Files/Pods-Antidote/Pods-Antidote.release.xcconfig"; sourceTree = ""; }; + CEC32120B965BE40E0029DB1 /* Pods-AntidoteTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AntidoteTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-AntidoteTests/Pods-AntidoteTests.release.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 111782A41DC64391000C1721 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 8B8E9C45924FB18EB2C8044E /* libPods-ScreenshotsUITests.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1164762C19794D3300DB20B8 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 1164763519794D3300DB20B8 /* CoreGraphics.framework in Frameworks */, + 1164763719794D3300DB20B8 /* UIKit.framework in Frameworks */, + 1164763319794D3300DB20B8 /* Foundation.framework in Frameworks */, + D4F896D05F7EAA7C321A2AA8 /* libPods-Antidote.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1173F0531BC5D94400B88B7B /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 96166DAAD67996D5A6819984 /* libPods-AntidoteTests.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + AF2C9297279AB3F10094C08D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 1117826C1DC52BBB000C1721 /* Mocks */ = { + isa = PBXGroup; + children = ( + 111782771DC52BDB000C1721 /* OCTManagerMock.swift */, + 1117827A1DC52C3A000C1721 /* OCTSubmanagerBootstrapMock.swift */, + 1117827D1DC52CBA000C1721 /* OCTSubmanagerCallsMock.swift */, + 1117828C1DC531AD000C1721 /* OCTSubmanagerChatsMock.swift */, + 111782921DC53371000C1721 /* OCTSubmanagerFilesMock.swift */, + 111782951DC53458000C1721 /* OCTSubmanagerFriendsMock.swift */, + 111782981DC53545000C1721 /* OCTSubmanagerObjectsMock.swift */, + 1117829B1DC5363C000C1721 /* OCTSubmanagerUserMock.swift */, + ); + name = Mocks; + sourceTree = ""; + }; + 111782A81DC64391000C1721 /* ScreenshotsUITests */ = { + isa = PBXGroup; + children = ( + 111782AB1DC64391000C1721 /* Info.plist */, + 111782A91DC64391000C1721 /* ScreenshotsUITests.swift */, + 1117835E1DC64C89000C1721 /* ScreenshotUITests-Bridging-Header.h */, + 114D2D3F1E34D6E400662713 /* SnapshotHelper.swift */, + ); + path = ScreenshotsUITests; + sourceTree = ""; + }; + 112950891D6851B600C9CE0F /* Login */ = { + isa = PBXGroup; + children = ( + 11FA0EE81BC5A66D00F3DA5B /* LoginCoordinator.swift */, + 1129508A1D6851EB00C9CE0F /* LoginCreateAccountCoordinator.swift */, + ); + name = Login; + sourceTree = ""; + }; + 113F02FB1CAFCBA00009ABE1 /* Cells */ = { + isa = PBXGroup; + children = ( + 113F03131CAFD5EE0009ABE1 /* CellSnapshotTest.swift */, + 113F030B1CAFCCDD0009ABE1 /* ChatIncomingCallCellSnapshotTest.swift */, + 113F030E1CAFCE7B0009ABE1 /* ChatIncomingFileCellSnapshotTest.swift */, + 113F03181CAFDB0D0009ABE1 /* ChatIncomingTextCellSnapshotTest.swift */, + 113F031A1CAFDBF70009ABE1 /* ChatListCellSnapshotTest.swift */, + 113F031C1CAFE0DE0009ABE1 /* ChatMovableDateCellSnapshotTest.swift */, + 113F031E1CAFE2130009ABE1 /* ChatOutgoingCallCellSnapshotTest.swift */, + 113F03201CAFE2B50009ABE1 /* ChatOutgoingFileCellSnapshotTest.swift */, + 113F03221CAFE5190009ABE1 /* ChatOutgoingTextCellSnapshotTest.swift */, + ); + name = Cells; + sourceTree = ""; + }; + 113F030D1CAFCCE20009ABE1 /* SnapshotTests */ = { + isa = PBXGroup; + children = ( + 113F03101CAFD1610009ABE1 /* icon.png */, + 113F03091CAFCCB90009ABE1 /* SnapshotBaseTest.swift */, + 113F02FB1CAFCBA00009ABE1 /* Cells */, + 11C33AB81DC961AB008DBC49 /* Login */, + 113F03151CAFD9200009ABE1 /* Mocks */, + ); + name = SnapshotTests; + sourceTree = ""; + }; + 113F03151CAFD9200009ABE1 /* Mocks */ = { + isa = PBXGroup; + children = ( + 113F03161CAFD9370009ABE1 /* MockedChatProgressProtocol.swift */, + ); + name = Mocks; + sourceTree = ""; + }; + 1164762619794D3300DB20B8 = { + isa = PBXGroup; + children = ( + 1164763819794D3300DB20B8 /* Antidote */, + 1173F0571BC5D94400B88B7B /* AntidoteTests */, + 111782A81DC64391000C1721 /* ScreenshotsUITests */, + AF2C929B279AB3F10094C08D /* pushextension */, + 1164763119794D3300DB20B8 /* Frameworks */, + 1164763019794D3300DB20B8 /* Products */, + 1173EFB21BC5C40100B88B7B /* Submodules */, + D5C4D8B82C26B8F47A461D93 /* Pods */, + ); + sourceTree = ""; + }; + 1164763019794D3300DB20B8 /* Products */ = { + isa = PBXGroup; + children = ( + 1164762F19794D3300DB20B8 /* Antidote.app */, + 1173F0561BC5D94400B88B7B /* AntidoteTests.xctest */, + 111782A71DC64391000C1721 /* ScreenshotsUITests.xctest */, + AF2C929A279AB3F10094C08D /* pushextension.appex */, + ); + name = Products; + sourceTree = ""; + }; + 1164763119794D3300DB20B8 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 1164763219794D3300DB20B8 /* Foundation.framework */, + 1164763419794D3300DB20B8 /* CoreGraphics.framework */, + 1164763619794D3300DB20B8 /* UIKit.framework */, + 1164764B19794D3300DB20B8 /* XCTest.framework */, + 034E57B3AE56E352BBAA0487 /* libPods-Antidote.a */, + 72586F4D098584EF43024224 /* libPods-AntidoteTests.a */, + 6A1B3D525D11BDD4F3E9B831 /* libPods-ScreenshotsUITests.a */, + ); + name = Frameworks; + sourceTree = ""; + }; + 1164763819794D3300DB20B8 /* Antidote */ = { + isa = PBXGroup; + children = ( + 4E4B267D27C0DC9800E07A66 /* CallManagement */, + 9C89D83C1DDB36770040C67B /* Antidote.entitlements */, + F902D28D1ADED27A0070A3F5 /* Application */, + 1193AB561C1F565B006AA9E5 /* Cells */, + 1173F06C1BC5D9B000B88B7B /* Classes */, + 1164C8E31BC9279500B91107 /* Controllers */, + 11FA0ED61BC584A300F3DA5B /* Coordinators */, + 11CFCD091C2744E10046BD94 /* Enums */, + 9C7475C11BC698240098B1A4 /* Extensions */, + 11FA0EDF1BC591EA00F3DA5B /* Functions */, + 1117826C1DC52BBB000C1721 /* Mocks */, + 11771E341CA5C6D100EC259E /* Other */, + 119AD2081BEC718C000C5CB8 /* Sounds */, + 1164C8EA1BC97FF600B91107 /* Views */, + ); + path = Antidote; + sourceTree = ""; + }; + 1164C8E31BC9279500B91107 /* Controllers */ = { + isa = PBXGroup; + children = ( + 112422651BDD2032004D7926 /* KeyboardNotificationController.swift */, + 1160B6891D5FD8DE002DF75B /* LaunchPlaceholderController.swift */, + 11DDEAFC1D5FD9FE0000E2BE /* LaunchPlaceholderBoard.storyboard */, + 9C07151C1BCD2E5B003A27B5 /* PortraitNavigationController.swift */, + 119AD1CD1BDEE4A2000C5CB8 /* Login */, + 9C9A06F51BE792E60003D6C7 /* Running */, + ); + name = Controllers; + sourceTree = ""; + }; + 1164C8EA1BC97FF600B91107 /* Views */ = { + isa = PBXGroup; + children = ( + 11B253131C4A79A50068F47C /* BubbleView.swift */, + 112E4EE41C676553004312CF /* CallButton.swift */, + 1105B18C1EA09B1A0035B213 /* ChatFauxOfflineHeaderView.swift */, + 11A21EFC1C45BDF200E80A89 /* ChatInputView.swift */, + 11B253551C4AEA400068F47C /* ChatPrivateTitleView.swift */, + 113BBBA61EA88EAC00540E6C /* ChatTypingHeaderView.swift */, + 116634D81C70F1260072C980 /* CopyLabel.swift */, + 9CBBC7CC1BDFC6C600099A5E /* ExtendedTextField.swift */, + 11B9C6961BD80B080083C2A5 /* FullscreenPicker.swift */, + 11CFCD0C1C27488E0046BD94 /* ImageViewWithStatus.swift */, + 11B253AD1C4EC47D0068F47C /* IncompressibleView.swift */, + 113AD8561CA9C70F00D981B5 /* iPadFriendsButton.swift */, + 113AD8491CA97A3000D981B5 /* iPadNavigationView.swift */, + 11628E771CA5819B008C097E /* LoadingImageView.swift */, + 116513251C2D636A0066AF06 /* NotificationWindow.swift */, + 1109019A1D83417500BC5751 /* PinInputView.swift */, + 1183BCBF1CA1DB05000CD310 /* ProgressCircleView.swift */, + 113D564C1C2F437B00B3D3E8 /* QRScannerAimView.swift */, + 1164C8EC1BC9801200B91107 /* RoundedButton.swift */, + 11CFCD101C2A02350046BD94 /* StaticBackgroundView.swift */, + 11CFCD0E1C27499D0046BD94 /* UserStatusView.swift */, + 11E6406C1C2D6C3500D24C6D /* ViewPassingGestures.swift */, + ); + name = Views; + sourceTree = ""; + }; + 1173EFB21BC5C40100B88B7B /* Submodules */ = { + isa = PBXGroup; + children = ( + 1173EFC81BC5C6B300B88B7B /* SnapKit.xcodeproj */, + 1173EFE41BC5CF5D00B88B7B /* Yaml.xcodeproj */, + ); + name = Submodules; + sourceTree = ""; + }; + 1173EFC91BC5C6B300B88B7B /* Products */ = { + isa = PBXGroup; + children = ( + 1173EFD01BC5C6B300B88B7B /* SnapKit.framework */, + 1173EFD41BC5C6B300B88B7B /* SnapKit Tests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 1173EFE51BC5CF5D00B88B7B /* Products */ = { + isa = PBXGroup; + children = ( + 1173EFEC1BC5CF5D00B88B7B /* Yaml.framework */, + 1173EFEE1BC5CF5D00B88B7B /* Tests.xctest */, + 1173EFF01BC5CF5D00B88B7B /* Yaml.framework */, + 1173EFF21BC5CF5D00B88B7B /* Tests.xctest */, + 113F02F01CAFC9830009ABE1 /* Yaml.framework */, + 113F02F21CAFC9830009ABE1 /* Tests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 1173F0571BC5D94400B88B7B /* AntidoteTests */ = { + isa = PBXGroup; + children = ( + 11F83BD31CAFB0F30074FE11 /* AntidoteTests-Bridging-Header.h */, + 1173F05A1BC5D94400B88B7B /* Info.plist */, + 9CDC09241C34083100DC0D63 /* FriendListDataSourceTest.swift */, + 1160B6801D5FC7CC002DF75B /* KeychainManagerTests.swift */, + 11F83BDA1CAFB2A20074FE11 /* SwiftSupport.swift */, + 1173F06F1BC5D9CA00B88B7B /* ThemeTest.swift */, + 113F030D1CAFCCE20009ABE1 /* SnapshotTests */, + ); + path = AntidoteTests; + sourceTree = ""; + }; + 1173F06C1BC5D9B000B88B7B /* Classes */ = { + isa = PBXGroup; + children = ( + 113F03411CB31DD60009ABE1 /* AlertAudioPlayer.swift */, + 11B2534E1C4AD2550068F47C /* AudioPlayer.swift */, + 1156A4881C15FB2B005AC8C6 /* AvatarManager.swift */, + 115CE3E71EB06F54001C08A0 /* ChatBottomStatusViewManager.swift */, + 9CDE31E51E489B2700333E0D /* ChatInputViewManager.swift */, + 9C2EF3791C4E2DDE006E7AB1 /* ChatListTableManager.swift */, + 11628E311CA2FBD1008C097E /* FilePreviewControllerDataSource.swift */, + 9CDC091A1C34081900DC0D63 /* FriendListDataSource.swift */, + 112495361DE7ABFF00EF45C4 /* KeyboardObserver.swift */, + 1160B67D1D5F9993002DF75B /* KeychainManager.swift */, + 9CEE6B1E1C510A1E00A1ECB5 /* NotificationObject.swift */, + 9CDDB2051BD5376200B65D79 /* ProfileManager.swift */, + 9C1FEB281D8C10EB008C2ADE /* ProfileSettings.swift */, + 11FC10561D32E54A00CE863E /* Results.swift */, + 11FC10591D32EED000CE863E /* ResultsChange.swift */, + 11B253651C4BAD3C0068F47C /* TabBarAbstractItem.swift */, + 11B253691C4BAD560068F47C /* TabBarBadgeItem.swift */, + 11B2536C1C4BAD5D0068F47C /* TabBarProfileItem.swift */, + 1173F06D1BC5D9BA00B88B7B /* Theme.swift */, + 1117829E1DC53AB4000C1721 /* ToxFactory.swift */, + 1164C8D71BC922EB00B91107 /* UserDefaultsManager.swift */, + 4E3D0F9427C9751300D5A068 /* LinearProgressBar.swift */, + ); + name = Classes; + sourceTree = ""; + }; + 11771E341CA5C6D100EC259E /* Other */ = { + isa = PBXGroup; + children = ( + AFA024012753CC9000FBFCC0 /* GoogleService-Info.plist */, + 11771E351CA5C6E900EC259E /* Reach.swift */, + ); + name = Other; + sourceTree = ""; + }; + 1193AB561C1F565B006AA9E5 /* Cells */ = { + isa = PBXGroup; + children = ( + 1193AB651C1F5694006AA9E5 /* BaseCell.swift */, + 1193AB671C1F569A006AA9E5 /* BaseCellModel.swift */, + 11F276AD1D3EBEF700C613AA /* ChatBaseTextCell.swift */, + 11F276BA1D3EBF3000C613AA /* ChatBaseTextCellModel.swift */, + 1136605B1CDE5D5E0092C27A /* ChatEditable.swift */, + 11628E711CA580ED008C097E /* ChatGenericFileCell.swift */, + 11628E741CA5811C008C097E /* ChatGenericFileCellModel.swift */, + 1166349F1C6E8D0F0072C980 /* ChatIncomingCallCell.swift */, + 116634A81C6E8D1A0072C980 /* ChatIncomingCallCellModel.swift */, + 1183BCAB1CA1B398000CD310 /* ChatIncomingFileCell.swift */, + 1183BCB41CA1B3AE000CD310 /* ChatIncomingFileCellModel.swift */, + 11B252F91C4A614D0068F47C /* ChatIncomingTextCell.swift */, + 9CE0BDEF1C4522BF00DCE357 /* ChatListCell.swift */, + 9CE0BDF21C4522C800DCE357 /* ChatListCellModel.swift */, + 11B253011C4A61D00068F47C /* ChatMovableDateCell.swift */, + 11B253031C4A61D50068F47C /* ChatMovableDateCellModel.swift */, + 116634AB1C6F407D0072C980 /* ChatOutgoingCallCell.swift */, + 116634AE1C6F40820072C980 /* ChatOutgoingCallCellModel.swift */, + 11628E621CA57B14008C097E /* ChatOutgoingFileCell.swift */, + 11628E6B1CA57B19008C097E /* ChatOutgoingFileCellModel.swift */, + 11B252FD1C4A615E0068F47C /* ChatOutgoingTextCell.swift */, + 113187431DD63B6600E6FAA2 /* ChatOutgoingTextCellModel.swift */, + 1183BCDC1CA1FD55000CD310 /* ChatProgressBridge.swift */, + 1183BCD61CA1FC5B000CD310 /* ChatProgressProtocol.swift */, + 1193AB691C1F5C28006AA9E5 /* FriendListCell.swift */, + 1193AB6B1C1F5C31006AA9E5 /* FriendListCellModel.swift */, + 1156A4861C10D122005AC8C6 /* StaticTableAvatarCell.swift */, + 1156A4841C10D119005AC8C6 /* StaticTableAvatarCellModel.swift */, + 9C04BB6C1C17389200F58488 /* StaticTableBaseCell.swift */, + 1156A4781C0E478D005AC8C6 /* StaticTableBaseCellModel.swift */, + 1156A4801C0FA0A4005AC8C6 /* StaticTableButtonCell.swift */, + 1156A47A1C0F6178005AC8C6 /* StaticTableButtonCellModel.swift */, + 116513211C2C74940066AF06 /* StaticTableChatButtonsCell.swift */, + 116513231C2C749E0066AF06 /* StaticTableChatButtonsCellModel.swift */, + 115DFB891C177F5C00F18DB5 /* StaticTableDefaultCell.swift */, + 115DFB951C177F6500F18DB5 /* StaticTableDefaultCellModel.swift */, + 116634DF1C7B8D770072C980 /* StaticTableInfoCell.swift */, + 116634E81C7B8D7C0072C980 /* StaticTableInfoCellModel.swift */, + 116634EE1C7B94530072C980 /* StaticTableMultiChoiceButtonCell.swift */, + 116634F11C7B945A0072C980 /* StaticTableMultiChoiceButtonCellModel.swift */, + 1156A47C1C0F632C005AC8C6 /* StaticTableSelectableCellModel.swift */, + 11B253FA1C52C0A10068F47C /* StaticTableSwitchCell.swift */, + 11B253FD1C52C0AA0068F47C /* StaticTableSwitchCellModel.swift */, + ); + name = Cells; + sourceTree = ""; + }; + 119AD1CD1BDEE4A2000C5CB8 /* Login */ = { + isa = PBXGroup; + children = ( + 1164C8E61BC929C500B91107 /* LoginBaseController.swift */, + 1164C8E81BC929F700B91107 /* LoginChoiceController.swift */, + 9CBBC7C01BDFC62700099A5E /* LoginCreateAccountController.swift */, + 112950861D63AFD800C9CE0F /* LoginCreatePasswordController.swift */, + 9C07151E1BCD501D003A27B5 /* LoginFormController.swift */, + 112950831D63AFCE00C9CE0F /* LoginGenericCreateController.swift */, + 1164C8F21BC9880000B91107 /* LoginLogoController.swift */, + ); + name = Login; + sourceTree = ""; + }; + 119AD2081BEC718C000C5CB8 /* Sounds */ = { + isa = PBXGroup; + children = ( + 11B253491C4AD2200068F47C /* isotoxin_Calltone.aac */, + 11B2534A1C4AD23A0068F47C /* isotoxin_Hangup.aac */, + 11B2534B1C4AD23A0068F47C /* isotoxin_NewMessage.aac */, + 11B2534C1C4AD23A0068F47C /* isotoxin_Ringtone.aac */, + 11B2534D1C4AD23A0068F47C /* isotoxin_RingtoneWhileCall.aac */, + ); + name = Sounds; + sourceTree = ""; + }; + 11C33AB81DC961AB008DBC49 /* Login */ = { + isa = PBXGroup; + children = ( + 11C33AC31DC961DC008DBC49 /* LoginChoiceViewSnapshotTest.swift */, + ); + name = Login; + sourceTree = ""; + }; + 11CFCD091C2744E10046BD94 /* Enums */ = { + isa = PBXGroup; + children = ( + 11B253A31C4EA8040068F47C /* InterfaceIdiom.swift */, + AFA023F3274C069100FBFCC0 /* ConnectionStatus.swift */, + 11CFCD0A1C2745230046BD94 /* UserStatus.swift */, + ); + name = Enums; + sourceTree = ""; + }; + 11FA0ED61BC584A300F3DA5B /* Coordinators */ = { + isa = PBXGroup; + children = ( + 11FA0ED91BC584D900F3DA5B /* AppCoordinator.swift */, + 11FA0EDD1BC58DCC00F3DA5B /* CoordinatorProtocol.swift */, + 116DCE311CAAF47100B693EC /* TopCoordinatorProtocol.swift */, + 112950891D6851B600C9CE0F /* Login */, + 11FA0EE31BC59A9B00F3DA5B /* Running */, + ); + name = Coordinators; + sourceTree = ""; + }; + 11FA0EDF1BC591EA00F3DA5B /* Functions */ = { + isa = PBXGroup; + children = ( + 119AD1C91BDED6E9000C5CB8 /* ErrorHandling.swift */, + 9CDC092A1C34102F00DC0D63 /* ExceptionHandling.h */, + 9CDC092B1C34102F00DC0D63 /* ExceptionHandling.m */, + 11E640771C2DC15400D24C6D /* HelperFunctions.swift */, + 11FA0EE01BC591FC00F3DA5B /* Logger.swift */, + ); + name = Functions; + sourceTree = ""; + }; + 11FA0EE31BC59A9B00F3DA5B /* Running */ = { + isa = PBXGroup; + children = ( + 11FA0EE61BC59B1400F3DA5B /* ActiveSessionCoordinator.swift */, + 110E49DF1BF925FD00D1FE6F /* ActiveSessionNavigationCoordinator.swift */, + 11771E2B1CA5C3F200EC259E /* AutomationCoordinator.swift */, + 1180FD9F1C384E29005F3EA1 /* CallCoordinator.swift */, + 11FA0EF21BC5A6AF00F3DA5B /* ChatsTabCoordinator.swift */, + 11FA0EEA1BC5A68600F3DA5B /* FriendsTabCoordinator.swift */, + 9C2EF3701C4D4D5C006E7AB1 /* NotificationCoordinator.swift */, + 9C3271861D79C19C00347490 /* PinAuthorizationCoordinator.swift */, + 11FA0EEC1BC5A69000F3DA5B /* ProfileTabCoordinator.swift */, + 9CB1F9501D58CA4000105858 /* RunningCoordinator.swift */, + 11FA0EF01BC5A6A500F3DA5B /* SettingsTabCoordinator.swift */, + ); + name = Running; + sourceTree = ""; + }; + 4E4B267D27C0DC9800E07A66 /* CallManagement */ = { + isa = PBXGroup; + children = ( + 4E4B268A27C0DCBC00E07A66 /* ProviderDelegate.swift */, + 4E4B268427C0DCB500E07A66 /* CallManager.swift */, + 4E4B267E27C0DCAE00E07A66 /* Call.swift */, + ); + path = CallManagement; + sourceTree = ""; + }; + 9C7475C11BC698240098B1A4 /* Extensions */ = { + isa = PBXGroup; + children = ( + 1180FD9D1C38497A005F3EA1 /* NSDateFormatterExtension.swift */, + 11B253B61C503FA10068F47C /* NSTimerExtension.swift */, + 116DCE3A1CAAF85300B693EC /* NSURLExtension.swift */, + 11B9C6821BD598FC0083C2A5 /* OCTManagerConfigurationExtension.swift */, + 11FC105C1D32F29700CE863E /* OCTSubmanagerObjectsExtension.swift */, + 110E078E1EB0756C00B2CA9D /* ResultsExtension.swift */, + 9C7475C41BC698510098B1A4 /* StringExtension.swift */, + 11770D761CBC1C7A00D34D6E /* UIAlertControllerExtension.swift */, + 116634B11C7087A80072C980 /* UIApplicationExtension.swift */, + 119AD1CB1BDEDD9C000C5CB8 /* UIColorExtension.swift */, + 113F03321CB2E9C20009ABE1 /* UIFontExtension.swift */, + 1164C8EF1BC982FF00B91107 /* UIImageExtension.swift */, + 1164C8F51BC98F8300B91107 /* UIViewControllerExtension.swift */, + ); + name = Extensions; + sourceTree = ""; + }; + 9C9A06F51BE792E60003D6C7 /* Running */ = { + isa = PBXGroup; + children = ( + 11E640751C2DBAE200D24C6D /* AddFriendController.swift */, + 112E4EDE1C675C58004312CF /* CallActiveController.swift */, + 114962941C64051A001E5435 /* CallBaseController.swift */, + 112E4ED51C668C02004312CF /* CallIncomingController.swift */, + 11628E7A1CA5BF1F008C097E /* ChangeAutodownloadImagesController.swift */, + 114962911C5E1BE0001E5435 /* ChangePasswordController.swift */, + 116046181D8D434B002287C8 /* ChangePinTimeoutController.swift */, + 1149626B1C5CE3DF001E5435 /* ChangeUserStatusController.swift */, + 9CE0BDE51C45229500DCE357 /* ChatListController.swift */, + 11A21EFA1C45BDB100E80A89 /* ChatPrivateController.swift */, + 9C19367D1D79CF7E005EA0B2 /* EnterPinController.swift */, + 11AEBE701DA1876F00D04B59 /* FAQController.swift */, + 116513181C2C6C980066AF06 /* FriendCardController.swift */, + 1193AB471C1F4164006AA9E5 /* FriendListController.swift */, + 116634EB1C7B90F20072C980 /* FriendRequestController.swift */, + 11770D691CBC120C00D34D6E /* FriendSelectController.swift */, + 9CEE6AA11C4E679100A1ECB5 /* PrimaryIpadController.swift */, + 114962741C5CEB0B001E5435 /* ProfileDetailsController.swift */, + 9C9A07001BE793BA0003D6C7 /* ProfileMainController.swift */, + 113D56551C2F459E00B3D3E8 /* QRScannerController.swift */, + 1193AB411C1E2075006AA9E5 /* QRViewerController.swift */, + 11628E3D1CA30C13008C097E /* QuickLookPreviewController.swift */, + 9CEE6B4E1C528AAA00A1ECB5 /* SettingsAboutController.swift */, + 9CEE6B511C528AB600A1ECB5 /* SettingsAdvancedController.swift */, + 9CEE6B451C5289E200A1ECB5 /* SettingsMainController.swift */, + 110E425B1C00DC5E001A3CA2 /* StaticTableController.swift */, + 11B2535C1C4BACDB0068F47C /* TabBarController.swift */, + 1193AB351C1DEF2E006AA9E5 /* TextEditController.swift */, + 119AD1BD1BDED261000C5CB8 /* TextViewController.swift */, + ); + name = Running; + sourceTree = ""; + }; + AF2C929B279AB3F10094C08D /* pushextension */ = { + isa = PBXGroup; + children = ( + AF2C929C279AB3F10094C08D /* NotificationService.swift */, + AF2C929E279AB3F10094C08D /* Info.plist */, + ); + path = pushextension; + sourceTree = ""; + }; + D5C4D8B82C26B8F47A461D93 /* Pods */ = { + isa = PBXGroup; + children = ( + 2D5B916CEDBEC1B69CD1EFA4 /* Pods-Antidote.debug.xcconfig */, + B3C17AF8CE3B4AD1B68F2B5B /* Pods-Antidote.release.xcconfig */, + 43C533DEE94E80C981FEC348 /* Pods-AntidoteTests.debug.xcconfig */, + CEC32120B965BE40E0029DB1 /* Pods-AntidoteTests.release.xcconfig */, + 02404DE3D3BB1BF461C45EA0 /* Pods-ScreenshotsUITests.debug.xcconfig */, + 22DCF57E8F127B60BD096DD1 /* Pods-ScreenshotsUITests.release.xcconfig */, + ); + name = Pods; + sourceTree = ""; + }; + F902D28D1ADED27A0070A3F5 /* Application */ = { + isa = PBXGroup; + children = ( + 4E4EEA1E27DCECD3008B0E77 /* Bus.swift */, + 4E4EEA1827DCEC67008B0E77 /* LocationManager.swift */, + 11FA0ED21BC5842800F3DA5B /* Antidote-Bridging-Header.h */, + 9CDC093D1C3415DE00DC0D63 /* Antidote-Prefix.pch */, + 1164763A19794D3300DB20B8 /* Antidote-Info.plist */, + 11F08D171DE0610B00F80F5F /* InfoPlist.strings */, + 11FA0ED31BC5842800F3DA5B /* AppDelegate.swift */, + 1164764419794D3300DB20B8 /* Images.xcassets */, + 11D17CE81DD11F10006B2910 /* dummy-photo.jpg */, + 9CEA6A1E1D957EFC0045F000 /* antidote-acknowledgements.html */, + 1131D6C71CA9D8BC00B4531C /* import-profile.html */, + 1173F0711BC5D9DA00B88B7B /* default-theme.yaml */, + 9C7475C01BC698110098B1A4 /* Localizable.strings */, + 113E96461E4BB302000282FC /* AppStoreLocalizable.strings */, + 116634CE1C70E46C0072C980 /* Launch Screen.storyboard */, + ); + name = Application; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 111782A61DC64391000C1721 /* ScreenshotsUITests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 111782BA1DC64391000C1721 /* Build configuration list for PBXNativeTarget "ScreenshotsUITests" */; + buildPhases = ( + 6544AEF82D801AA2208FA2C0 /* [CP] Check Pods Manifest.lock */, + 111782A31DC64391000C1721 /* Sources */, + 111782A41DC64391000C1721 /* Frameworks */, + 111782A51DC64391000C1721 /* Resources */, + 008EF89EF3FF486967EBDAF6 /* [CP] Copy Pods Resources */, + ); + buildRules = ( + ); + dependencies = ( + 111782AD1DC64391000C1721 /* PBXTargetDependency */, + ); + name = ScreenshotsUITests; + productName = ScreenshotsUITests; + productReference = 111782A71DC64391000C1721 /* ScreenshotsUITests.xctest */; + productType = "com.apple.product-type.bundle.ui-testing"; + }; + 1164762E19794D3300DB20B8 /* Antidote */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1164765B19794D3300DB20B8 /* Build configuration list for PBXNativeTarget "Antidote" */; + buildPhases = ( + 0E40AAC10D854CCE59CF1B7F /* [CP] Check Pods Manifest.lock */, + 1164762B19794D3300DB20B8 /* Sources */, + 1164762C19794D3300DB20B8 /* Frameworks */, + 1164762D19794D3300DB20B8 /* Resources */, + F334EF7D7E56B63481570925 /* [CP] Copy Pods Resources */, + AF2C92A2279AB3F10094C08D /* Embed App Extensions */, + ); + buildRules = ( + ); + dependencies = ( + AF2C92A0279AB3F10094C08D /* PBXTargetDependency */, + ); + name = Antidote; + productName = Antidote; + productReference = 1164762F19794D3300DB20B8 /* Antidote.app */; + productType = "com.apple.product-type.application"; + }; + 1173F0551BC5D94400B88B7B /* AntidoteTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1173F05D1BC5D94400B88B7B /* Build configuration list for PBXNativeTarget "AntidoteTests" */; + buildPhases = ( + 0684EDB5CA4B84C1AF4AF8A4 /* [CP] Check Pods Manifest.lock */, + 1173F0521BC5D94400B88B7B /* Sources */, + 1173F0531BC5D94400B88B7B /* Frameworks */, + 1173F0541BC5D94400B88B7B /* Resources */, + B98298617DAB39F4AF6E0CCC /* [CP] Copy Pods Resources */, + ); + buildRules = ( + ); + dependencies = ( + 1173F05C1BC5D94400B88B7B /* PBXTargetDependency */, + ); + name = AntidoteTests; + productName = AntidoteTests; + productReference = 1173F0561BC5D94400B88B7B /* AntidoteTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + AF2C9299279AB3F10094C08D /* pushextension */ = { + isa = PBXNativeTarget; + buildConfigurationList = AF2C92A5279AB3F10094C08D /* Build configuration list for PBXNativeTarget "pushextension" */; + buildPhases = ( + AF2C9296279AB3F10094C08D /* Sources */, + AF2C9297279AB3F10094C08D /* Frameworks */, + AF2C9298279AB3F10094C08D /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = pushextension; + productName = pushextension; + productReference = AF2C929A279AB3F10094C08D /* pushextension.appex */; + productType = "com.apple.product-type.app-extension"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 1164762719794D3300DB20B8 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 1250; + LastUpgradeCheck = 1300; + ORGANIZATIONNAME = zoxcore; + TargetAttributes = { + 111782A61DC64391000C1721 = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 0820; + TestTargetID = 1164762E19794D3300DB20B8; + }; + 1164762E19794D3300DB20B8 = { + DevelopmentTeam = Y46L589C5C; + LastSwiftMigration = 0930; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.Keychain = { + enabled = 1; + }; + }; + }; + 1173F0551BC5D94400B88B7B = { + CreatedOnToolsVersion = 7.0; + LastSwiftMigration = 0930; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.BackgroundModes = { + enabled = 1; + }; + }; + TestTargetID = 1164762E19794D3300DB20B8; + }; + AF2C9299279AB3F10094C08D = { + CreatedOnToolsVersion = 12.5; + DevelopmentTeam = Y46L589C5C; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = 1164762A19794D3300DB20B8 /* Build configuration list for PBXProject "Antidote" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ru, + zh, + da, + de, + pt, + es, + ar, + br, + lt, + fr, + cs, + nl, + pl, + Base, + it, + ca, + ko, + nb, + "pt-BR", + el, + ); + mainGroup = 1164762619794D3300DB20B8; + productRefGroup = 1164763019794D3300DB20B8 /* Products */; + projectDirPath = ""; + projectReferences = ( + { + ProductGroup = 1173EFC91BC5C6B300B88B7B /* Products */; + ProjectRef = 1173EFC81BC5C6B300B88B7B /* SnapKit.xcodeproj */; + }, + { + ProductGroup = 1173EFE51BC5CF5D00B88B7B /* Products */; + ProjectRef = 1173EFE41BC5CF5D00B88B7B /* Yaml.xcodeproj */; + }, + ); + projectRoot = ""; + targets = ( + 1164762E19794D3300DB20B8 /* Antidote */, + 1173F0551BC5D94400B88B7B /* AntidoteTests */, + 111782A61DC64391000C1721 /* ScreenshotsUITests */, + AF2C9299279AB3F10094C08D /* pushextension */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXReferenceProxy section */ + 113F02F01CAFC9830009ABE1 /* Yaml.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = Yaml.framework; + remoteRef = 113F02EF1CAFC9830009ABE1 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 113F02F21CAFC9830009ABE1 /* Tests.xctest */ = { + isa = PBXReferenceProxy; + fileType = wrapper.cfbundle; + path = Tests.xctest; + remoteRef = 113F02F11CAFC9830009ABE1 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 1173EFD01BC5C6B300B88B7B /* SnapKit.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = SnapKit.framework; + remoteRef = 1173EFCF1BC5C6B300B88B7B /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 1173EFD41BC5C6B300B88B7B /* SnapKit Tests.xctest */ = { + isa = PBXReferenceProxy; + fileType = wrapper.cfbundle; + path = "SnapKit Tests.xctest"; + remoteRef = 1173EFD31BC5C6B300B88B7B /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 1173EFEC1BC5CF5D00B88B7B /* Yaml.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = Yaml.framework; + remoteRef = 1173EFEB1BC5CF5D00B88B7B /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 1173EFEE1BC5CF5D00B88B7B /* Tests.xctest */ = { + isa = PBXReferenceProxy; + fileType = wrapper.cfbundle; + path = Tests.xctest; + remoteRef = 1173EFED1BC5CF5D00B88B7B /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 1173EFF01BC5CF5D00B88B7B /* Yaml.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = Yaml.framework; + remoteRef = 1173EFEF1BC5CF5D00B88B7B /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 1173EFF21BC5CF5D00B88B7B /* Tests.xctest */ = { + isa = PBXReferenceProxy; + fileType = wrapper.cfbundle; + path = Tests.xctest; + remoteRef = 1173EFF11BC5CF5D00B88B7B /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; +/* End PBXReferenceProxy section */ + +/* Begin PBXResourcesBuildPhase section */ + 111782A51DC64391000C1721 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 115C3BD61DC6D2B900903A47 /* Localizable.strings in Resources */, + 11F08D151DE0610B00F80F5F /* InfoPlist.strings in Resources */, + 11D17CDD1DD11E58006B2910 /* Images.xcassets in Resources */, + 1143E4331DCE1A5600BE7250 /* import-profile.html in Resources */, + 111783101DC647BD000C1721 /* LaunchPlaceholderBoard.storyboard in Resources */, + 113E96441E4BB302000282FC /* AppStoreLocalizable.strings in Resources */, + 11D17CEA1DD11F10006B2910 /* dummy-photo.jpg in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1164762D19794D3300DB20B8 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 11D17CE91DD11F10006B2910 /* dummy-photo.jpg in Resources */, + 11F08D131DE0610B00F80F5F /* InfoPlist.strings in Resources */, + 113E96421E4BB302000282FC /* AppStoreLocalizable.strings in Resources */, + 11B253541C4AD9CF0068F47C /* isotoxin_RingtoneWhileCall.aac in Resources */, + 11B253501C4AD9CF0068F47C /* isotoxin_Calltone.aac in Resources */, + 11DDEAFD1D5FD9FE0000E2BE /* LaunchPlaceholderBoard.storyboard in Resources */, + 11B253531C4AD9CF0068F47C /* isotoxin_Ringtone.aac in Resources */, + 9C7475BE1BC698110098B1A4 /* Localizable.strings in Resources */, + 9CEA6A1F1D957EFC0045F000 /* antidote-acknowledgements.html in Resources */, + AFA024022753CC9000FBFCC0 /* GoogleService-Info.plist in Resources */, + 1173F0721BC5D9DA00B88B7B /* default-theme.yaml in Resources */, + 116634CF1C70E46C0072C980 /* Launch Screen.storyboard in Resources */, + 1131D6C51CA9D8BC00B4531C /* import-profile.html in Resources */, + 11B253521C4AD9CF0068F47C /* isotoxin_NewMessage.aac in Resources */, + 1164764519794D3300DB20B8 /* Images.xcassets in Resources */, + 11B253511C4AD9CF0068F47C /* isotoxin_Hangup.aac in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1173F0541BC5D94400B88B7B /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 113F03111CAFD1610009ABE1 /* icon.png in Resources */, + 11F08D141DE0610B00F80F5F /* InfoPlist.strings in Resources */, + 113E96431E4BB302000282FC /* AppStoreLocalizable.strings in Resources */, + 113F03081CAFCC9D0009ABE1 /* default-theme.yaml in Resources */, + 9CEA6A201D957EFC0045F000 /* antidote-acknowledgements.html in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + AF2C9298279AB3F10094C08D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 008EF89EF3FF486967EBDAF6 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-ScreenshotsUITests/Pods-ScreenshotsUITests-resources.sh", + "${PODS_ROOT}/JGProgressHUD/JGProgressHUD/JGProgressHUD/JGProgressHUD Resources.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/objcTox/objcTox.bundle", + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/JGProgressHUD Resources.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/objcTox.bundle", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ScreenshotsUITests/Pods-ScreenshotsUITests-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + 0684EDB5CA4B84C1AF4AF8A4 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-AntidoteTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 0E40AAC10D854CCE59CF1B7F /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Antidote-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 6544AEF82D801AA2208FA2C0 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-ScreenshotsUITests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + B98298617DAB39F4AF6E0CCC /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-AntidoteTests/Pods-AntidoteTests-resources.sh", + "${PODS_ROOT}/JGProgressHUD/JGProgressHUD/JGProgressHUD/JGProgressHUD Resources.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/objcTox/objcTox.bundle", + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/JGProgressHUD Resources.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/objcTox.bundle", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-AntidoteTests/Pods-AntidoteTests-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + F334EF7D7E56B63481570925 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Antidote/Pods-Antidote-resources.sh", + "${PODS_ROOT}/JGProgressHUD/JGProgressHUD/JGProgressHUD/JGProgressHUD Resources.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/objcTox/objcTox.bundle", + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/JGProgressHUD Resources.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/objcTox.bundle", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Antidote/Pods-Antidote-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 111782A31DC64391000C1721 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 111782F41DC64796000C1721 /* StaticTableDefaultCellModel.swift in Sources */, + 111783041DC6479E000C1721 /* ProfileManager.swift in Sources */, + 111783411DC64810000C1721 /* ExtendedTextField.swift in Sources */, + 111782BB1DC643A3000C1721 /* OCTManagerMock.swift in Sources */, + 1117830E1DC647BD000C1721 /* KeyboardNotificationController.swift in Sources */, + 1117830B1DC6479E000C1721 /* Theme.swift in Sources */, + 1117833F1DC64810000C1721 /* ChatPrivateTitleView.swift in Sources */, + 111783391DC647F8000C1721 /* HelperFunctions.swift in Sources */, + 1117834D1DC64810000C1721 /* StaticBackgroundView.swift in Sources */, + 113BBBA91EA88EAC00540E6C /* ChatTypingHeaderView.swift in Sources */, + 111782FD1DC6479E000C1721 /* AudioPlayer.swift in Sources */, + 111782F31DC64796000C1721 /* StaticTableDefaultCell.swift in Sources */, + 111782D41DC64796000C1721 /* ChatBaseTextCell.swift in Sources */, + 111783441DC64810000C1721 /* IncompressibleView.swift in Sources */, + 1117833B1DC647FF000C1721 /* Reach.swift in Sources */, + 1117832F1DC647E4000C1721 /* OCTSubmanagerObjectsExtension.swift in Sources */, + 111782C11DC643A3000C1721 /* OCTSubmanagerFriendsMock.swift in Sources */, + 111782FF1DC6479E000C1721 /* ChatListTableManager.swift in Sources */, + 1117832D1DC647E4000C1721 /* NSURLExtension.swift in Sources */, + 111783321DC647E4000C1721 /* UIApplicationExtension.swift in Sources */, + 111782EB1DC64796000C1721 /* StaticTableAvatarCell.swift in Sources */, + 111782F61DC64796000C1721 /* StaticTableInfoCellModel.swift in Sources */, + 111782F21DC64796000C1721 /* StaticTableChatButtonsCellModel.swift in Sources */, + 111783011DC6479E000C1721 /* FriendListDataSource.swift in Sources */, + 114D2D401E34D6E400662713 /* SnapshotHelper.swift in Sources */, + 111783291DC647DF000C1721 /* InterfaceIdiom.swift in Sources */, + 111782DC1DC64796000C1721 /* ChatIncomingFileCellModel.swift in Sources */, + 111782D91DC64796000C1721 /* ChatIncomingCallCell.swift in Sources */, + 1117832C1DC647E4000C1721 /* NSTimerExtension.swift in Sources */, + 111783461DC64810000C1721 /* iPadNavigationView.swift in Sources */, + 111783251DC647D9000C1721 /* PinAuthorizationCoordinator.swift in Sources */, + 111782E71DC64796000C1721 /* ChatProgressBridge.swift in Sources */, + 111783811DC64D75000C1721 /* SettingsMainController.swift in Sources */, + 1117834F1DC64810000C1721 /* ViewPassingGestures.swift in Sources */, + 111783281DC647D9000C1721 /* SettingsTabCoordinator.swift in Sources */, + 1117831C1DC647D4000C1721 /* LoginCoordinator.swift in Sources */, + 111782D81DC64796000C1721 /* ChatGenericFileCellModel.swift in Sources */, + 1117834B1DC64810000C1721 /* QRScannerAimView.swift in Sources */, + 111783071DC6479E000C1721 /* ResultsChange.swift in Sources */, + 1117830F1DC647BD000C1721 /* LaunchPlaceholderController.swift in Sources */, + 111783221DC647D9000C1721 /* ChatsTabCoordinator.swift in Sources */, + 115CE3EA1EB06F54001C08A0 /* ChatBottomStatusViewManager.swift in Sources */, + 111783701DC64D75000C1721 /* ChangePinTimeoutController.swift in Sources */, + 111783491DC64810000C1721 /* PinInputView.swift in Sources */, + 111783201DC647D9000C1721 /* AutomationCoordinator.swift in Sources */, + 111783271DC647D9000C1721 /* RunningCoordinator.swift in Sources */, + 111782EF1DC64796000C1721 /* StaticTableButtonCell.swift in Sources */, + 1117834E1DC64810000C1721 /* UserStatusView.swift in Sources */, + 111783231DC647D9000C1721 /* FriendsTabCoordinator.swift in Sources */, + 111782E61DC64796000C1721 /* ChatOutgoingTextCell.swift in Sources */, + 1117830C1DC6479E000C1721 /* ToxFactory.swift in Sources */, + 1117831D1DC647D4000C1721 /* LoginCreateAccountCoordinator.swift in Sources */, + 111782C01DC643A3000C1721 /* OCTSubmanagerFilesMock.swift in Sources */, + 111783791DC64D75000C1721 /* FriendSelectController.swift in Sources */, + 111783691DC64D50000C1721 /* QuickLookPreviewController.swift in Sources */, + 1117832B1DC647E4000C1721 /* NSDateFormatterExtension.swift in Sources */, + 111782FE1DC6479E000C1721 /* AvatarManager.swift in Sources */, + 111783841DC64D75000C1721 /* TextEditController.swift in Sources */, + 111783471DC64810000C1721 /* LoadingImageView.swift in Sources */, + 111783021DC6479E000C1721 /* KeychainManager.swift in Sources */, + 111783771DC64D75000C1721 /* FriendListController.swift in Sources */, + 1124953F1DE7AC0400EF45C4 /* KeyboardObserver.swift in Sources */, + 111783261DC647D9000C1721 /* ProfileTabCoordinator.swift in Sources */, + 1117836D1DC64D75000C1721 /* CallActiveController.swift in Sources */, + 111782EA1DC64796000C1721 /* FriendListCellModel.swift in Sources */, + 111782D71DC64796000C1721 /* ChatGenericFileCell.swift in Sources */, + 111783381DC647F8000C1721 /* ExceptionHandling.m in Sources */, + 1117837D1DC64D75000C1721 /* QRScannerController.swift in Sources */, + 1105B18F1EA09B1A0035B213 /* ChatFauxOfflineHeaderView.swift in Sources */, + 111783091DC6479E000C1721 /* TabBarBadgeItem.swift in Sources */, + 1117836B1DC64D68000C1721 /* CallBaseController.swift in Sources */, + 111782DA1DC64796000C1721 /* ChatIncomingCallCellModel.swift in Sources */, + 110E07911EB0756C00B2CA9D /* ResultsExtension.swift in Sources */, + 111783451DC64810000C1721 /* iPadFriendsButton.swift in Sources */, + 111782DE1DC64796000C1721 /* ChatListCell.swift in Sources */, + 111782FB1DC64796000C1721 /* StaticTableSwitchCellModel.swift in Sources */, + 111783711DC64D75000C1721 /* ChangeUserStatusController.swift in Sources */, + 1117832E1DC647E4000C1721 /* OCTManagerConfigurationExtension.swift in Sources */, + 111783151DC647C1000C1721 /* LoginCreatePasswordController.swift in Sources */, + 1117836F1DC64D75000C1721 /* ChangePasswordController.swift in Sources */, + 1117834C1DC64810000C1721 /* RoundedButton.swift in Sources */, + 111783341DC647E4000C1721 /* UIFontExtension.swift in Sources */, + 1117834A1DC64810000C1721 /* ProgressCircleView.swift in Sources */, + 111783061DC6479E000C1721 /* Results.swift in Sources */, + 113187461DD63B6600E6FAA2 /* ChatOutgoingTextCellModel.swift in Sources */, + 111783421DC64810000C1721 /* FullscreenPicker.swift in Sources */, + 111783751DC64D75000C1721 /* FAQController.swift in Sources */, + 111782F81DC64796000C1721 /* StaticTableMultiChoiceButtonCellModel.swift in Sources */, + 111782E91DC64796000C1721 /* FriendListCell.swift in Sources */, + 1117833A1DC647F8000C1721 /* Logger.swift in Sources */, + 1117831E1DC647D9000C1721 /* ActiveSessionCoordinator.swift in Sources */, + 111782F71DC64796000C1721 /* StaticTableMultiChoiceButtonCell.swift in Sources */, + 111782D21DC64796000C1721 /* BaseCell.swift in Sources */, + 111783171DC647C1000C1721 /* LoginGenericCreateController.swift in Sources */, + 11687F2E1DC64F0D0029B93F /* AppDelegate.swift in Sources */, + 111783311DC647E4000C1721 /* UIAlertControllerExtension.swift in Sources */, + 111783431DC64810000C1721 /* ImageViewWithStatus.swift in Sources */, + 111782BE1DC643A3000C1721 /* OCTSubmanagerChatsMock.swift in Sources */, + 1117836C1DC64D75000C1721 /* AddFriendController.swift in Sources */, + 111782E11DC64796000C1721 /* ChatMovableDateCellModel.swift in Sources */, + 111782F51DC64796000C1721 /* StaticTableInfoCell.swift in Sources */, + 111782D61DC64796000C1721 /* ChatEditable.swift in Sources */, + 1117831F1DC647D9000C1721 /* ActiveSessionNavigationCoordinator.swift in Sources */, + 111783131DC647C1000C1721 /* LoginChoiceController.swift in Sources */, + 111782ED1DC64796000C1721 /* StaticTableBaseCell.swift in Sources */, + 111783141DC647C1000C1721 /* LoginCreateAccountController.swift in Sources */, + 1117836A1DC64D5A000C1721 /* CallIncomingController.swift in Sources */, + 111782EE1DC64796000C1721 /* StaticTableBaseCellModel.swift in Sources */, + 9CDE31E81E489B2700333E0D /* ChatInputViewManager.swift in Sources */, + 1117837A1DC64D75000C1721 /* PrimaryIpadController.swift in Sources */, + 111783731DC64D75000C1721 /* ChatPrivateController.swift in Sources */, + 111783121DC647C1000C1721 /* LoginBaseController.swift in Sources */, + 111782E01DC64796000C1721 /* ChatMovableDateCell.swift in Sources */, + 111782DD1DC64796000C1721 /* ChatIncomingTextCell.swift in Sources */, + 111783831DC64D75000C1721 /* TabBarController.swift in Sources */, + 111783211DC647D9000C1721 /* CallCoordinator.swift in Sources */, + 111783161DC647C1000C1721 /* LoginFormController.swift in Sources */, + 111782E21DC64796000C1721 /* ChatOutgoingCallCell.swift in Sources */, + 111783851DC64D75000C1721 /* TextViewController.swift in Sources */, + 111783821DC64D75000C1721 /* StaticTableController.swift in Sources */, + 111782E31DC64796000C1721 /* ChatOutgoingCallCellModel.swift in Sources */, + 111782DB1DC64796000C1721 /* ChatIncomingFileCell.swift in Sources */, + 111782FC1DC6479E000C1721 /* AlertAudioPlayer.swift in Sources */, + 111783191DC647CF000C1721 /* AppCoordinator.swift in Sources */, + 1117830A1DC6479E000C1721 /* TabBarProfileItem.swift in Sources */, + 111782F91DC64796000C1721 /* StaticTableSelectableCellModel.swift in Sources */, + 111783741DC64D75000C1721 /* EnterPinController.swift in Sources */, + 1117833C1DC64810000C1721 /* BubbleView.swift in Sources */, + 1117831A1DC647CF000C1721 /* CoordinatorProtocol.swift in Sources */, + 1117837E1DC64D75000C1721 /* QRViewerController.swift in Sources */, + 1117836E1DC64D75000C1721 /* ChangeAutodownloadImagesController.swift in Sources */, + 111782BC1DC643A3000C1721 /* OCTSubmanagerBootstrapMock.swift in Sources */, + 111782D51DC64796000C1721 /* ChatBaseTextCellModel.swift in Sources */, + 111783241DC647D9000C1721 /* NotificationCoordinator.swift in Sources */, + 111782DF1DC64796000C1721 /* ChatListCellModel.swift in Sources */, + 111783111DC647BD000C1721 /* PortraitNavigationController.swift in Sources */, + 111782F01DC64796000C1721 /* StaticTableButtonCellModel.swift in Sources */, + 111783031DC6479E000C1721 /* NotificationObject.swift in Sources */, + 111783761DC64D75000C1721 /* FriendCardController.swift in Sources */, + 111783051DC6479E000C1721 /* ProfileSettings.swift in Sources */, + 111782AA1DC64391000C1721 /* ScreenshotsUITests.swift in Sources */, + 111783781DC64D75000C1721 /* FriendRequestController.swift in Sources */, + 111782E51DC64796000C1721 /* ChatOutgoingFileCellModel.swift in Sources */, + 111782BD1DC643A3000C1721 /* OCTSubmanagerCallsMock.swift in Sources */, + 111783371DC647F8000C1721 /* ErrorHandling.swift in Sources */, + 1117832A1DC647DF000C1721 /* UserStatus.swift in Sources */, + 111783001DC6479E000C1721 /* FilePreviewControllerDataSource.swift in Sources */, + 111783301DC647E4000C1721 /* StringExtension.swift in Sources */, + 111783331DC647E4000C1721 /* UIColorExtension.swift in Sources */, + 1117831B1DC647CF000C1721 /* TopCoordinatorProtocol.swift in Sources */, + 111783361DC647E4000C1721 /* UIViewControllerExtension.swift in Sources */, + 111783721DC64D75000C1721 /* ChatListController.swift in Sources */, + 111783801DC64D75000C1721 /* SettingsAdvancedController.swift in Sources */, + 1117833D1DC64810000C1721 /* CallButton.swift in Sources */, + 111783481DC64810000C1721 /* NotificationWindow.swift in Sources */, + 111782FA1DC64796000C1721 /* StaticTableSwitchCell.swift in Sources */, + 111783401DC64810000C1721 /* CopyLabel.swift in Sources */, + 111782C31DC643A3000C1721 /* OCTSubmanagerUserMock.swift in Sources */, + 111782E81DC64796000C1721 /* ChatProgressProtocol.swift in Sources */, + 111782E41DC64796000C1721 /* ChatOutgoingFileCell.swift in Sources */, + 111782F11DC64796000C1721 /* StaticTableChatButtonsCell.swift in Sources */, + 111783351DC647E4000C1721 /* UIImageExtension.swift in Sources */, + 1117837B1DC64D75000C1721 /* ProfileDetailsController.swift in Sources */, + 1117837C1DC64D75000C1721 /* ProfileMainController.swift in Sources */, + 111783181DC647C1000C1721 /* LoginLogoController.swift in Sources */, + 1117830D1DC6479E000C1721 /* UserDefaultsManager.swift in Sources */, + 111783081DC6479E000C1721 /* TabBarAbstractItem.swift in Sources */, + 111782C21DC643A3000C1721 /* OCTSubmanagerObjectsMock.swift in Sources */, + 111782EC1DC64796000C1721 /* StaticTableAvatarCellModel.swift in Sources */, + 1117837F1DC64D75000C1721 /* SettingsAboutController.swift in Sources */, + 111782D31DC64796000C1721 /* BaseCellModel.swift in Sources */, + 1117833E1DC64810000C1721 /* ChatInputView.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1164762B19794D3300DB20B8 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 11628E721CA580ED008C097E /* ChatGenericFileCell.swift in Sources */, + 116634AF1C6F40820072C980 /* ChatOutgoingCallCellModel.swift in Sources */, + 116634B21C7087A80072C980 /* UIApplicationExtension.swift in Sources */, + 113187441DD63B6600E6FAA2 /* ChatOutgoingTextCellModel.swift in Sources */, + 1117828D1DC531AD000C1721 /* OCTSubmanagerChatsMock.swift in Sources */, + 11A21EFD1C45BDF200E80A89 /* ChatInputView.swift in Sources */, + 1183BCB51CA1B3AE000CD310 /* ChatIncomingFileCellModel.swift in Sources */, + 110E425C1C00DC5E001A3CA2 /* StaticTableController.swift in Sources */, + 11FC105A1D32EED000CE863E /* ResultsChange.swift in Sources */, + 114962751C5CEB0B001E5435 /* ProfileDetailsController.swift in Sources */, + 11FC105D1D32F29700CE863E /* OCTSubmanagerObjectsExtension.swift in Sources */, + 11628E321CA2FBD1008C097E /* FilePreviewControllerDataSource.swift in Sources */, + 113D564D1C2F437B00B3D3E8 /* QRScannerAimView.swift in Sources */, + 1193AB361C1DEF2E006AA9E5 /* TextEditController.swift in Sources */, + 11B252FA1C4A614D0068F47C /* ChatIncomingTextCell.swift in Sources */, + 4E4B268527C0DCB500E07A66 /* CallManager.swift in Sources */, + 116513241C2C749E0066AF06 /* StaticTableChatButtonsCellModel.swift in Sources */, + 116634A01C6E8D0F0072C980 /* ChatIncomingCallCell.swift in Sources */, + 112E4EE51C676553004312CF /* CallButton.swift in Sources */, + 11771E361CA5C6E900EC259E /* Reach.swift in Sources */, + 112950871D63AFD800C9CE0F /* LoginCreatePasswordController.swift in Sources */, + 9CEE6B1F1C510A1E00A1ECB5 /* NotificationObject.swift in Sources */, + 1156A4871C10D122005AC8C6 /* StaticTableAvatarCell.swift in Sources */, + 11E640761C2DBAE200D24C6D /* AddFriendController.swift in Sources */, + 9CDC092C1C34102F00DC0D63 /* ExceptionHandling.m in Sources */, + 9CE0BDF31C4522C800DCE357 /* ChatListCellModel.swift in Sources */, + 11CFCD111C2A02350046BD94 /* StaticBackgroundView.swift in Sources */, + 111782961DC53458000C1721 /* OCTSubmanagerFriendsMock.swift in Sources */, + 111782991DC53545000C1721 /* OCTSubmanagerObjectsMock.swift in Sources */, + 1183BCAC1CA1B398000CD310 /* ChatIncomingFileCell.swift in Sources */, + 112E4ED61C668C02004312CF /* CallIncomingController.swift in Sources */, + 4E3D0F9527C9751300D5A068 /* LinearProgressBar.swift in Sources */, + 116634E91C7B8D7C0072C980 /* StaticTableInfoCellModel.swift in Sources */, + 11CFCD0D1C27488E0046BD94 /* ImageViewWithStatus.swift in Sources */, + 11B2535D1C4BACDB0068F47C /* TabBarController.swift in Sources */, + 9CB1F9511D58CA4000105858 /* RunningCoordinator.swift in Sources */, + 4E4EEA1927DCEC67008B0E77 /* LocationManager.swift in Sources */, + 11628E6C1CA57B19008C097E /* ChatOutgoingFileCellModel.swift in Sources */, + 9CBBC7C11BDFC62700099A5E /* LoginCreateAccountController.swift in Sources */, + 116DCE3B1CAAF85300B693EC /* NSURLExtension.swift in Sources */, + 1183BCDD1CA1FD55000CD310 /* ChatProgressBridge.swift in Sources */, + 11E640781C2DC15400D24C6D /* HelperFunctions.swift in Sources */, + 11FA0EEB1BC5A68600F3DA5B /* FriendsTabCoordinator.swift in Sources */, + 1164C8F01BC982FF00B91107 /* UIImageExtension.swift in Sources */, + 4E4B267F27C0DCAE00E07A66 /* Call.swift in Sources */, + 9CEE6B461C5289E200A1ECB5 /* SettingsMainController.swift in Sources */, + 9CE0BDF01C4522BF00DCE357 /* ChatListCell.swift in Sources */, + 116513261C2D636A0066AF06 /* NotificationWindow.swift in Sources */, + 1117829C1DC5363C000C1721 /* OCTSubmanagerUserMock.swift in Sources */, + 11B253AE1C4EC47D0068F47C /* IncompressibleView.swift in Sources */, + 11F276BB1D3EBF3000C613AA /* ChatBaseTextCellModel.swift in Sources */, + 11628E3E1CA30C13008C097E /* QuickLookPreviewController.swift in Sources */, + 1105B18D1EA09B1A0035B213 /* ChatFauxOfflineHeaderView.swift in Sources */, + 1164C8ED1BC9801200B91107 /* RoundedButton.swift in Sources */, + 11FA0EF11BC5A6A500F3DA5B /* SettingsTabCoordinator.swift in Sources */, + 1156A4891C15FB2B005AC8C6 /* AvatarManager.swift in Sources */, + 119AD1CA1BDED6E9000C5CB8 /* ErrorHandling.swift in Sources */, + 9C2EF3711C4D4D5C006E7AB1 /* NotificationCoordinator.swift in Sources */, + 1156A4811C0FA0A4005AC8C6 /* StaticTableButtonCell.swift in Sources */, + 11B2536D1C4BAD5D0068F47C /* TabBarProfileItem.swift in Sources */, + 11B253A41C4EA8040068F47C /* InterfaceIdiom.swift in Sources */, + 11FA0EE91BC5A66D00F3DA5B /* LoginCoordinator.swift in Sources */, + 111782781DC52BDB000C1721 /* OCTManagerMock.swift in Sources */, + 11AEBE711DA1876F00D04B59 /* FAQController.swift in Sources */, + 11B253141C4A79A50068F47C /* BubbleView.swift in Sources */, + 11B252FE1C4A615E0068F47C /* ChatOutgoingTextCell.swift in Sources */, + 112950841D63AFCE00C9CE0F /* LoginGenericCreateController.swift in Sources */, + 116634EC1C7B90F20072C980 /* FriendRequestController.swift in Sources */, + 11CFCD0B1C2745230046BD94 /* UserStatus.swift in Sources */, + 11B253021C4A61D00068F47C /* ChatMovableDateCell.swift in Sources */, + 11B253041C4A61D50068F47C /* ChatMovableDateCellModel.swift in Sources */, + 1164C8F61BC98F8300B91107 /* UIViewControllerExtension.swift in Sources */, + 11FA0EF31BC5A6AF00F3DA5B /* ChatsTabCoordinator.swift in Sources */, + 11B253561C4AEA400068F47C /* ChatPrivateTitleView.swift in Sources */, + 1173F06E1BC5D9BA00B88B7B /* Theme.swift in Sources */, + 4E4EEA1F27DCECD3008B0E77 /* Bus.swift in Sources */, + 1193AB481C1F4164006AA9E5 /* FriendListController.swift in Sources */, + 11CFCD0F1C27499D0046BD94 /* UserStatusView.swift in Sources */, + 9CEE6B4F1C528AAA00A1ECB5 /* SettingsAboutController.swift in Sources */, + 113F03331CB2E9C20009ABE1 /* UIFontExtension.swift in Sources */, + 11F276AE1D3EBEF700C613AA /* ChatBaseTextCell.swift in Sources */, + 4E4B268B27C0DCBC00E07A66 /* ProviderDelegate.swift in Sources */, + 1193AB6A1C1F5C28006AA9E5 /* FriendListCell.swift in Sources */, + 9CBBC7CD1BDFC6C600099A5E /* ExtendedTextField.swift in Sources */, + 11B9C6971BD80B080083C2A5 /* FullscreenPicker.swift in Sources */, + 9C07151D1BCD2E5B003A27B5 /* PortraitNavigationController.swift in Sources */, + 11FA0EED1BC5A69000F3DA5B /* ProfileTabCoordinator.swift in Sources */, + 1156A4851C10D119005AC8C6 /* StaticTableAvatarCellModel.swift in Sources */, + 116634AC1C6F407D0072C980 /* ChatOutgoingCallCell.swift in Sources */, + 113AD8571CA9C70F00D981B5 /* iPadFriendsButton.swift in Sources */, + 1156A4791C0E478D005AC8C6 /* StaticTableBaseCellModel.swift in Sources */, + 9CEE6AA21C4E679100A1ECB5 /* PrimaryIpadController.swift in Sources */, + 112422661BDD2032004D7926 /* KeyboardNotificationController.swift in Sources */, + 11B2536A1C4BAD560068F47C /* TabBarBadgeItem.swift in Sources */, + 113D56561C2F459E00B3D3E8 /* QRScannerController.swift in Sources */, + 116513191C2C6C980066AF06 /* FriendCardController.swift in Sources */, + 9C1FEB291D8C10EB008C2ADE /* ProfileSettings.swift in Sources */, + 9C07151F1BCD501D003A27B5 /* LoginFormController.swift in Sources */, + 11FA0EE71BC59B1400F3DA5B /* ActiveSessionCoordinator.swift in Sources */, + 1164C8F31BC9880000B91107 /* LoginLogoController.swift in Sources */, + 11B253FE1C52C0AA0068F47C /* StaticTableSwitchCellModel.swift in Sources */, + 119AD1CC1BDEDD9C000C5CB8 /* UIColorExtension.swift in Sources */, + 1117829F1DC53AB4000C1721 /* ToxFactory.swift in Sources */, + 9CDE31E61E489B2700333E0D /* ChatInputViewManager.swift in Sources */, + 115DFB8A1C177F5C00F18DB5 /* StaticTableDefaultCell.swift in Sources */, + 9C7475C51BC698510098B1A4 /* StringExtension.swift in Sources */, + 1193AB661C1F5694006AA9E5 /* BaseCell.swift in Sources */, + 1156A47D1C0F632C005AC8C6 /* StaticTableSelectableCellModel.swift in Sources */, + 111782931DC53371000C1721 /* OCTSubmanagerFilesMock.swift in Sources */, + 114962951C64051A001E5435 /* CallBaseController.swift in Sources */, + 115DFB961C177F6500F18DB5 /* StaticTableDefaultCellModel.swift in Sources */, + 1160B68B1D5FD8DE002DF75B /* LaunchPlaceholderController.swift in Sources */, + 1183BCD71CA1FC5B000CD310 /* ChatProgressProtocol.swift in Sources */, + 1117827B1DC52C3A000C1721 /* OCTSubmanagerBootstrapMock.swift in Sources */, + 1193AB681C1F569A006AA9E5 /* BaseCellModel.swift in Sources */, + 11771E2C1CA5C3F200EC259E /* AutomationCoordinator.swift in Sources */, + 11FC10571D32E54A00CE863E /* Results.swift in Sources */, + 11FA0EDA1BC584D900F3DA5B /* AppCoordinator.swift in Sources */, + 9C19367E1D79CF7E005EA0B2 /* EnterPinController.swift in Sources */, + 11770D6A1CBC120C00D34D6E /* FriendSelectController.swift in Sources */, + 1193AB421C1E2075006AA9E5 /* QRViewerController.swift in Sources */, + 9CEE6B521C528AB600A1ECB5 /* SettingsAdvancedController.swift in Sources */, + AFA023F4274C069100FBFCC0 /* ConnectionStatus.swift in Sources */, + 116634E01C7B8D770072C980 /* StaticTableInfoCell.swift in Sources */, + 119AD1BE1BDED261000C5CB8 /* TextViewController.swift in Sources */, + 1156A47B1C0F6178005AC8C6 /* StaticTableButtonCellModel.swift in Sources */, + 11B9C6831BD598FC0083C2A5 /* OCTManagerConfigurationExtension.swift in Sources */, + 110E49E01BF925FD00D1FE6F /* ActiveSessionNavigationCoordinator.swift in Sources */, + 1164C8D81BC922EB00B91107 /* UserDefaultsManager.swift in Sources */, + 11770D771CBC1C7A00D34D6E /* UIAlertControllerExtension.swift in Sources */, + 9C3271871D79C19C00347490 /* PinAuthorizationCoordinator.swift in Sources */, + 1109019B1D83417500BC5751 /* PinInputView.swift in Sources */, + 1180FDA01C384E29005F3EA1 /* CallCoordinator.swift in Sources */, + 110E078F1EB0756C00B2CA9D /* ResultsExtension.swift in Sources */, + 11FA0ED41BC5842800F3DA5B /* AppDelegate.swift in Sources */, + 11B253FB1C52C0A10068F47C /* StaticTableSwitchCell.swift in Sources */, + 113F03421CB31DD60009ABE1 /* AlertAudioPlayer.swift in Sources */, + 116634D91C70F1260072C980 /* CopyLabel.swift in Sources */, + 113BBBA71EA88EAC00540E6C /* ChatTypingHeaderView.swift in Sources */, + 1193AB6C1C1F5C31006AA9E5 /* FriendListCellModel.swift in Sources */, + 11B253661C4BAD3C0068F47C /* TabBarAbstractItem.swift in Sources */, + 113AD84A1CA97A3000D981B5 /* iPadNavigationView.swift in Sources */, + 116634F21C7B945A0072C980 /* StaticTableMultiChoiceButtonCellModel.swift in Sources */, + 11B2534F1C4AD2550068F47C /* AudioPlayer.swift in Sources */, + 9C04BB6D1C17389200F58488 /* StaticTableBaseCell.swift in Sources */, + 1129508B1D6851EB00C9CE0F /* LoginCreateAccountCoordinator.swift in Sources */, + 11B253B71C503FA10068F47C /* NSTimerExtension.swift in Sources */, + 9CE0BDE61C45229500DCE357 /* ChatListController.swift in Sources */, + 11E6406D1C2D6C3500D24C6D /* ViewPassingGestures.swift in Sources */, + 1136605C1CDE5D5E0092C27A /* ChatEditable.swift in Sources */, + 11628E7B1CA5BF1F008C097E /* ChangeAutodownloadImagesController.swift in Sources */, + 116513221C2C74940066AF06 /* StaticTableChatButtonsCell.swift in Sources */, + 9C9A07011BE793BA0003D6C7 /* ProfileMainController.swift in Sources */, + 11628E631CA57B14008C097E /* ChatOutgoingFileCell.swift in Sources */, + 112495371DE7ABFF00EF45C4 /* KeyboardObserver.swift in Sources */, + 116DCE321CAAF47100B693EC /* TopCoordinatorProtocol.swift in Sources */, + 1180FD9E1C38497A005F3EA1 /* NSDateFormatterExtension.swift in Sources */, + 9CDDB2061BD5376200B65D79 /* ProfileManager.swift in Sources */, + 1160B67E1D5F9993002DF75B /* KeychainManager.swift in Sources */, + 116046191D8D434B002287C8 /* ChangePinTimeoutController.swift in Sources */, + 114962921C5E1BE0001E5435 /* ChangePasswordController.swift in Sources */, + 9C2EF37A1C4E2DDE006E7AB1 /* ChatListTableManager.swift in Sources */, + 112E4EDF1C675C58004312CF /* CallActiveController.swift in Sources */, + 11628E751CA5811C008C097E /* ChatGenericFileCellModel.swift in Sources */, + 11A21EFB1C45BDB100E80A89 /* ChatPrivateController.swift in Sources */, + 1164C8E91BC929F700B91107 /* LoginChoiceController.swift in Sources */, + 1117827E1DC52CBA000C1721 /* OCTSubmanagerCallsMock.swift in Sources */, + 1149626C1C5CE3DF001E5435 /* ChangeUserStatusController.swift in Sources */, + 115CE3E81EB06F54001C08A0 /* ChatBottomStatusViewManager.swift in Sources */, + 116634EF1C7B94530072C980 /* StaticTableMultiChoiceButtonCell.swift in Sources */, + 116634A91C6E8D1A0072C980 /* ChatIncomingCallCellModel.swift in Sources */, + 11FA0EDE1BC58DCC00F3DA5B /* CoordinatorProtocol.swift in Sources */, + 11FA0EE11BC591FC00F3DA5B /* Logger.swift in Sources */, + 1164C8E71BC929C500B91107 /* LoginBaseController.swift in Sources */, + 9CDC091B1C34081900DC0D63 /* FriendListDataSource.swift in Sources */, + 1183BCC01CA1DB05000CD310 /* ProgressCircleView.swift in Sources */, + 11628E781CA5819B008C097E /* LoadingImageView.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1173F0521BC5D94400B88B7B /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 9CEE6ACC1C4E8FDC00A1ECB5 /* StaticTableChatButtonsCellModel.swift in Sources */, + 9CEE6AFC1C4E8FDC00A1ECB5 /* ChatsTabCoordinator.swift in Sources */, + 1183BCC71CA1DB09000CD310 /* ProgressCircleView.swift in Sources */, + 9CEE6AD91C4E8FDC00A1ECB5 /* TabBarProfileItem.swift in Sources */, + 112E4EE61C676553004312CF /* CallButton.swift in Sources */, + 113AD8581CA9C70F00D981B5 /* iPadFriendsButton.swift in Sources */, + 9CEE6B181C4E8FDC00A1ECB5 /* RoundedButton.swift in Sources */, + 11B253A51C4EA8040068F47C /* InterfaceIdiom.swift in Sources */, + 9C3271881D79C19C00347490 /* PinAuthorizationCoordinator.swift in Sources */, + 116634EA1C7B8D7C0072C980 /* StaticTableInfoCellModel.swift in Sources */, + 9CEE6B201C510A1E00A1ECB5 /* NotificationObject.swift in Sources */, + 113F03341CB2E9C20009ABE1 /* UIFontExtension.swift in Sources */, + 112E4EE01C675C58004312CF /* CallActiveController.swift in Sources */, + 9CEE6B161C4E8FDC00A1ECB5 /* UserStatusView.swift in Sources */, + 9CEE6AE21C4E8FDC00A1ECB5 /* LoginLogoController.swift in Sources */, + 9CEE6B191C4E8FDC00A1ECB5 /* ExtendedTextField.swift in Sources */, + 111782A01DC53AB4000C1721 /* ToxFactory.swift in Sources */, + 9CEE6ABA1C4E8FDC00A1ECB5 /* BaseCellModel.swift in Sources */, + 1117829A1DC53545000C1721 /* OCTSubmanagerObjectsMock.swift in Sources */, + 9CEE6B0C1C4E8FDC00A1ECB5 /* HelperFunctions.swift in Sources */, + 113F03231CAFE5190009ABE1 /* ChatOutgoingTextCellSnapshotTest.swift in Sources */, + 116634E11C7B8D770072C980 /* StaticTableInfoCell.swift in Sources */, + 11771E2D1CA5C3F200EC259E /* AutomationCoordinator.swift in Sources */, + 11628E331CA2FBD1008C097E /* FilePreviewControllerDataSource.swift in Sources */, + 9CEE6B531C528AB600A1ECB5 /* SettingsAdvancedController.swift in Sources */, + 113F031F1CAFE2130009ABE1 /* ChatOutgoingCallCellSnapshotTest.swift in Sources */, + 116634A11C6E8D0F0072C980 /* ChatIncomingCallCell.swift in Sources */, + 116DCE3C1CAAF85300B693EC /* NSURLExtension.swift in Sources */, + 9CEE6AEB1C4E8FDC00A1ECB5 /* FriendListController.swift in Sources */, + 9CEE6AC81C4E8FDC00A1ECB5 /* StaticTableBaseCellModel.swift in Sources */, + 1183BCDE1CA1FD55000CD310 /* ChatProgressBridge.swift in Sources */, + 9CEE6AD71C4E8FDC00A1ECB5 /* TabBarAbstractItem.swift in Sources */, + 9CEE6ABB1C4E8FDC00A1ECB5 /* ChatIncomingTextCell.swift in Sources */, + 11AEBE721DA1876F00D04B59 /* FAQController.swift in Sources */, + 9CEE6AC51C4E8FDC00A1ECB5 /* StaticTableAvatarCell.swift in Sources */, + 9CEE6AB81C4E8FDC00A1ECB5 /* AppDelegate.swift in Sources */, + 9CEE6AE11C4E8FDC00A1ECB5 /* LoginFormController.swift in Sources */, + 1117827C1DC52C3A000C1721 /* OCTSubmanagerBootstrapMock.swift in Sources */, + 11FC10581D32E54A00CE863E /* Results.swift in Sources */, + 11771E371CA5C6E900EC259E /* Reach.swift in Sources */, + 9CEE6ACE1C4E8FDC00A1ECB5 /* StaticTableDefaultCellModel.swift in Sources */, + 9CEE6B091C4E8FDC00A1ECB5 /* UIColorExtension.swift in Sources */, + 9CEE6B501C528AAA00A1ECB5 /* SettingsAboutController.swift in Sources */, + 11628E6D1CA57B19008C097E /* ChatOutgoingFileCellModel.swift in Sources */, + 9CEE6AC61C4E8FDC00A1ECB5 /* StaticTableAvatarCellModel.swift in Sources */, + 114962931C5E1BE0001E5435 /* ChangePasswordController.swift in Sources */, + 11628E641CA57B14008C097E /* ChatOutgoingFileCell.swift in Sources */, + 1183BCAD1CA1B398000CD310 /* ChatIncomingFileCell.swift in Sources */, + 113187451DD63B6600E6FAA2 /* ChatOutgoingTextCellModel.swift in Sources */, + 9CEE6AF21C4E8FDC00A1ECB5 /* TabBarController.swift in Sources */, + 9CEE6B051C4E8FDC00A1ECB5 /* OCTManagerConfigurationExtension.swift in Sources */, + 9CEE6AE01C4E8FDC00A1ECB5 /* LoginCreateAccountController.swift in Sources */, + 1117828E1DC531AD000C1721 /* OCTSubmanagerChatsMock.swift in Sources */, + 1109019C1D83417500BC5751 /* PinInputView.swift in Sources */, + 9CEE6AC91C4E8FDC00A1ECB5 /* StaticTableButtonCell.swift in Sources */, + 11FC105E1D32F29700CE863E /* OCTSubmanagerObjectsExtension.swift in Sources */, + 113F03431CB31DD60009ABE1 /* AlertAudioPlayer.swift in Sources */, + 116DCE331CAAF47100B693EC /* TopCoordinatorProtocol.swift in Sources */, + 9CEE6ABD1C4E8FDC00A1ECB5 /* ChatListCell.swift in Sources */, + 9CEE6B021C4E8FDC00A1ECB5 /* UserStatus.swift in Sources */, + 9CEE6B0D1C4E8FDC00A1ECB5 /* Logger.swift in Sources */, + 9C19367F1D79CF7E005EA0B2 /* EnterPinController.swift in Sources */, + 9CEE6B001C4E8FDC00A1ECB5 /* ActiveSessionNavigationCoordinator.swift in Sources */, + 9CEE6ADA1C4E8FDC00A1ECB5 /* Theme.swift in Sources */, + 9CEE6B0E1C4E8FDC00A1ECB5 /* BubbleView.swift in Sources */, + 113F03211CAFE2B50009ABE1 /* ChatOutgoingFileCellSnapshotTest.swift in Sources */, + 9CEE6B0A1C4E8FDC00A1ECB5 /* UIViewControllerExtension.swift in Sources */, + 11628E7C1CA5BF1F008C097E /* ChangeAutodownloadImagesController.swift in Sources */, + 1160461A1D8D434B002287C8 /* ChangePinTimeoutController.swift in Sources */, + 116634ED1C7B90F20072C980 /* FriendRequestController.swift in Sources */, + 11B3F8701CE095D2001927D8 /* ChatEditable.swift in Sources */, + 9CDC092D1C34102F00DC0D63 /* ExceptionHandling.m in Sources */, + 11B253FC1C52C0A10068F47C /* StaticTableSwitchCell.swift in Sources */, + 11628E3F1CA30C13008C097E /* QuickLookPreviewController.swift in Sources */, + 1117829D1DC5363C000C1721 /* OCTSubmanagerUserMock.swift in Sources */, + 113F030A1CAFCCB90009ABE1 /* SnapshotBaseTest.swift in Sources */, + 9CEE6AF41C4E8FDC00A1ECB5 /* TextViewController.swift in Sources */, + 113F03171CAFD9370009ABE1 /* MockedChatProgressProtocol.swift in Sources */, + 113F030F1CAFCE7B0009ABE1 /* ChatIncomingFileCellSnapshotTest.swift in Sources */, + 113F031D1CAFE0DE0009ABE1 /* ChatMovableDateCellSnapshotTest.swift in Sources */, + 1117827F1DC52CBA000C1721 /* OCTSubmanagerCallsMock.swift in Sources */, + 9CEE6B171C4E8FDC00A1ECB5 /* ViewPassingGestures.swift in Sources */, + 9CEE6B0B1C4E8FDC00A1ECB5 /* ErrorHandling.swift in Sources */, + 116634B01C6F40820072C980 /* ChatOutgoingCallCellModel.swift in Sources */, + 9CEE6B101C4E8FDC00A1ECB5 /* ChatPrivateTitleView.swift in Sources */, + 9CEE6AC31C4E8FDC00A1ECB5 /* FriendListCell.swift in Sources */, + 9CDC09251C34083100DC0D63 /* FriendListDataSourceTest.swift in Sources */, + 9CEE6AF71C4E8FDC00A1ECB5 /* AppCoordinator.swift in Sources */, + 111782941DC53371000C1721 /* OCTSubmanagerFilesMock.swift in Sources */, + 113F03141CAFD5EE0009ABE1 /* CellSnapshotTest.swift in Sources */, + 9CDE31E71E489B2700333E0D /* ChatInputViewManager.swift in Sources */, + 112E4ED71C668C02004312CF /* CallIncomingController.swift in Sources */, + 9CEE6ADC1C4E8FDC00A1ECB5 /* KeyboardNotificationController.swift in Sources */, + 11628E761CA5811C008C097E /* ChatGenericFileCellModel.swift in Sources */, + 9CEE6ADE1C4E8FDC00A1ECB5 /* LoginBaseController.swift in Sources */, + 9CEE6AF91C4E8FDC00A1ECB5 /* ActiveSessionCoordinator.swift in Sources */, + 11F83BDB1CAFB2A20074FE11 /* SwiftSupport.swift in Sources */, + 9CEE6AC41C4E8FDC00A1ECB5 /* FriendListCellModel.swift in Sources */, + 9CEE6B131C4E8FDC00A1ECB5 /* NotificationWindow.swift in Sources */, + 1160B68C1D5FD8DE002DF75B /* LaunchPlaceholderController.swift in Sources */, + 113F030C1CAFCCDD0009ABE1 /* ChatIncomingCallCellSnapshotTest.swift in Sources */, + 113F03191CAFDB0D0009ABE1 /* ChatIncomingTextCellSnapshotTest.swift in Sources */, + 113BBBA81EA88EAC00540E6C /* ChatTypingHeaderView.swift in Sources */, + 9CEE6ACB1C4E8FDC00A1ECB5 /* StaticTableChatButtonsCell.swift in Sources */, + 9CEE6B471C5289E200A1ECB5 /* SettingsMainController.swift in Sources */, + 9CEE6AEC1C4E8FDC00A1ECB5 /* PrimaryIpadController.swift in Sources */, + 9CEE6AF81C4E8FDC00A1ECB5 /* LoginCoordinator.swift in Sources */, + 1129508C1D6851EB00C9CE0F /* LoginCreateAccountCoordinator.swift in Sources */, + 9CEE6AD31C4E8FDC00A1ECB5 /* FriendListDataSource.swift in Sources */, + 11FC105B1D32EED000CE863E /* ResultsChange.swift in Sources */, + 9CEE6AE81C4E8FDC00A1ECB5 /* ChatPrivateController.swift in Sources */, + 9CEE6ACD1C4E8FDC00A1ECB5 /* StaticTableDefaultCell.swift in Sources */, + 1105B18E1EA09B1A0035B213 /* ChatFauxOfflineHeaderView.swift in Sources */, + 9CEE6AB91C4E8FDC00A1ECB5 /* BaseCell.swift in Sources */, + 1149626D1C5CE3DF001E5435 /* ChangeUserStatusController.swift in Sources */, + 9CEE6AD11C4E8FDC00A1ECB5 /* AvatarManager.swift in Sources */, + 9C1FEB2A1D8C10EB008C2ADE /* ProfileSettings.swift in Sources */, + 114962961C64051A001E5435 /* CallBaseController.swift in Sources */, + 11F276BC1D3EBF3000C613AA /* ChatBaseTextCellModel.swift in Sources */, + 9CEE6B071C4E8FDC00A1ECB5 /* StringExtension.swift in Sources */, + 113AD84B1CA97A3000D981B5 /* iPadNavigationView.swift in Sources */, + 9CEE6AEE1C4E8FDC00A1ECB5 /* QRScannerController.swift in Sources */, + 1183BCD81CA1FC5B000CD310 /* ChatProgressProtocol.swift in Sources */, + 9CEE6ADD1C4E8FDC00A1ECB5 /* PortraitNavigationController.swift in Sources */, + 9CEE6AE71C4E8FDC00A1ECB5 /* ChatListController.swift in Sources */, + 1173F0701BC5D9CA00B88B7B /* ThemeTest.swift in Sources */, + 9CEE6AF11C4E8FDC00A1ECB5 /* StaticTableController.swift in Sources */, + 11B253FF1C52C0AA0068F47C /* StaticTableSwitchCellModel.swift in Sources */, + 9CEE6ABE1C4E8FDC00A1ECB5 /* ChatListCellModel.swift in Sources */, + 9CEE6AEF1C4E8FDC00A1ECB5 /* QRViewerController.swift in Sources */, + 1160B6821D5FC7CC002DF75B /* KeychainManagerTests.swift in Sources */, + 9CEE6AC71C4E8FDC00A1ECB5 /* StaticTableBaseCell.swift in Sources */, + 116634AA1C6E8D1A0072C980 /* ChatIncomingCallCellModel.swift in Sources */, + 116634AD1C6F407D0072C980 /* ChatOutgoingCallCell.swift in Sources */, + 9CEE6B121C4E8FDC00A1ECB5 /* ImageViewWithStatus.swift in Sources */, + 11628E731CA580ED008C097E /* ChatGenericFileCell.swift in Sources */, + 9CEE6ADB1C4E8FDC00A1ECB5 /* UserDefaultsManager.swift in Sources */, + 9CEE6AF61C4E8FDC00A1ECB5 /* CoordinatorProtocol.swift in Sources */, + 116634B31C7087A80072C980 /* UIApplicationExtension.swift in Sources */, + 9CEE6ACA1C4E8FDC00A1ECB5 /* StaticTableButtonCellModel.swift in Sources */, + 112950881D63AFD800C9CE0F /* LoginCreatePasswordController.swift in Sources */, + 9CEE6AEA1C4E8FDC00A1ECB5 /* FriendCardController.swift in Sources */, + 9CEE6AFA1C4E8FDC00A1ECB5 /* CallCoordinator.swift in Sources */, + 111782971DC53458000C1721 /* OCTSubmanagerFriendsMock.swift in Sources */, + 11C33AC41DC961DC008DBC49 /* LoginChoiceViewSnapshotTest.swift in Sources */, + 9CEE6AE51C4E8FDC00A1ECB5 /* AddFriendController.swift in Sources */, + 9CEE6AFE1C4E8FDC00A1ECB5 /* NotificationCoordinator.swift in Sources */, + 9CEE6AD21C4E8FDC00A1ECB5 /* ChatListTableManager.swift in Sources */, + 9CEE6B011C4E8FDC00A1ECB5 /* SettingsTabCoordinator.swift in Sources */, + 114962761C5CEB0B001E5435 /* ProfileDetailsController.swift in Sources */, + 9CEE6B151C4E8FDC00A1ECB5 /* StaticBackgroundView.swift in Sources */, + 9CEE6AFD1C4E8FDC00A1ECB5 /* FriendsTabCoordinator.swift in Sources */, + 9CEE6ACF1C4E8FDC00A1ECB5 /* StaticTableSelectableCellModel.swift in Sources */, + 9CEE6B141C4E8FDC00A1ECB5 /* QRScannerAimView.swift in Sources */, + 110E07901EB0756C00B2CA9D /* ResultsExtension.swift in Sources */, + 9CEE6AD81C4E8FDC00A1ECB5 /* TabBarBadgeItem.swift in Sources */, + 9CEE6B031C4E8FDC00A1ECB5 /* UIImageExtension.swift in Sources */, + 9CEE6B111C4E8FDC00A1ECB5 /* FullscreenPicker.swift in Sources */, + 1183BCB61CA1B3AE000CD310 /* ChatIncomingFileCellModel.swift in Sources */, + 112950851D63AFCE00C9CE0F /* LoginGenericCreateController.swift in Sources */, + 9CEE6AD61C4E8FDC00A1ECB5 /* ProfileManager.swift in Sources */, + 111782791DC52BDB000C1721 /* OCTManagerMock.swift in Sources */, + 9CEE6AC01C4E8FDC00A1ECB5 /* ChatMovableDateCellModel.swift in Sources */, + 116634DA1C70F1260072C980 /* CopyLabel.swift in Sources */, + 9CEE6AF31C4E8FDC00A1ECB5 /* TextEditController.swift in Sources */, + 11770D781CBC1C7A00D34D6E /* UIAlertControllerExtension.swift in Sources */, + 9CEE6B041C4E8FDC00A1ECB5 /* NSDateFormatterExtension.swift in Sources */, + 1160B67F1D5F9993002DF75B /* KeychainManager.swift in Sources */, + 11F276AF1D3EBEF700C613AA /* ChatBaseTextCell.swift in Sources */, + 9CEE6B0F1C4E8FDC00A1ECB5 /* ChatInputView.swift in Sources */, + 116634F01C7B94530072C980 /* StaticTableMultiChoiceButtonCell.swift in Sources */, + 115CE3E91EB06F54001C08A0 /* ChatBottomStatusViewManager.swift in Sources */, + 9CEE6AED1C4E8FDC00A1ECB5 /* ProfileMainController.swift in Sources */, + 11B253AF1C4EC47D0068F47C /* IncompressibleView.swift in Sources */, + 1124953E1DE7AC0300EF45C4 /* KeyboardObserver.swift in Sources */, + 9CEE6AC11C4E8FDC00A1ECB5 /* ChatOutgoingTextCell.swift in Sources */, + 9CEE6ABF1C4E8FDC00A1ECB5 /* ChatMovableDateCell.swift in Sources */, + 116634F31C7B945A0072C980 /* StaticTableMultiChoiceButtonCellModel.swift in Sources */, + 113F031B1CAFDBF70009ABE1 /* ChatListCellSnapshotTest.swift in Sources */, + 9CEE6AFF1C4E8FDC00A1ECB5 /* ProfileTabCoordinator.swift in Sources */, + 11770D6B1CBC120C00D34D6E /* FriendSelectController.swift in Sources */, + 9CEE6ADF1C4E8FDC00A1ECB5 /* LoginChoiceController.swift in Sources */, + 11628E791CA5819B008C097E /* LoadingImageView.swift in Sources */, + 11B253B81C503FA10068F47C /* NSTimerExtension.swift in Sources */, + 9CEE6AD01C4E8FDC00A1ECB5 /* AudioPlayer.swift in Sources */, + 9CB1F9521D58CA4000105858 /* RunningCoordinator.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + AF2C9296279AB3F10094C08D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + AF2C929D279AB3F10094C08D /* NotificationService.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 111782AD1DC64391000C1721 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 1164762E19794D3300DB20B8 /* Antidote */; + targetProxy = 111782AC1DC64391000C1721 /* PBXContainerItemProxy */; + }; + 1173F05C1BC5D94400B88B7B /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 1164762E19794D3300DB20B8 /* Antidote */; + targetProxy = 1173F05B1BC5D94400B88B7B /* PBXContainerItemProxy */; + }; + AF2C92A0279AB3F10094C08D /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = AF2C9299279AB3F10094C08D /* pushextension */; + targetProxy = AF2C929F279AB3F10094C08D /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 1131D6C71CA9D8BC00B4531C /* import-profile.html */ = { + isa = PBXVariantGroup; + children = ( + 1131D6C61CA9D8BC00B4531C /* en */, + 1131D6C91CA9DA1500B4531C /* ru */, + 11F83B751CADC9260074FE11 /* zh */, + 11F83B7D1CADC9330074FE11 /* da */, + 11F83B821CADC9460074FE11 /* de */, + 11F83B841CADC9790074FE11 /* pt */, + 11F83B861CADC9820074FE11 /* es */, + 113F035C1CB458D10009ABE1 /* ar */, + 11D15D741D53CDAA0042FD4A /* br */, + 11D15D761D53CECC0042FD4A /* lt */, + 11D15D7A1D53D26A0042FD4A /* fr */, + 11763ADF1D9C54640035B4C9 /* cs */, + 1143E4311DCE1A2500BE7250 /* nl */, + 113187371DD290DD00E6FAA2 /* pl */, + AF6AB23629156EDA00019362 /* ca */, + AF6AB23929156F0000019362 /* ko */, + AF6AB23D29156F0A00019362 /* nb */, + AF6AB24129156F1C00019362 /* pt-BR */, + ); + name = "import-profile.html"; + sourceTree = ""; + }; + 113E96461E4BB302000282FC /* AppStoreLocalizable.strings */ = { + isa = PBXVariantGroup; + children = ( + 113E96451E4BB302000282FC /* en */, + 113E96471E4BB314000282FC /* ru */, + 113E96481E4BB318000282FC /* zh */, + 113E96491E4BB31F000282FC /* da */, + 113E964A1E4BB322000282FC /* de */, + 113E964B1E4BB327000282FC /* pt */, + 113E964C1E4BB32B000282FC /* es */, + 113E964E1E4BB371000282FC /* fr */, + 113E964F1E4BB37B000282FC /* nl */, + AF6AB23429156C6000019362 /* it */, + AF6AB23729156EDC00019362 /* ca */, + AF6AB23B29156F0000019362 /* ko */, + AF6AB23F29156F0B00019362 /* nb */, + AF6AB24229156F1E00019362 /* pt-BR */, + ); + name = AppStoreLocalizable.strings; + sourceTree = ""; + }; + 11F08D171DE0610B00F80F5F /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 11F08D161DE0610B00F80F5F /* en */, + 11F08D1E1DE0611700F80F5F /* ru */, + 11F08D1F1DE0611800F80F5F /* zh */, + 11F08D201DE0611800F80F5F /* da */, + 11F08D211DE0611900F80F5F /* de */, + 11F08D221DE0611A00F80F5F /* pt */, + 11F08D231DE0611B00F80F5F /* es */, + 11F08D241DE0611B00F80F5F /* ar */, + 11F08D251DE0611C00F80F5F /* lt */, + 11F08D261DE0611D00F80F5F /* br */, + 11F08D281DE0612200F80F5F /* fr */, + 11F08D291DE0612200F80F5F /* cs */, + 11F08D2B1DE0612400F80F5F /* nl */, + 11F08D2C1DE0612700F80F5F /* pl */, + AF6AB23329156C5800019362 /* it */, + AF6AB23529156EDA00019362 /* ca */, + AF6AB23829156F0000019362 /* ko */, + AF6AB23C29156F0A00019362 /* nb */, + AF6AB24029156F1C00019362 /* pt-BR */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; + 9C7475C01BC698110098B1A4 /* Localizable.strings */ = { + isa = PBXVariantGroup; + children = ( + 9C7475BF1BC698110098B1A4 /* en */, + 1131D6C41CA9D64500B4531C /* ru */, + 11F83B7C1CADC9270074FE11 /* zh */, + 11F83B7E1CADC9330074FE11 /* da */, + 11F83B831CADC9460074FE11 /* de */, + 11F83B851CADC9790074FE11 /* pt */, + 11F83B871CADC9820074FE11 /* es */, + 113F035D1CB458D10009ABE1 /* ar */, + 11D15D751D53CDAA0042FD4A /* br */, + 11D15D771D53CECC0042FD4A /* lt */, + 11D15D7B1D53D26A0042FD4A /* fr */, + 11763AEA1D9C54680035B4C9 /* cs */, + 1143E4321DCE1A2600BE7250 /* nl */, + 113187381DD290DE00E6FAA2 /* pl */, + AF6AB23A29156F0000019362 /* ko */, + AF6AB23A29256F0000019362 /* it */, + AF6AB23A29257F0000019362 /* ca */, + AF6AB23A29258F0000019362 /* nb */, + AF6AB23A29259F0000019362 /* pt-BR */, + AF6AB24129156F1C00019362 /* el */, + ); + name = Localizable.strings; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 111782AE1DC64391000C1721 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 02404DE3D3BB1BF461C45EA0 /* Pods-ScreenshotsUITests.debug.xcconfig */; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + INFOPLIST_FILE = ScreenshotsUITests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = YES; + OTHER_LDFLAGS = ( + "$(inherited)", + "-ObjC", + "-l\"CocoaLumberjack\"", + "-l\"JGProgressHUD\"", + "-l\"LNNotificationsUI\"", + "-l\"RBBAnimation\"", + "-l\"Realm\"", + "-l\"SDCAlertView\"", + "-l\"SDCAutoLayout\"", + "-l\"TPCircularBuffer\"", + "-l\"UITextView+Placeholder\"", + "-l\"c++\"", + "-l\"libopus\"", + "-l\"libsodium\"", + "-l\"objcTox\"", + "-l\"realm-ios\"", + "-l\"toxcore\"", + "-framework", + "\"AudioToolbox\"", + "-framework", + "\"Foundation\"", + "-framework", + "\"QuartzCore\"", + "-framework", + "\"UIKit\"", + "-framework", + "\"vpx\"", + "-read_only_relocs", + suppress, + ); + PRODUCT_BUNDLE_IDENTIFIER = org.zoxcore.ScreenshotsUITests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "ScreenshotsUITests/ScreenshotUITests-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 4.0; + TEST_TARGET_NAME = Antidote; + }; + name = Debug; + }; + 111782AF1DC64391000C1721 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 22DCF57E8F127B60BD096DD1 /* Pods-ScreenshotsUITests.release.xcconfig */; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + INFOPLIST_FILE = ScreenshotsUITests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_LDFLAGS = ( + "$(inherited)", + "-ObjC", + "-l\"CocoaLumberjack\"", + "-l\"JGProgressHUD\"", + "-l\"LNNotificationsUI\"", + "-l\"RBBAnimation\"", + "-l\"Realm\"", + "-l\"SDCAlertView\"", + "-l\"SDCAutoLayout\"", + "-l\"TPCircularBuffer\"", + "-l\"UITextView+Placeholder\"", + "-l\"c++\"", + "-l\"libopus\"", + "-l\"libsodium\"", + "-l\"objcTox\"", + "-l\"realm-ios\"", + "-l\"toxcore\"", + "-framework", + "\"AudioToolbox\"", + "-framework", + "\"Foundation\"", + "-framework", + "\"QuartzCore\"", + "-framework", + "\"UIKit\"", + "-framework", + "\"vpx\"", + "-read_only_relocs", + suppress, + ); + PRODUCT_BUNDLE_IDENTIFIER = org.zoxcore.ScreenshotsUITests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "ScreenshotsUITests/ScreenshotUITests-Bridging-Header.h"; + SWIFT_VERSION = 4.0; + TEST_TARGET_NAME = Antidote; + }; + name = Release; + }; + 1164765919794D3300DB20B8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "$(inherited)"; + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREFIX_HEADER = "Antidote/Antidote-Prefix.pch"; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + ONLY_ACTIVE_ARCH = YES; + PROVISIONING_PROFILE = ""; + SDKROOT = iphoneos; + }; + name = Debug; + }; + 1164765A19794D3300DB20B8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "$(inherited)"; + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = YES; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREFIX_HEADER = "Antidote/Antidote-Prefix.pch"; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 1164765C19794D3300DB20B8 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 2D5B916CEDBEC1B69CD1EFA4 /* Pods-Antidote.debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CLANG_STATIC_ANALYZER_MODE = deep; + CODE_SIGN_ENTITLEMENTS = Antidote/Antidote.entitlements; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CURRENT_PROJECT_VERSION = 142800; + DEVELOPMENT_TEAM = Y46L589C5C; + ENABLE_BITCODE = NO; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "Antidote/Antidote-Prefix.pch"; + GCC_WARN_SIGN_COMPARE = YES; + INFOPLIST_FILE = "Antidote/Antidote-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + MARKETING_VERSION = 1.4.28; + PRODUCT_BUNDLE_IDENTIFIER = "org.zoxcore.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE = ""; + RUN_CLANG_STATIC_ANALYZER = YES; + SWIFT_OBJC_BRIDGING_HEADER = "Antidote/Antidote-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.0; + TARGETED_DEVICE_FAMILY = 1; + WRAPPER_EXTENSION = app; + }; + name = Debug; + }; + 1164765D19794D3300DB20B8 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = B3C17AF8CE3B4AD1B68F2B5B /* Pods-Antidote.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CLANG_STATIC_ANALYZER_MODE = deep; + CODE_SIGN_ENTITLEMENTS = Antidote/Antidote.entitlements; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CURRENT_PROJECT_VERSION = 142800; + DEVELOPMENT_TEAM = Y46L589C5C; + ENABLE_BITCODE = NO; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "Antidote/Antidote-Prefix.pch"; + GCC_WARN_SIGN_COMPARE = YES; + INFOPLIST_FILE = "Antidote/Antidote-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + MARKETING_VERSION = 1.4.28; + PRODUCT_BUNDLE_IDENTIFIER = "org.zoxcore.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE = ""; + RUN_CLANG_STATIC_ANALYZER = YES; + SWIFT_OBJC_BRIDGING_HEADER = "Antidote/Antidote-Bridging-Header.h"; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.0; + TARGETED_DEVICE_FAMILY = 1; + WRAPPER_EXTENSION = app; + }; + name = Release; + }; + 1173F05E1BC5D94400B88B7B /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 43C533DEE94E80C981FEC348 /* Pods-AntidoteTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CLANG_ENABLE_MODULES = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_NO_COMMON_BLOCKS = YES; + INFOPLIST_FILE = AntidoteTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = YES; + PRODUCT_BUNDLE_IDENTIFIER = zoxcore.AntidoteTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "AntidoteTests/AntidoteTests-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Antidote.app/Antidote"; + }; + name = Debug; + }; + 1173F05F1BC5D94400B88B7B /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = CEC32120B965BE40E0029DB1 /* Pods-AntidoteTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CLANG_ENABLE_MODULES = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + INFOPLIST_FILE = AntidoteTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_BUNDLE_IDENTIFIER = zoxcore.AntidoteTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "AntidoteTests/AntidoteTests-Bridging-Header.h"; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Antidote.app/Antidote"; + }; + name = Release; + }; + AF2C92A3279AB3F10094C08D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES_NONAGGRESSIVE; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + DEBUG_INFORMATION_FORMAT = dwarf; + DEVELOPMENT_TEAM = Y46L589C5C; + INFOPLIST_FILE = pushextension/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = org.zoxcore.Antidote.pushextension; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 4.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + AF2C92A4279AB3F10094C08D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES_NONAGGRESSIVE; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEVELOPMENT_TEAM = Y46L589C5C; + INFOPLIST_FILE = pushextension/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = org.zoxcore.Antidote.pushextension; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_VERSION = 4.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 111782BA1DC64391000C1721 /* Build configuration list for PBXNativeTarget "ScreenshotsUITests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 111782AE1DC64391000C1721 /* Debug */, + 111782AF1DC64391000C1721 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1164762A19794D3300DB20B8 /* Build configuration list for PBXProject "Antidote" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1164765919794D3300DB20B8 /* Debug */, + 1164765A19794D3300DB20B8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1164765B19794D3300DB20B8 /* Build configuration list for PBXNativeTarget "Antidote" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1164765C19794D3300DB20B8 /* Debug */, + 1164765D19794D3300DB20B8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1173F05D1BC5D94400B88B7B /* Build configuration list for PBXNativeTarget "AntidoteTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1173F05E1BC5D94400B88B7B /* Debug */, + 1173F05F1BC5D94400B88B7B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + AF2C92A5279AB3F10094C08D /* Build configuration list for PBXNativeTarget "pushextension" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + AF2C92A3279AB3F10094C08D /* Debug */, + AF2C92A4279AB3F10094C08D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 1164762719794D3300DB20B8 /* Project object */; +} diff --git a/Antidote/ActiveSessionCoordinator.swift b/Antidote/ActiveSessionCoordinator.swift new file mode 100644 index 0000000..78ee43c --- /dev/null +++ b/Antidote/ActiveSessionCoordinator.swift @@ -0,0 +1,634 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit + +protocol ActiveSessionCoordinatorDelegate: class { + func activeSessionCoordinatorDidLogout(_ coordinator: ActiveSessionCoordinator, importToxProfileFromURL: URL?) + func activeSessionCoordinatorDeleteProfile(_ coordinator: ActiveSessionCoordinator) + func activeSessionCoordinatorRecreateCoordinatorsStack(_ coordinator: ActiveSessionCoordinator, options: CoordinatorOptions) + func activeSessionCoordinatorDidStartCall(_ coordinator: ActiveSessionCoordinator) + func activeSessionCoordinatorDidFinishCall(_ coordinator: ActiveSessionCoordinator) +} + +private struct Options { + static let ToShowKey = "ToShowKey" + static let StoredOptions = "StoredOptions" + + enum Coordinator { + case none + case settings + } +} + +private struct IpadObjects { + let splitController: UISplitViewController + + let primaryController: PrimaryIpadController + + let keyboardObserver = KeyboardObserver() +} + +private struct IphoneObjects { + enum TabCoordinator: Int { + case friends = 0 + case chats = 1 + case settings = 2 + case profile = 3 + + static func allValues() -> [TabCoordinator]{ + return [friends, chats, settings, profile] + } + } + + let chatsCoordinator: ChatsTabCoordinator + + let tabBarController: TabBarController + + let friendsTabBarItem: TabBarBadgeItem + let chatsTabBarItem: TabBarBadgeItem + let profileTabBarItem: TabBarProfileItem +} + +class ActiveSessionCoordinator: NSObject { + weak var delegate: ActiveSessionCoordinatorDelegate? + + fileprivate let theme: Theme + fileprivate let window: UIWindow + + // Tox manager is stored here + var toxManager: OCTManager! + + fileprivate let friendsCoordinator: FriendsTabCoordinator + fileprivate let settingsCoordinator: SettingsTabCoordinator + fileprivate let profileCoordinator: ProfileTabCoordinator + + fileprivate let notificationCoordinator: NotificationCoordinator + fileprivate let automationCoordinator: AutomationCoordinator + var callCoordinator: CallCoordinator! + + /** + One of following properties will be non-empty, depending on running device. + */ + fileprivate var iPhone: IphoneObjects! + fileprivate var iPad: IpadObjects! + + init(theme: Theme, window: UIWindow, toxManager: OCTManager) { + self.theme = theme + self.window = window + self.toxManager = toxManager + + self.friendsCoordinator = FriendsTabCoordinator(theme: theme, toxManager: toxManager) + self.settingsCoordinator = SettingsTabCoordinator(theme: theme) + self.profileCoordinator = ProfileTabCoordinator(theme: theme, toxManager: toxManager) + self.notificationCoordinator = NotificationCoordinator(theme: theme, submanagerObjects: toxManager.objects) + self.automationCoordinator = AutomationCoordinator(submanagerObjects: toxManager.objects, submanagerFiles: toxManager.files) + + super.init() + + // order matters + createDeviceSpecificObjects() + createCallCoordinator() + + toxManager.user.delegate = self + + friendsCoordinator.delegate = self + settingsCoordinator.delegate = self + profileCoordinator.delegate = self + notificationCoordinator.delegate = self + + NotificationCenter.default.addObserver(self, selector: #selector(ActiveSessionCoordinator.applicationWillTerminate), name: NSNotification.Name.UIApplicationWillTerminate, object: nil) + } + + deinit { + NotificationCenter.default.removeObserver(self) + } + + @objc func applicationWillTerminate() { + toxManager = nil + + // Giving tox some time to close all connections. + let until = Date(timeIntervalSinceNow:1.0) + RunLoop.current.run(until: until) + } +} + +extension ActiveSessionCoordinator: TopCoordinatorProtocol { + func startWithOptions(_ options: CoordinatorOptions?) { + switch InterfaceIdiom.current() { + case .iPhone: + iPhone.tabBarController.selectedIndex = IphoneObjects.TabCoordinator.chats.rawValue + iPhone.chatsCoordinator.startWithOptions(nil) + + window.rootViewController = iPhone.tabBarController + case .iPad: + primaryIpadControllerShowFriends(iPad.primaryController) + + window.rootViewController = iPad.splitController + } + + var settingsOptions: CoordinatorOptions? + + let toShow = options?[Options.ToShowKey] as? Options.Coordinator ?? .none + switch toShow { + case .none: + break + case .settings: + settingsOptions = options?[Options.StoredOptions] as? CoordinatorOptions + } + + friendsCoordinator.startWithOptions(nil) + settingsCoordinator.startWithOptions(settingsOptions) + profileCoordinator.startWithOptions(nil) + notificationCoordinator.startWithOptions(nil) + automationCoordinator.startWithOptions(nil) + callCoordinator.startWithOptions(nil) + + toxManager.bootstrap.addPredefinedNodes() + toxManager.bootstrap.bootstrap() + + updateUserAvatar() + updateUserName() + + switch toShow { + case .none: + break + case .settings: + showSettings() + } + } + func handleLocalNotification(_ notification: UILocalNotification) { + notificationCoordinator.handleLocalNotification(notification) + } + + func handleInboxURL(_ url: URL) { + let fileName = url.lastPathComponent + let filePath = url.path + let isToxFile = url.isToxURL() + + let style: UIAlertControllerStyle + + switch InterfaceIdiom.current() { + case .iPhone: + style = .actionSheet + case .iPad: + style = .alert + } + + let alert = UIAlertController(title: nil, message: fileName, preferredStyle: style) + + if isToxFile { + alert.addAction(UIAlertAction(title: String(localized: "create_profile"), style: .default) { [unowned self] _ -> Void in + self.logout(importToxProfileFromURL: url) + }) + } + + alert.addAction(UIAlertAction(title: String(localized: "file_send_to_contact"), style: .default) { [unowned self] _ -> Void in + self.sendFileToChats(filePath, fileName: fileName) + }) + + alert.addAction(UIAlertAction(title: String(localized: "alert_cancel"), style: .cancel, handler: nil)) + + switch InterfaceIdiom.current() { + case .iPhone: + iPhone.tabBarController.present(alert, animated: true, completion: nil) + case .iPad: + iPad.splitController.present(alert, animated: true, completion: nil) + } + } +} + +extension ActiveSessionCoordinator: OCTSubmanagerUserDelegate { + func submanagerUser(_ submanager: OCTSubmanagerUser, connectionStatusUpdate connectionStatus: OCTToxConnectionStatus) { + updateUserStatusView() + + let show = (connectionStatus == .none) + notificationCoordinator.toggleConnectingView(show: show, animated: true) + } +} + +extension ActiveSessionCoordinator: NotificationCoordinatorDelegate { + func notificationCoordinator(_ coordinator: NotificationCoordinator, showChat chat: OCTChat) { + showChat(chat) + } + + func notificationCoordinatorShowFriendRequest(_ coordinator: NotificationCoordinator, showRequest request: OCTFriendRequest) { + showFriendRequest(request) + } + + func notificationCoordinatorAnswerIncomingCall(_ coordinator: NotificationCoordinator, userInfo: String) { + callCoordinator.answerIncomingCallWithUserInfo(userInfo) + } + + func notificationCoordinator(_ coordinator: NotificationCoordinator, updateFriendsBadge badge: Int) { + let text: String? = (badge > 0) ? "\(badge)" : nil + + switch InterfaceIdiom.current() { + case .iPhone: + iPhone.friendsTabBarItem.badgeText = text + case .iPad: + iPad.primaryController.friendsBadgeText = text + break + } + } + + func notificationCoordinator(_ coordinator: NotificationCoordinator, updateChatsBadge badge: Int) { + switch InterfaceIdiom.current() { + case .iPhone: + iPhone.chatsTabBarItem.badgeText = (badge > 0) ? "\(badge)" : nil + case .iPad: + // none + break + } + } +} + +extension ActiveSessionCoordinator: CallCoordinatorDelegate { + func callCoordinator(_ coordinator: CallCoordinator, notifyAboutBackgroundCallFrom caller: String, userInfo: String) { + notificationCoordinator.showCallNotificationWithCaller(caller, userInfo: userInfo) + } + + func callCoordinatorDidStartCall(_ coordinator: CallCoordinator) { + delegate?.activeSessionCoordinatorDidStartCall(self) + } + + func callCoordinatorDidFinishCall(_ coordinator: CallCoordinator) { + delegate?.activeSessionCoordinatorDidFinishCall(self) + } +} + +extension ActiveSessionCoordinator: FriendsTabCoordinatorDelegate { + func friendsTabCoordinatorOpenChat(_ coordinator: FriendsTabCoordinator, forFriend friend: OCTFriend) { + let chat = toxManager.chats.getOrCreateChat(with: friend) + + showChat(chat!) + } + + func friendsTabCoordinatorCall(_ coordinator: FriendsTabCoordinator, toFriend friend: OCTFriend) { + let chat = toxManager.chats.getOrCreateChat(with: friend)! + + callCoordinator.callToChat(chat, enableVideo: false) + } + + func friendsTabCoordinatorVideoCall(_ coordinator: FriendsTabCoordinator, toFriend friend: OCTFriend) { + let chat = toxManager.chats.getOrCreateChat(with: friend)! + + callCoordinator.callToChat(chat, enableVideo: true) + } +} + +extension ActiveSessionCoordinator: ChatsTabCoordinatorDelegate { + func chatsTabCoordinator(_ coordinator: ChatsTabCoordinator, chatWillAppear chat: OCTChat) { + notificationCoordinator.banNotificationsForChat(chat) + } + + func chatsTabCoordinator(_ coordinator: ChatsTabCoordinator, chatWillDisapper chat: OCTChat) { + notificationCoordinator.unbanNotificationsForChat(chat) + } + + func chatsTabCoordinator(_ coordinator: ChatsTabCoordinator, callToChat chat: OCTChat, enableVideo: Bool) { + callCoordinator.callToChat(chat, enableVideo: enableVideo) + } +} + +extension ActiveSessionCoordinator: SettingsTabCoordinatorDelegate { + func settingsTabCoordinatorRecreateCoordinatorsStack(_ coordinator: SettingsTabCoordinator, options settingsOptions: CoordinatorOptions) { + delegate?.activeSessionCoordinatorRecreateCoordinatorsStack(self, options: [ + Options.ToShowKey: Options.Coordinator.settings, + Options.StoredOptions: settingsOptions, + ]) + } +} + +extension ActiveSessionCoordinator: ProfileTabCoordinatorDelegate { + func profileTabCoordinatorDelegateLogout(_ coordinator: ProfileTabCoordinator) { + logout() + } + + func profileTabCoordinatorDelegateDeleteProfile(_ coordinator: ProfileTabCoordinator) { + delegate?.activeSessionCoordinatorDeleteProfile(self) + } + + func profileTabCoordinatorDelegateDidChangeUserStatus(_ coordinator: ProfileTabCoordinator) { + updateUserStatusView() + } + + func profileTabCoordinatorDelegateDidChangeAvatar(_ coordinator: ProfileTabCoordinator) { + updateUserAvatar() + } + + func profileTabCoordinatorDelegateDidChangeUserName(_ coordinator: ProfileTabCoordinator) { + updateUserName() + } +} + +extension ActiveSessionCoordinator: PrimaryIpadControllerDelegate { + func primaryIpadController(_ controller: PrimaryIpadController, didSelectChat chat: OCTChat) { + showChat(chat) + } + + func primaryIpadControllerShowFriends(_ controller: PrimaryIpadController) { + iPad.splitController.showDetailViewController(friendsCoordinator.navigationController, sender: nil) + } + + func primaryIpadControllerShowSettings(_ controller: PrimaryIpadController) { + iPad.splitController.showDetailViewController(settingsCoordinator.navigationController, sender: nil) + } + + func primaryIpadControllerShowProfile(_ controller: PrimaryIpadController) { + iPad.splitController.showDetailViewController(profileCoordinator.navigationController, sender: nil) + } +} + +extension ActiveSessionCoordinator: ChatPrivateControllerDelegate { + func chatPrivateControllerWillAppear(_ controller: ChatPrivateController) { + notificationCoordinator.banNotificationsForChat(controller.chat) + } + + func chatPrivateControllerWillDisappear(_ controller: ChatPrivateController) { + notificationCoordinator.unbanNotificationsForChat(controller.chat) + } + + func chatPrivateControllerCallToChat(_ controller: ChatPrivateController, enableVideo: Bool) { + callCoordinator.callToChat(controller.chat, enableVideo: enableVideo) + } + + func chatPrivateControllerShowQuickLookController( + _ controller: ChatPrivateController, + dataSource: QuickLookPreviewControllerDataSource, + selectedIndex: Int) + { + let controller = QuickLookPreviewController() + controller.dataSource = dataSource + controller.dataSourceStorage = dataSource + controller.currentPreviewItemIndex = selectedIndex + + iPad.splitController.present(controller, animated: true, completion: nil) + } +} + +extension ActiveSessionCoordinator: FriendSelectControllerDelegate { + func friendSelectController(_ controller: FriendSelectController, didSelectFriend friend: OCTFriend) { + rootViewController().dismiss(animated: true) { [unowned self] in + guard let filePath = controller.userInfo as? String else { + return + } + + let chat = self.toxManager.chats.getOrCreateChat(with: friend) + self.sendFile(filePath, toChat: chat!) + } + } + + func friendSelectControllerCancel(_ controller: FriendSelectController) { + rootViewController().dismiss(animated: true, completion: nil) + + guard let filePath = controller.userInfo as? String else { + return + } + _ = try? FileManager.default.removeItem(atPath: filePath) + } +} + +private extension ActiveSessionCoordinator { + func createDeviceSpecificObjects() { + switch InterfaceIdiom.current() { + case .iPhone: + let chatsCoordinator = ChatsTabCoordinator(theme: theme, submanagerObjects: toxManager.objects, submanagerChats: toxManager.chats, submanagerFiles: toxManager.files) + chatsCoordinator.delegate = self + + let tabBarControllers = IphoneObjects.TabCoordinator.allValues().map { object -> UINavigationController in + switch object { + case .friends: + return friendsCoordinator.navigationController + case .chats: + return chatsCoordinator.navigationController + case .settings: + return settingsCoordinator.navigationController + case .profile: + return profileCoordinator.navigationController + } + } + + let tabBarItems = createTabBarItems() + + let friendsTabBarItem = tabBarItems[IphoneObjects.TabCoordinator.friends.rawValue] as! TabBarBadgeItem + let chatsTabBarItem = tabBarItems[IphoneObjects.TabCoordinator.chats.rawValue] as! TabBarBadgeItem + let profileTabBarItem = tabBarItems[IphoneObjects.TabCoordinator.profile.rawValue] as! TabBarProfileItem + + let tabBarController = TabBarController(theme: theme, controllers: tabBarControllers, tabBarItems: tabBarItems) + + iPhone = IphoneObjects( + chatsCoordinator: chatsCoordinator, + tabBarController: tabBarController, + friendsTabBarItem: friendsTabBarItem, + chatsTabBarItem: chatsTabBarItem, + profileTabBarItem: profileTabBarItem) + + case .iPad: + let splitController = UISplitViewController() + splitController.preferredDisplayMode = .allVisible + + let primaryController = PrimaryIpadController(theme: theme, submanagerChats: toxManager.chats, submanagerObjects: toxManager.objects) + primaryController.delegate = self + splitController.viewControllers = [UINavigationController(rootViewController: primaryController)] + + iPad = IpadObjects(splitController: splitController, primaryController: primaryController) + } + } + + func createCallCoordinator() { + let presentingController: UIViewController + + switch InterfaceIdiom.current() { + case .iPhone: + presentingController = iPhone.tabBarController + case .iPad: + presentingController = iPad.splitController + } + + self.callCoordinator = CallCoordinator( + theme: theme, + presentingController: presentingController, + submanagerCalls: toxManager.calls, + submanagerObjects: toxManager.objects) + callCoordinator.delegate = self + } + + func createTabBarItems() -> [TabBarAbstractItem] { + return IphoneObjects.TabCoordinator.allValues().map { + switch $0 { + case .friends: + let item = TabBarBadgeItem(theme: theme) + item.image = UIImage(named: "tab-bar-friends") + item.text = String(localized: "contacts_title") + item.badgeAccessibilityEnding = String(localized: "contact_requests_section") + return item + case .chats: + let item = TabBarBadgeItem(theme: theme) + item.image = UIImage(named: "tab-bar-chats") + item.text = String(localized: "chats_title") + item.badgeAccessibilityEnding = String(localized: "accessibility_chats_ending") + return item + case .settings: + let item = TabBarBadgeItem(theme: theme) + item.image = UIImage(named: "tab-bar-settings") + item.text = String(localized: "settings_title") + return item + case .profile: + return TabBarProfileItem(theme: theme) + } + } + } + + func showFriendRequest(_ request: OCTFriendRequest) { + switch InterfaceIdiom.current() { + case .iPhone: + iPhone.tabBarController.selectedIndex = IphoneObjects.TabCoordinator.friends.rawValue + case .iPad: + primaryIpadControllerShowFriends(iPad.primaryController) + } + + friendsCoordinator.showRequest(request, animated: false) + } + + /** + Returns active chat controller if it is visible, nil otherwise. + */ + func activeChatController() -> ChatPrivateController? { + switch InterfaceIdiom.current() { + case .iPhone: + if iPhone.tabBarController.selectedIndex != IphoneObjects.TabCoordinator.chats.rawValue { + return nil + } + + return iPhone.chatsCoordinator.activeChatController() + case .iPad: + return iPadDetailController() as? ChatPrivateController + } + } + + func showChat(_ chat: OCTChat) { + switch InterfaceIdiom.current() { + case .iPhone: + if iPhone.tabBarController.selectedIndex != IphoneObjects.TabCoordinator.chats.rawValue { + iPhone.tabBarController.selectedIndex = IphoneObjects.TabCoordinator.chats.rawValue + } + + iPhone.chatsCoordinator.showChat(chat, animated: false) + case .iPad: + if let chatVC = iPadDetailController() as? ChatPrivateController { + if chatVC.chat == chat { + // controller is already visible + return + } + } + + let controller = ChatPrivateController( + theme: theme, + chat: chat, + submanagerChats: toxManager.chats, + submanagerObjects: toxManager.objects, + submanagerFiles: toxManager.files, + delegate: self, + showKeyboardOnAppear: iPad.keyboardObserver.keyboardVisible) + let navigation = UINavigationController(rootViewController: controller) + + iPad.splitController.showDetailViewController(navigation, sender: nil) + } + } + + func showSettings() { + switch InterfaceIdiom.current() { + case .iPhone: + iPhone.tabBarController.selectedIndex = IphoneObjects.TabCoordinator.settings.rawValue + case .iPad: + primaryIpadControllerShowFriends(iPad.primaryController) + } + } + + func updateUserStatusView() { + let status = UserStatus(connectionStatus: toxManager.user.connectionStatus, userStatus: toxManager.user.userStatus) + let connectionstatus = ConnectionStatus(connectionStatus: toxManager.user.connectionStatus) + + switch InterfaceIdiom.current() { + case .iPhone: + iPhone.profileTabBarItem.userStatus = status + iPhone.profileTabBarItem.connectionStatus = connectionstatus + case .iPad: + iPad.primaryController.userStatus = status + } + } + + func updateUserAvatar() { + var avatar: UIImage? + + if let avatarData = toxManager.user.userAvatar() { + avatar = UIImage(data: avatarData) + } + + switch InterfaceIdiom.current() { + case .iPhone: + iPhone.profileTabBarItem.userImage = avatar + case .iPad: + iPad.primaryController.userAvatar = avatar + } + } + + func updateUserName() { + switch InterfaceIdiom.current() { + case .iPhone: + // nop + break + case .iPad: + iPad.primaryController.userName = toxManager.user.userName() + } + } + + func iPadDetailController() -> UIViewController? { + guard iPad.splitController.viewControllers.count == 2 else { + return nil + } + + let controller = iPad.splitController.viewControllers[1] + + if let navigation = controller as? UINavigationController { + return navigation.topViewController + } + + return controller + } + + func logout(importToxProfileFromURL profileURL: URL? = nil) { + delegate?.activeSessionCoordinatorDidLogout(self, importToxProfileFromURL: profileURL) + } + + func rootViewController() -> UIViewController { + switch InterfaceIdiom.current() { + case .iPhone: + return iPhone.tabBarController + case .iPad: + return iPad.splitController + } + } + + func sendFileToChats(_ filePath: String, fileName: String) { + let controller = FriendSelectController(theme: theme, submanagerObjects: toxManager.objects) + controller.delegate = self + controller.title = String(localized: "file_send_to_contact") + controller.userInfo = filePath as AnyObject? + + let navigation = UINavigationController(rootViewController: controller) + + rootViewController().present(navigation, animated: true, completion: nil) + } + + func sendFile(_ filePath: String, toChat chat: OCTChat) { + showChat(chat) + + toxManager.files.sendFile(atPath: filePath, moveToUploads: true, to: chat, failureBlock: { (error: Error) in + handleErrorWithType(.sendFileToFriend, error: error as NSError) + + }) + } +} diff --git a/Antidote/ActiveSessionNavigationCoordinator.swift b/Antidote/ActiveSessionNavigationCoordinator.swift new file mode 100644 index 0000000..7903112 --- /dev/null +++ b/Antidote/ActiveSessionNavigationCoordinator.swift @@ -0,0 +1,24 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit + +class ActiveSessionNavigationCoordinator { + let theme: Theme + let navigationController: UINavigationController + + init(theme: Theme) { + self.theme = theme + self.navigationController = UINavigationController() + } + + init(theme: Theme, navigationController: UINavigationController) { + self.theme = theme + self.navigationController = navigationController + } + + func startWithOptions(_ options: CoordinatorOptions?) { + preconditionFailure("This method must be overridden") + } +} diff --git a/Antidote/AddFriendController.swift b/Antidote/AddFriendController.swift new file mode 100644 index 0000000..3a77bd5 --- /dev/null +++ b/Antidote/AddFriendController.swift @@ -0,0 +1,245 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit +import SnapKit + +private struct Constants { + static let TextViewTopOffset = 5.0 + static let TextViewXOffset = 5.0 + static let QrCodeBottomSpacerDeltaHeight = 70.0 + + static let SendAlertTextViewBottomOffset = -10.0 + static let SendAlertTextViewXOffset = 5.0 + static let SendAlertTextViewHeight = 70.0 +} + +protocol AddFriendControllerDelegate: class { + func addFriendControllerScanQRCode( + _ controller: AddFriendController, + validateCodeHandler: @escaping (String) -> Bool, + didScanHander: @escaping (String) -> Void) + + func addFriendControllerDidFinish(_ controller: AddFriendController) +} + +class AddFriendController: UIViewController { + weak var delegate: AddFriendControllerDelegate? + + fileprivate let theme: Theme + fileprivate weak var submanagerFriends: OCTSubmanagerFriends! + + fileprivate var textView: UITextView! + + fileprivate var orTopSpacer: UIView! + fileprivate var qrCodeBottomSpacer: UIView! + + fileprivate var orLabel: UILabel! + fileprivate var qrCodeButton: UIButton! + + fileprivate var cachedMessage: String? + + init(theme: Theme, submanagerFriends: OCTSubmanagerFriends) { + self.theme = theme + self.submanagerFriends = submanagerFriends + + super.init(nibName: nil, bundle: nil) + + addNavigationButtons() + + edgesForExtendedLayout = UIRectEdge() + title = String(localized: "add_contact_title") + } + + required convenience init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func loadView() { + loadViewWithBackgroundColor(theme.colorForType(.NormalBackground)) + + createViews() + installConstraints() + + updateSendButton() + } +} + +extension AddFriendController { + @objc func qrCodeButtonPressed() { + func prepareString(_ string: String) -> String { + var string = string + + string = string.uppercased().trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) + + if string.hasPrefix("TOX:") { + return String(string[string.index(string.startIndex, offsetBy: 4) ..< string.endIndex]) + } + + return string + } + + delegate?.addFriendControllerScanQRCode(self, validateCodeHandler: { + return isAddressString(prepareString($0)) + + }, didScanHander: { [unowned self] in + self.textView.text = prepareString($0) + self.updateSendButton() + }) + } + + @objc func sendButtonPressed() { + textView.resignFirstResponder() + + let messageView = UITextView() + messageView.text = cachedMessage + let placeholderstring = NSAttributedString.init(string: String(localized: "add_contact_default_message_text")) + //messageView.attributedPlaceholder = placeholderstring + messageView.font = UIFont.systemFont(ofSize: 17.0) + messageView.layer.cornerRadius = 5.0 + messageView.layer.masksToBounds = true + + let alert = SDCAlertController( + title: String(localized: "add_contact_default_message_title"), + message: nil, + preferredStyle: .alert)! + + alert.contentView.addSubview(messageView) + messageView.snp.makeConstraints { + $0.top.equalTo(alert.contentView) + $0.bottom.equalTo(alert.contentView).offset(Constants.SendAlertTextViewBottomOffset); + $0.leading.equalTo(alert.contentView).offset(Constants.SendAlertTextViewXOffset); + $0.trailing.equalTo(alert.contentView).offset(-Constants.SendAlertTextViewXOffset); + $0.height.equalTo(Constants.SendAlertTextViewHeight); + } + + alert.addAction(SDCAlertAction(title: String(localized: "alert_cancel"), style: .default, handler: nil)) + alert.addAction(SDCAlertAction(title: String(localized: "add_contact_send"), style: .recommended) { [unowned self] action in + self.cachedMessage = messageView.text + + let message = messageView.text.isEmpty ? "Antidote is Tox" : messageView.text + + do { + try self.submanagerFriends.sendFriendRequest(toAddress: self.textView.text, message: message) + } + catch let error as NSError { + handleErrorWithType(.toxAddFriend, error: error) + return + } + + self.delegate?.addFriendControllerDidFinish(self) + }) + + alert.present(completion: nil) + } +} + +extension AddFriendController: UITextViewDelegate { + func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool { + if text == "\n" { + updateSendButton() + textView.resignFirstResponder() + return false + } + + let resultText = (textView.text! as NSString).replacingCharacters(in: range, with: text) + let maxLength = Int(kOCTToxAddressLength) + + if resultText.lengthOfBytes(using: String.Encoding.utf8) > maxLength { + textView.text = resultText.substringToByteLength(maxLength, encoding: String.Encoding.utf8) + updateSendButton() + return false + } + + updateSendButton() + return true + } + + func textViewDidChange(_ textView: UITextView) { + updateSendButton() + } +} + +private extension AddFriendController { + func addNavigationButtons() { + navigationItem.rightBarButtonItem = UIBarButtonItem( + title: String(localized: "add_contact_send"), + style: .done, + target: self, + action: #selector(AddFriendController.sendButtonPressed)) + } + + func createViews() { + textView = UITextView() + let placeholderstring = NSAttributedString.init(string: String(localized: "add_contact_tox_id_placeholder")) + //textView.attributedPlaceholder = (placeholderstring) + textView.delegate = self + textView.isScrollEnabled = false + textView.font = UIFont.systemFont(ofSize: 17) + textView.textColor = theme.colorForType(.NormalText) + textView.backgroundColor = .clear + textView.returnKeyType = .done + textView.layer.cornerRadius = 5.0 + textView.layer.borderWidth = 0.5 + textView.layer.borderColor = theme.colorForType(.SeparatorsAndBorders).cgColor + textView.layer.masksToBounds = true + view.addSubview(textView) + + orTopSpacer = createSpacer() + qrCodeBottomSpacer = createSpacer() + + orLabel = UILabel() + orLabel.text = String(localized: "add_contact_or_label") + orLabel.textColor = theme.colorForType(.NormalText) + orLabel.backgroundColor = .clear + view.addSubview(orLabel) + + qrCodeButton = UIButton(type: .system) + qrCodeButton.setTitle(String(localized: "add_contact_use_qr"), for: UIControlState()) + qrCodeButton.titleLabel!.font = UIFont.antidoteFontWithSize(16.0, weight: .bold) + qrCodeButton.addTarget(self, action: #selector(AddFriendController.qrCodeButtonPressed), for: .touchUpInside) + view.addSubview(qrCodeButton) + } + + func createSpacer() -> UIView { + let spacer = UIView() + spacer.backgroundColor = .clear + view.addSubview(spacer) + + return spacer + } + + func installConstraints() { + textView.snp.makeConstraints { + $0.top.equalTo(view).offset(Constants.TextViewTopOffset) + $0.leading.equalTo(view).offset(Constants.TextViewXOffset) + $0.trailing.equalTo(view).offset(-Constants.TextViewXOffset) + $0.bottom.equalTo(view.snp.centerY) + } + + orTopSpacer.snp.makeConstraints { + $0.top.equalTo(textView.snp.bottom) + } + + orLabel.snp.makeConstraints { + $0.top.equalTo(orTopSpacer.snp.bottom) + $0.centerX.equalTo(view) + } + + qrCodeButton.snp.makeConstraints { + $0.top.equalTo(orLabel.snp.bottom) + $0.centerX.equalTo(view) + } + + qrCodeBottomSpacer.snp.makeConstraints { + $0.top.equalTo(qrCodeButton.snp.bottom) + $0.bottom.equalTo(view) + $0.height.equalTo(orTopSpacer) + } + } + + func updateSendButton() { + navigationItem.rightBarButtonItem!.isEnabled = isAddressString(textView.text) + } +} diff --git a/Antidote/AlertAudioPlayer.swift b/Antidote/AlertAudioPlayer.swift new file mode 100644 index 0000000..11e3115 --- /dev/null +++ b/Antidote/AlertAudioPlayer.swift @@ -0,0 +1,50 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation +import AVFoundation + +class AlertAudioPlayer { + enum Sound: String { + case NewMessage = "isotoxin_NewMessage" + } + + var playOnlyIfApplicationIsActive = true + + fileprivate var sounds: [Sound: SystemSoundID]! + + init() { + sounds = [ + .NewMessage: createSystemSoundForSound(.NewMessage), + ] + } + + deinit { + for (_, systemSound) in sounds { + AudioServicesDisposeSystemSoundID(systemSound) + } + } + + func playSound(_ sound: Sound) { + if playOnlyIfApplicationIsActive && !UIApplication.isActive { + return + } + + guard let systemSound = sounds[sound] else { + return + } + + AudioServicesPlayAlertSound(systemSound) + } +} + +private extension AlertAudioPlayer { + func createSystemSoundForSound(_ sound: Sound) -> SystemSoundID { + let url = Bundle.main.url(forResource: sound.rawValue, withExtension: "aac")! + + var sound: SystemSoundID = 0 + AudioServicesCreateSystemSoundID(url as CFURL, &sound) + return sound + } +} diff --git a/Antidote/Antidote-Bridging-Header.h b/Antidote/Antidote-Bridging-Header.h new file mode 100644 index 0000000..c350f0e --- /dev/null +++ b/Antidote/Antidote-Bridging-Header.h @@ -0,0 +1,43 @@ +// +// Use this file to import your target's public headers that you would like to expose to Swift. +// + +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import + +#undef LOG_INFO +#undef LOG_DEBUG +#import "DDLog.h" +#import "DDASLLogger.h" +#import "DDTTYLogger.h" + +#import +#import +#import +#import + +#import "ExceptionHandling.h" diff --git a/Antidote/Antidote-Info.plist b/Antidote/Antidote-Info.plist new file mode 100644 index 0000000..137bf7e --- /dev/null +++ b/Antidote/Antidote-Info.plist @@ -0,0 +1,89 @@ + + + + + + NSLocationWhenInUseUsageDescription + Used to share your location with your contacts + CFBundleDevelopmentRegion + en + CFBundleDisplayName + ${PRODUCT_NAME} + CFBundleDocumentTypes + + + CFBundleTypeIconFiles + + CFBundleTypeName + Data + LSHandlerRank + Default + LSItemContentTypes + + public.data + + + + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + ITSAppUsesNonExemptEncryption + + LSApplicationCategoryType + + LSRequiresIPhoneOS + + LSSupportsOpeningDocumentsInPlace + + NSCameraUsageDescription + You can use video calls, send photos and videos, scan QR codes. + NSMicrophoneUsageDescription + You can use audio and video calls. + NSPhotoLibraryUsageDescription + You can send photos and videos. + UIBackgroundModes + + audio + fetch + location + remote-notification + voip + + UILaunchStoryboardName + Launch Screen + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + UIInterfaceOrientationPortraitUpsideDown + + UISupportsDocumentBrowser + + UIUserInterfaceStyle + Light + + diff --git a/Antidote/Antidote-Prefix.pch b/Antidote/Antidote-Prefix.pch new file mode 100644 index 0000000..de2f8e8 --- /dev/null +++ b/Antidote/Antidote-Prefix.pch @@ -0,0 +1,12 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + + +#ifndef Antidote_Prefix_pch +#define Antidote_Prefix_pch + +// Include any system framework and library headers here that should be included in all compilation units. +// You will also need to set the Prefix Header build setting of one or more of your targets to reference this file. + +#endif /* Antidote_Prefix_pch */ diff --git a/Antidote/Antidote.entitlements b/Antidote/Antidote.entitlements new file mode 100644 index 0000000..5265c39 --- /dev/null +++ b/Antidote/Antidote.entitlements @@ -0,0 +1,12 @@ + + + + + aps-environment + development + keychain-access-groups + + $(AppIdentifierPrefix)org.zoxcore.Antidote + + + diff --git a/Antidote/AppCoordinator.swift b/Antidote/AppCoordinator.swift new file mode 100644 index 0000000..985f1d4 --- /dev/null +++ b/Antidote/AppCoordinator.swift @@ -0,0 +1,163 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit + +class AppCoordinator { + fileprivate let window: UIWindow + var activeCoordinator: TopCoordinatorProtocol! + fileprivate var theme: Theme + + init(window: UIWindow) { + self.window = window + + let filepath = Bundle.main.path(forResource: "default-theme", ofType: "yaml")! + let yamlString = try! NSString(contentsOfFile:filepath, encoding:String.Encoding.utf8.rawValue) as String + + theme = try! Theme(yamlString: yamlString) + applyTheme(theme) + } +} + +// MARK: CoordinatorProtocol +extension AppCoordinator: TopCoordinatorProtocol { + func startWithOptions(_ options: CoordinatorOptions?) { + let storyboard = UIStoryboard(name: "LaunchPlaceholderBoard", bundle: Bundle.main) + window.rootViewController = storyboard.instantiateViewController(withIdentifier: "LaunchPlaceholderController") + + recreateActiveCoordinator(options: options) + } + + func handleLocalNotification(_ notification: UILocalNotification) { + activeCoordinator.handleLocalNotification(notification) + } + + func handleInboxURL(_ url: URL) { + activeCoordinator.handleInboxURL(url) + } +} + +extension AppCoordinator: RunningCoordinatorDelegate { + func runningCoordinatorDidLogout(_ coordinator: RunningCoordinator, importToxProfileFromURL: URL?) { + KeychainManager().deleteActiveAccountData() + + recreateActiveCoordinator() + + if let url = importToxProfileFromURL, + let coordinator = activeCoordinator as? LoginCoordinator { + coordinator.handleInboxURL(url) + } + } + + func runningCoordinatorDeleteProfile(_ coordinator: RunningCoordinator) { + let userDefaults = UserDefaultsManager() + let profileManager = ProfileManager() + + let name = userDefaults.lastActiveProfile! + + do { + try profileManager.deleteProfileWithName(name) + + KeychainManager().deleteActiveAccountData() + userDefaults.lastActiveProfile = nil + + recreateActiveCoordinator() + } + catch let error as NSError { + handleErrorWithType(.deleteProfile, error: error) + } + } + + func runningCoordinatorRecreateCoordinatorsStack(_ coordinator: RunningCoordinator, options: CoordinatorOptions) { + recreateActiveCoordinator(options: options, skipAuthorizationChallenge: true) + } +} + +extension AppCoordinator: LoginCoordinatorDelegate { + func loginCoordinatorDidLogin(_ coordinator: LoginCoordinator, manager: OCTManager, password: String) { + KeychainManager().toxPasswordForActiveAccount = password + + recreateActiveCoordinator(manager: manager, skipAuthorizationChallenge: true) + } +} + +// MARK: Private +private extension AppCoordinator { + func applyTheme(_ theme: Theme) { + let linkTextColor = theme.colorForType(.LinkText) + + UIButton.appearance().tintColor = linkTextColor + UISwitch.appearance().onTintColor = linkTextColor + UINavigationBar.appearance().tintColor = linkTextColor + } + + func recreateActiveCoordinator(options: CoordinatorOptions? = nil, + manager: OCTManager? = nil, + skipAuthorizationChallenge: Bool = false) { + if let password = KeychainManager().toxPasswordForActiveAccount { + let successBlock: (OCTManager) -> Void = { [unowned self] manager -> Void in + self.activeCoordinator = self.createRunningCoordinatorWithManager(manager, + options: options, + skipAuthorizationChallenge: skipAuthorizationChallenge) + } + + if let manager = manager { + successBlock(manager) + } + else { + let deleteActiveAccountAndRetry: () -> Void = { [unowned self] in + KeychainManager().deleteActiveAccountData() + self.recreateActiveCoordinator(options: options, + manager: manager, + skipAuthorizationChallenge: skipAuthorizationChallenge) + } + + guard let profileName = UserDefaultsManager().lastActiveProfile else { + deleteActiveAccountAndRetry() + return + } + + let path = ProfileManager().pathForProfileWithName(profileName) + + guard let configuration = OCTManagerConfiguration.configurationWithBaseDirectory(path) else { + deleteActiveAccountAndRetry() + return + } + + ToxFactory.createToxWithConfiguration(configuration, + encryptPassword: password, + successBlock: successBlock, + failureBlock: { _ in + log("Cannot create tox with configuration \(configuration)") + deleteActiveAccountAndRetry() + }) + } + } + else { + activeCoordinator = createLoginCoordinator(options) + } + } + + func createRunningCoordinatorWithManager(_ manager: OCTManager, + options: CoordinatorOptions?, + skipAuthorizationChallenge: Bool) -> RunningCoordinator { + let coordinator = RunningCoordinator(theme: theme, + window: window, + toxManager: manager, + skipAuthorizationChallenge: skipAuthorizationChallenge) + coordinator.delegate = self + coordinator.startWithOptions(options) + + return coordinator + } + + func createLoginCoordinator(_ options: CoordinatorOptions?) -> LoginCoordinator { + let coordinator = LoginCoordinator(theme: theme, window: window) + coordinator.delegate = self + coordinator.startWithOptions(options) + + return coordinator + } +} + diff --git a/Antidote/AppDelegate.swift b/Antidote/AppDelegate.swift new file mode 100644 index 0000000..78c7770 --- /dev/null +++ b/Antidote/AppDelegate.swift @@ -0,0 +1,321 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit +import Firebase +import os + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + var window: UIWindow? + let gcmMessageIDKey = "gcm.message_id" + var coordinator: AppCoordinator! + let callManager = CallManager() + lazy var providerDelegate: ProviderDelegate = ProviderDelegate(callManager: self.callManager) + var backgroundTask: UIBackgroundTaskIdentifier = UIBackgroundTaskInvalid + var gps_was_stopped_by_forground: Bool = false + static var lastStartGpsTS: Int64 = 0 + static var location_sharing_contact_pubkey: String = "-1" + + class var shared: AppDelegate { + return UIApplication.shared.delegate as! AppDelegate + } + + func displayIncomingCall(uuid: UUID, handle: String, hasVideo: Bool = false, completion: ((NSError?) -> Void)?) { + providerDelegate.reportIncomingCall(uuid: uuid, handle: handle, hasVideo: hasVideo, completion: completion) + } + + func endIncomingCalls() { + providerDelegate.endIncomingCalls() + } + + func applicationWillEnterForeground(_ application: UIApplication) { + os_log("AppDelegate:applicationWillEnterForeground") + UIApplication.shared.endBackgroundTask(self.backgroundTask) + self.backgroundTask = UIBackgroundTaskInvalid + + gps_was_stopped_by_forground = true + let gps = LocationManager.shared + if !gps.isHasAccess() { + os_log("AppDelegate:applicationWillEnterForeground:gps:no_access") + } else if gps.state == .Monitoring { + os_log("AppDelegate:applicationWillEnterForeground:gps:STOP") + gps.stopMonitoring() + } + + os_log("AppDelegate:applicationWillEnterForeground:DidEnterBackground:2:END") + } + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { + window = UIWindow(frame:UIScreen.main.bounds) + + print("didFinishLaunchingWithOptions") + os_log("AppDelegate:didFinishLaunchingWithOptions:start") + + if ProcessInfo.processInfo.arguments.contains("UI_TESTING") { + // Speeding up animations for UI tests. + window!.layer.speed = 1000 + } + + configureLoggingStuff() + + coordinator = AppCoordinator(window: window!) + coordinator.startWithOptions(nil) + + if let notification = launchOptions?[UIApplicationLaunchOptionsKey.localNotification] as? UILocalNotification { + coordinator.handleLocalNotification(notification) + } + + window?.backgroundColor = UIColor.white + window?.makeKeyAndVisible() + + FirebaseApp.configure() + + Messaging.messaging().delegate = self + + if #available(iOS 10.0, *) { + UNUserNotificationCenter.current().delegate = self + + let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound] + UNUserNotificationCenter.current().requestAuthorization( + options: authOptions, + completionHandler: { _, _ in } + ) + } else { + let settings: UIUserNotificationSettings = + UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil) + application.registerUserNotificationSettings(settings) + } + + application.registerForRemoteNotifications() + // HINT: try to go online every 47 minutes + let bgfetchInterval: TimeInterval = 47 * 60 + application.setMinimumBackgroundFetchInterval(bgfetchInterval); + os_log("AppDelegate:didFinishLaunchingWithOptions:end") + + return true + } + + func applicationWillTerminate(_ application: UIApplication) { + print("WillTerminate") + os_log("AppDelegate:applicationWillTerminate") + } + + func applicationDidReceiveMemoryWarning(_ application: UIApplication) { + print("DidReceiveMemoryWarning") + os_log("AppDelegate:applicationDidReceiveMemoryWarning") + } + + func applicationDidEnterBackground(_ application: UIApplication) { + print("DidEnterBackground") + os_log("AppDelegate:applicationDidEnterBackground:start") + + backgroundTask = UIApplication.shared.beginBackgroundTask (expirationHandler: { [unowned self] in + UIApplication.shared.endBackgroundTask(self.backgroundTask) + self.backgroundTask = UIBackgroundTaskInvalid + os_log("AppDelegate:applicationDidEnterBackground:3:expirationHandler:END") + }) + + DispatchQueue.main.asyncAfter(wallDeadline: DispatchWallTime.now() + 15) { + if (UserDefaultsManager().LongerbgMode == true) { + os_log("AppDelegate:applicationDidEnterBackground:PushSelf:start") + let coord = self.coordinator.activeCoordinator + let runcoord = coord as! RunningCoordinator + runcoord.activeSessionCoordinator?.toxManager.chats.sendOwnPush() + } else { + os_log("AppDelegate:applicationDidEnterBackground:PushSelf:longer-bg-mode not active in settings") + } + } + + gps_was_stopped_by_forground = false + let gps = LocationManager.shared + if gps.isHasAccess() { + AppDelegate.lastStartGpsTS = Date().millisecondsSince1970 + gps.startMonitoring() + os_log("AppDelegate:applicationDidEnterBackground:gps:START") + DispatchQueue.main.asyncAfter(wallDeadline: DispatchWallTime.now() + (3 * 60)) { + os_log("AppDelegate:applicationDidEnterBackground:4:gps:finishing") + let gps = LocationManager.shared + if !gps.isHasAccess() { + os_log("AppDelegate:applicationDidEnterBackground:4:gps:no_access") + } else if gps.state == .Monitoring { + if (self.gps_was_stopped_by_forground == false) { + + let diffTime = Date().millisecondsSince1970 - AppDelegate.lastStartGpsTS + os_log("AppDelegate:applicationDidEnterBackground:4:gps:Tlast=%ld", AppDelegate.lastStartGpsTS) + os_log("AppDelegate:applicationDidEnterBackground:4:gps:Tnow=%ld", Date().millisecondsSince1970) + os_log("AppDelegate:applicationDidEnterBackground:4:gps:Tdiff=%ld", diffTime) + + if (diffTime > (((3 * 60) - 4) * 1000)) + { + os_log("AppDelegate:applicationDidEnterBackground:4:gps:STOP") + gps.stopMonitoring() + } else { + os_log("AppDelegate:applicationDidEnterBackground:4:gps:STOP skipped, must be an old timer") + } + } else { + os_log("AppDelegate:applicationDidEnterBackground:4:gps:was stopped by forground, skipping") + } + } else { + os_log("AppDelegate:applicationDidEnterBackground:4:gps:STOP skipped, gps was stopped already") + } + } + } else { + os_log("AppDelegate:applicationDidEnterBackground:gps:no_access") + } + + DispatchQueue.main.asyncAfter(wallDeadline: DispatchWallTime.now() + 25) { + UIApplication.shared.endBackgroundTask(self.backgroundTask) + self.backgroundTask = UIBackgroundTaskInvalid + os_log("AppDelegate:applicationDidEnterBackground:1:END") + } + } + + func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { + + print("performFetchWithCompletionHandler:start") + os_log("AppDelegate:performFetchWithCompletionHandler:start") + // HINT: we have 30 seconds here. use 25 of those 30 seconds to be on the safe side + DispatchQueue.main.asyncAfter(deadline: .now() + 25) { [weak self] in + completionHandler(UIBackgroundFetchResult.newData) + print("performFetchWithCompletionHandler:end") + os_log("AppDelegate:performFetchWithCompletionHandler:end") + } + } + + func application(_ application: UIApplication, didReceive notification: UILocalNotification) { + coordinator.handleLocalNotification(notification) + } + + func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any]) -> Bool { + coordinator.handleInboxURL(url) + + return true + } + + func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool { + coordinator.handleInboxURL(url) + + return true + } + + // Device received notification (legacy callback) + // + func application(_ application: UIApplication, + didReceiveRemoteNotification userInfo: [AnyHashable: Any]) { + if let messageID = userInfo[gcmMessageIDKey] { + print("Message ID: \(messageID)") + } + } + + // tells the app that a remote notification arrived that indicates there is data to be fetched. + // ios 7+ + // + func application(_ application: UIApplication, + didReceiveRemoteNotification userInfo: [AnyHashable: Any], + fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) + -> Void) { + if let messageID = userInfo[gcmMessageIDKey] { + print("Message ID: \(messageID)") + } + + os_log("AppDelegate:didReceiveRemoteNotification:start") + // HINT: we have 30 seconds here. use 25 of those 30 seconds to be on the safe side + DispatchQueue.main.asyncAfter(deadline: .now() + 25) { [weak self] in + completionHandler(UIBackgroundFetchResult.newData) + os_log("AppDelegate:didReceiveRemoteNotification:start") + } + } + + // APNs failed to register the device for push notifications + // + func application(_ application: UIApplication, + didFailToRegisterForRemoteNotificationsWithError error: Error) { + print("Unable to register for remote notifications: \(error.localizedDescription)") + } + + func application(_ application: UIApplication, + didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { + print("APNs token retrieved: \(deviceToken)") + os_log("AppDelegate:didRegisterForRemoteNotificationsWithDeviceToken") + } +} + +@available(iOS 10, *) +extension AppDelegate: UNUserNotificationCenterDelegate { + + // determine what to do if app is in foreground when a notification is coming + // ios 10+ UNUserNotificationCenterDelegate method + // + func userNotificationCenter(_ center: UNUserNotificationCenter, + willPresent notification: UNNotification, + withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) + -> Void) { + let userInfo = notification.request.content.userInfo + + if let messageID = userInfo[gcmMessageIDKey] { + print("Message ID: \(messageID)") + } + completionHandler([[.alert, .sound]]) + } + + // Process and handle the user's response to a delivered notification. + // ios 10+ UNUserNotificationCenterDelegate method + // + func userNotificationCenter(_ center: UNUserNotificationCenter, + didReceive response: UNNotificationResponse, + withCompletionHandler completionHandler: @escaping () -> Void) { + let userInfo = response.notification.request.content.userInfo + + if let messageID = userInfo[gcmMessageIDKey] { + print("Message ID: \(messageID)") + } + completionHandler() + } + +} + +private extension AppDelegate { + func configureLoggingStuff() { + DDLog.add(DDASLLogger.sharedInstance()) + // DDLog.add(DDTTYLogger.sharedInstance()) + } +} + +extension AppDelegate: MessagingDelegate { + func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) { + print("Firebase registration token: \(String(describing: fcmToken))") + + let dataDict: [String: String] = ["token": fcmToken ?? ""] + NotificationCenter.default.post( + name: Notification.Name("FCMToken"), + object: nil, + userInfo: dataDict + ) + } +} + +// Convenience AppWide Simple Alert +extension AppDelegate { + func alert(_ title: String, _ msg: String? = nil) { + os_log("AppDelegate:alert") + let cnt = UIAlertController(title: title, message: msg, preferredStyle: .alert) + cnt.addAction(UIAlertAction(title: "Ok", style: .default, handler: { [weak cnt] act in + cnt?.dismiss(animated: true, completion: nil) + })) + + // guard let vc = AppDelegate.topViewController() else { return } + // vc.present(cnt, animated: true, completion: nil) + } +} + +extension Date { + var millisecondsSince1970: Int64 { + Int64((self.timeIntervalSince1970 * 1000.0).rounded()) + } + + init(milliseconds: Int64) { + self = Date(timeIntervalSince1970: TimeInterval(milliseconds) / 1000) + } +} diff --git a/Antidote/AudioPlayer.swift b/Antidote/AudioPlayer.swift new file mode 100644 index 0000000..c24111d --- /dev/null +++ b/Antidote/AudioPlayer.swift @@ -0,0 +1,81 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation +import AVFoundation + +class AudioPlayer { + enum Sound: String { + case Calltone = "isotoxin_Calltone" + case Hangup = "isotoxin_Hangup" + case Ringtone = "isotoxin_Ringtone" + case RingtoneWhileCall = "isotoxin_RingtoneWhileCall" + } + + var playOnlyIfApplicationIsActive = true + + fileprivate var players = [Sound: AVAudioPlayer]() + + func playSound(_ sound: Sound, loop: Bool) { + if playOnlyIfApplicationIsActive && !UIApplication.isActive { + return + } + + guard let player = playerForSound(sound) else { + return + } + + player.numberOfLoops = loop ? -1 : 1 + player.currentTime = 0.0 + player.play() + } + + func isPlayingSound(_ sound: Sound) -> Bool { + guard let player = playerForSound(sound) else { + return false + } + + return player.isPlaying + } + + func isPlaying() -> Bool { + let pl = players.filter { + $0.1.isPlaying + } + + return !pl.isEmpty + } + + func stopSound(_ sound: Sound) { + guard let player = playerForSound(sound) else { + return + } + player.stop() + } + + func stopAll() { + for (_, player) in players { + player.stop() + } + } +} + +private extension AudioPlayer { + func playerForSound(_ sound: Sound) -> AVAudioPlayer? { + if let player = players[sound] { + return player + } + + guard let path = Bundle.main.path(forResource: sound.rawValue, ofType: "aac") else { + return nil + } + + guard let player = try? AVAudioPlayer(contentsOf: URL(fileURLWithPath: path)) else { + return nil + } + + players[sound] = player + return player + } +} diff --git a/Antidote/AutomationCoordinator.swift b/Antidote/AutomationCoordinator.swift new file mode 100644 index 0000000..87cb50e --- /dev/null +++ b/Antidote/AutomationCoordinator.swift @@ -0,0 +1,110 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation +import MobileCoreServices +import os + +private struct Constants { + static let MaxFileSizeWiFi: OCTToxFileSize = 100 * 1024 * 1024 + static let MaxFileSizeWWAN: OCTToxFileSize = 20 * 1024 * 1024 +} + +class AutomationCoordinator: NSObject { + fileprivate weak var submanagerFiles: OCTSubmanagerFiles! + + fileprivate var fileMessagesToken: RLMNotificationToken? + fileprivate let userDefaults = UserDefaultsManager() + fileprivate let reachability = Reach() + + init(submanagerObjects: OCTSubmanagerObjects, submanagerFiles: OCTSubmanagerFiles) { + self.submanagerFiles = submanagerFiles + + super.init() + + let predicate = NSPredicate(format: "senderUniqueIdentifier != nil AND messageFile != nil") + let results = submanagerObjects.messages(predicate: predicate) + fileMessagesToken = results.addNotificationBlock { [unowned self] change in + switch change { + case .initial: + break + case .update(let results, _, let insertions, _): + guard let results = results else { + break + } + + for index in insertions { + let message = results[index] + self.proceedNewFileMessage(message) + } + case .error(let error): + fatalError("\(error)") + } + } + } +} + +extension AutomationCoordinator: CoordinatorProtocol { + func startWithOptions(_ options: CoordinatorOptions?) { + // nop + } +} + +private extension AutomationCoordinator { + func proceedNewFileMessage(_ message: OCTMessageAbstract) { + let usingWiFi = self.usingWiFi() + os_log("AutomationCoordinator:usingWiFi=%d", usingWiFi) + switch userDefaults.autodownloadImages { + case .Never: + return + case .UsingWiFi: + if !usingWiFi { + return + } + case .Always: + break + } + + // HINT: now we apply autodownload to all files, not only images + // if !UTTypeConformsTo(message.messageFile!.fileUTI as CFString? ?? "" as CFString, kUTTypeImage) { + // // download images only + // return + // } + + // skip too large files + if usingWiFi { + if message.messageFile!.fileSize > Constants.MaxFileSizeWiFi { + return + } + } + else { + if message.messageFile!.fileSize > Constants.MaxFileSizeWWAN { + return + } + } + + // workaround for deadlock in objcTox https://github.com/Antidote-for-Tox/objcTox/issues/51 + let delayTime = DispatchTime.now() + Double(Int64(0.0 * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC) + DispatchQueue.main.asyncAfter(deadline: delayTime) { [weak self] in + self?.submanagerFiles.acceptFileTransfer(message, failureBlock: nil) + } + } + + func usingWiFi() -> Bool + { + switch reachability.connectionStatus() { + case .offline: + return false + case .unknown: + return false + case .online(let type): + switch type { + case .wwan: + return false + case .wiFi: + return true + } + } + } +} diff --git a/Antidote/AvatarManager.swift b/Antidote/AvatarManager.swift new file mode 100644 index 0000000..320392d --- /dev/null +++ b/Antidote/AvatarManager.swift @@ -0,0 +1,131 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +class AvatarManager { + enum AvatarType: String { + case Normal + case Call + } + + fileprivate let theme: Theme + fileprivate let cache: NSCache + + init(theme: Theme) { + self.theme = theme + self.cache = NSCache() + } + + /** + Returns round avatar created from string with a given diameter. Searches for an avatar in cache first, + if not found creates it. + + - Parameters: + - string: String to create avatar from. In case of empty string avatar will be set to "?". + - diameter: Diameter of circle with avatar. + + - Returns: Avatar from given string with given size. + */ + func avatarFromString(_ string: String, diameter: CGFloat, type: AvatarType = .Normal) -> UIImage { + var string = string + + if string.isEmpty { + string = "?" + } + + let key = keyFromString(string, diameter: diameter, type: type) + + if let avatar = cache.object(forKey: key as AnyObject) as? UIImage { + return avatar + } + + let avatar = createAvatarFromString(string, diameter: diameter, type: type) + cache.setObject(avatar, forKey: key as AnyObject) + + return avatar + } +} + +private extension AvatarManager { + func keyFromString(_ string: String, diameter: CGFloat, type: AvatarType) -> String { + return "\(string)-\(diameter)-\(type.rawValue)" + } + + func createAvatarFromString(_ string: String, diameter: CGFloat, type: AvatarType) -> UIImage { + let avatarString = avatarStringFromString(string) + + let label = UILabel() + label.layer.borderWidth = 1.0 + label.layer.masksToBounds = true + label.textAlignment = .center + label.text = avatarString + + switch type { + case .Normal: + label.backgroundColor = theme.colorForType(.NormalBackground) + label.layer.borderColor = theme.colorForType(.LinkText).cgColor + label.textColor = theme.colorForType(.LinkText) + case .Call: + label.backgroundColor = .clear + label.layer.borderColor = theme.colorForType(.CallButtonIconColor).cgColor + label.textColor = theme.colorForType(.CallButtonIconColor) + } + + var size: CGSize + var fontSize = diameter + + repeat { + fontSize -= 1 + + let font = UIFont.antidoteFontWithSize(fontSize, weight: .light) + size = avatarString.stringSizeWithFont(font) + } + while (max(size.width, size.height) > diameter) + + let frame = CGRect(x: 0, y: 0, width: diameter, height: diameter) + + label.font = UIFont.antidoteFontWithSize(fontSize * 0.6, weight: .light) + label.layer.cornerRadius = frame.size.width / 2 + label.frame = frame + + return imageWithLabel(label) + } + + func avatarStringFromString(_ string: String) -> String { + guard !string.isEmpty else { + return "" + } + + // Avatar can have alphanumeric symbols and ? sign. + let badSymbols = (CharacterSet.alphanumerics.inverted as NSCharacterSet).mutableCopy() as! NSMutableCharacterSet + badSymbols.removeCharacters(in: "?") + + let words = string.components(separatedBy: CharacterSet.whitespaces).map { + $0.components(separatedBy: badSymbols as CharacterSet).joined(separator: "") + }.filter { + !$0.isEmpty + } + + var result = words.map { + $0.isEmpty ? "" : $0[$0.startIndex ..< $0.index($0.startIndex, offsetBy: 1)] + }.joined(separator: "") + + let numberOfLetters = min(2, result.count) + + result = result.uppercased() + return String(result[result.startIndex ..< result.index(result.startIndex, offsetBy: numberOfLetters)]) + } + + func imageWithLabel(_ label: UILabel) -> UIImage { + UIGraphicsBeginImageContextWithOptions(label.bounds.size, false, 0.0) + label.layer.render(in: UIGraphicsGetCurrentContext()!) + + let image = UIGraphicsGetImageFromCurrentImageContext() + + UIGraphicsEndImageContext() + + return image! + } +} diff --git a/Antidote/BaseCell.swift b/Antidote/BaseCell.swift new file mode 100644 index 0000000..c9a9df4 --- /dev/null +++ b/Antidote/BaseCell.swift @@ -0,0 +1,39 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit + +class BaseCell: UITableViewCell { + static var staticReuseIdentifier: String { + get { + return NSStringFromClass(self) + } + } + + override init(style: UITableViewCellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + + createViews() + installConstraints() + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + /** + Override this method in subclass. + */ + func setupWithTheme(_ theme: Theme, model: BaseCellModel) {} + + /** + Override this method in subclass. + */ + func createViews() {} + + /** + Override this method in subclass. + */ + func installConstraints() {} +} diff --git a/Antidote/BaseCellModel.swift b/Antidote/BaseCellModel.swift new file mode 100644 index 0000000..cf547b5 --- /dev/null +++ b/Antidote/BaseCellModel.swift @@ -0,0 +1,9 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +class BaseCellModel { + +} diff --git a/Antidote/BubbleView.swift b/Antidote/BubbleView.swift new file mode 100644 index 0000000..30bed86 --- /dev/null +++ b/Antidote/BubbleView.swift @@ -0,0 +1,104 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit +import SnapKit + +private struct Constants { + static let TextViewMinWidth = 5.0 + static let TextViewMaxWidth = 260.0 + static let TextViewMinHeight = 10.0 + + static let TextViewVerticalOffset = 1.0 + static let TextViewHorizontalOffset = 5.0 +} + +class BubbleView: UIView { + fileprivate var textView: UITextView! + + var text: String? { + get { + return textView.text + } + set { + textView.text = newValue + } + } + + var attributedText: NSAttributedString? { + get { + return textView.attributedText + } + set { + textView.attributedText = newValue + } + } + + var textColor: UIColor { + get { + return textView.textColor! + } + set { + textView.textColor = newValue + } + } + + var font: UIFont? { + get { + return textView.font + } + set { + textView.font = newValue + } + } + + override var tintColor: UIColor! { + didSet { + textView.linkTextAttributes = [ + NSAttributedStringKey.foregroundColor.rawValue: tintColor, + NSAttributedStringKey.underlineStyle.rawValue: NSUnderlineStyle.styleSingle.rawValue, + ] + } + } + + var selectable: Bool { + get { + return textView.isSelectable + } + set { + textView.isSelectable = newValue + } + } + + override init(frame: CGRect) { + super.init(frame: frame) + + layer.cornerRadius = 12.0 + layer.masksToBounds = true + + textView = UITextView() + textView.backgroundColor = .clear + textView.isEditable = false + textView.isScrollEnabled = false + textView.dataDetectorTypes = .all + textView.font = UIFont.systemFont(ofSize: 16.0) + + addSubview(textView) + + textView.snp.makeConstraints { + $0.top.equalTo(self).offset(Constants.TextViewVerticalOffset) + $0.bottom.equalTo(self).offset(-Constants.TextViewVerticalOffset) + $0.leading.equalTo(self).offset(Constants.TextViewHorizontalOffset) + $0.trailing.equalTo(self).offset(-Constants.TextViewHorizontalOffset) + + $0.width.greaterThanOrEqualTo(Constants.TextViewMinWidth) + $0.width.lessThanOrEqualTo(Constants.TextViewMaxWidth) + $0.height.greaterThanOrEqualTo(Constants.TextViewMinHeight) + } + } + + required convenience init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} diff --git a/Antidote/Bus.swift b/Antidote/Bus.swift new file mode 100644 index 0000000..d170c09 --- /dev/null +++ b/Antidote/Bus.swift @@ -0,0 +1,86 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// +// Bus.swift +// CLBackgroundAccess +// +// Created by Samer Murad on 10.04.21. +// + +import Foundation +import UIKit + +// Convenience wrapper around NotificationCenter + +// MARK: - Decleration +class Bus { + typealias Unsubscriber = () -> Void + static let shared = Bus() + private init() {} +} + +// MARK: - Subscribe / Post +extension Bus { + /// Subscribe to an event, return an Unsubscriber method (call to remove sub) + func on(event: Events, object: Any? = nil, queue: OperationQueue? = nil, cb: @escaping (Notification) -> Void) -> Unsubscriber { + let center = NotificationCenter.default + let notificationName = event.notifciationName() + + let observer = center.addObserver(forName: notificationName, object: object, queue: queue, using: cb) + return { + if object != nil { + center.removeObserver(observer, name: notificationName, object: object) + } else { + center.removeObserver(observer) + } + } + } + + /// Post event + func post(event: Events, object: Any? = nil, userInfo: [AnyHashable: Any]? = nil) { + guard event.isManualPostSupported() else { return } + let center = NotificationCenter.default + print("Event dispatch:", event) + center.post(name: event.notifciationName(), object: object, userInfo: userInfo) + } +} + +// MARK: - Events Enum +extension Bus { + enum Events: String { + // Location Events + case LocationUpdate + case LocationAuthUpdate + case LocationManagerStateChange + // Builtin Events + case AppEnteredBackground + case AppEnteredForeground + } + +} + +// MARK: - Events enum Notification.Name support and system events guard +extension Bus.Events { + func notifciationName() -> Notification.Name { + //switch self { + //case .AppEnteredBackground: + // return UIApplication.NSNotification.Name.UIApplicationDidEnterBackground + //case .AppEnteredForeground: + // return UIApplication.NSNotification.Name.UIApplicationWillEnterForeground + //default: + return Notification.Name(self.rawValue) + //} + } + + func isManualPostSupported() -> Bool { + let name = Notification.Name(self.rawValue) + let actualNotificationName = self.notifciationName() + let isSupported = name == actualNotificationName + if !isSupported { + print("WARN: Event \"", self, "\" Wrapps the System Event \"", actualNotificationName.rawValue, "\" And should not be posted manually") + } + return isSupported + } +} diff --git a/Antidote/CallActiveController.swift b/Antidote/CallActiveController.swift new file mode 100644 index 0000000..b33a859 --- /dev/null +++ b/Antidote/CallActiveController.swift @@ -0,0 +1,403 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit +import SnapKit + +protocol CallActiveControllerDelegate: class { + func callActiveController(_ controller: CallActiveController, mute: Bool) + func callActiveController(_ controller: CallActiveController, speaker: Bool) + func callActiveController(_ controller: CallActiveController, outgoingVideo: Bool) + func callActiveControllerDecline(_ controller: CallActiveController) + func callActiveControllerSwitchCamera(_ controller: CallActiveController) +} + +private struct Constants { + static let BigCenterContainerTopOffset = 50.0 + static let BigButtonOffset = 30.0 + + static let SmallButtonOffset = 20.0 + static let SmallBottomOffset: CGFloat = -20.0 + + static let VideoPreviewOffset = -20.0 + static let VideoPreviewSize = CGSize(width: 150.0, height: 110) + static let SwitchCameraOffset = 5.0 + + static let ControlsAnimationDuration = 0.3 +} + +class CallActiveController: CallBaseController { + enum State { + case none + case reaching + case active(duration: TimeInterval) + } + + weak var delegate: CallActiveControllerDelegate? + + var state: State = .none { + didSet { + // load view + _ = view + + switch state { + case .none: + infoLabel.text = nil + case .reaching: + infoLabel.text = String(localized: "call_reaching") + + bigVideoButton?.isEnabled = false + smallVideoButton?.isEnabled = false + case .active(let duration): + infoLabel.text = String(timeInterval: duration) + + bigVideoButton?.isEnabled = true + smallVideoButton?.isEnabled = true + } + } + } + + var mute: Bool = false { + didSet { + bigMuteButton?.isSelected = mute + smallMuteButton?.isSelected = mute + } + } + + var speaker: Bool = false { + didSet { + bigSpeakerButton?.isSelected = speaker + smallSpeakerButton?.isSelected = speaker + } + } + + var outgoingVideo: Bool = false { + didSet { + bigVideoButton?.isSelected = outgoingVideo + smallVideoButton?.isSelected = outgoingVideo + } + } + + var videoFeed: UIView? { + didSet { + if oldValue === videoFeed { + return + } + + if let old = oldValue { + old.removeFromSuperview() + } + + if let feed = videoFeed { + view.insertSubview(feed, belowSubview: videoPreviewView) + + feed.bounds.size = view.bounds.size + + feed.snp.makeConstraints { + $0.edges.equalTo(view) + } + + updateViewsWithTraitCollection(self.traitCollection) + } + } + } + + var videoPreviewLayer: CALayer? { + didSet { + if oldValue === videoPreviewLayer { + return + } + + if let old = oldValue { + old.removeFromSuperlayer() + videoPreviewView.isHidden = true + } + + if let layer = videoPreviewLayer { + videoPreviewView.layer.addSublayer(layer) + videoPreviewView.bringSubview(toFront: switchCameraButton) + videoPreviewView.isHidden = false + view.layoutIfNeeded() + } + + updateViewsWithTraitCollection(self.traitCollection) + } + } + + fileprivate var showControls = true { + didSet { + let offset = showControls ? Constants.SmallBottomOffset : smallContainerView.frame.size.height + smallContainerViewBottomConstraint.update(offset: offset) + + toggleTopContainer(hidden: !showControls) + + UIView.animate(withDuration: Constants.ControlsAnimationDuration, animations: { [unowned self] in + self.view.layoutIfNeeded() + }) + } + } + + fileprivate var videoPreviewView: UIView! + fileprivate var switchCameraButton: UIButton! + + fileprivate var bigContainerView: UIView! + fileprivate var bigCenterContainer: UIView! + fileprivate var bigMuteButton: CallButton? + fileprivate var bigSpeakerButton: CallButton? + fileprivate var bigVideoButton: CallButton? + fileprivate var bigDeclineButton: CallButton? + + fileprivate var smallContainerViewBottomConstraint: Constraint! + + fileprivate var smallContainerView: UIView! + fileprivate var smallMuteButton: CallButton? + fileprivate var smallSpeakerButton: CallButton? + fileprivate var smallVideoButton: CallButton? + fileprivate var smallDeclineButton: CallButton? + + override init(theme: Theme, callerName: String) { + super.init(theme: theme, callerName: callerName) + } + + required convenience init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func loadView() { + super.loadView() + + createGestureRecognizers() + createVideoPreviewView() + createBigViews() + createSmallViews() + installConstraints() + + view.bringSubview(toFront: topContainer) + + setButtonsInitValues() + + updateViewsWithTraitCollection(self.traitCollection) + } + + override func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator) { + updateViewsWithTraitCollection(newCollection) + showControls = true + } + + override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + + if let layer = videoPreviewLayer { + layer.frame.size = videoPreviewView.frame.size + } + } + + override func prepareForRemoval() { + super.prepareForRemoval() + + bigMuteButton?.isEnabled = false + bigSpeakerButton?.isEnabled = false + bigVideoButton?.isEnabled = false + bigDeclineButton?.isEnabled = false + + smallMuteButton?.isEnabled = false + smallSpeakerButton?.isEnabled = false + smallVideoButton?.isEnabled = false + smallDeclineButton?.isEnabled = false + } +} + +// MARK: Actions +extension CallActiveController { + @objc func tapOnView() { + guard !smallContainerView.isHidden else { + return + } + + showControls = !showControls + } + + @objc func muteButtonPressed(_ button: CallButton) { + mute = !button.isSelected + delegate?.callActiveController(self, mute: mute) + } + + @objc func speakerButtonPressed(_ button: CallButton) { + speaker = !button.isSelected + delegate?.callActiveController(self, speaker: speaker) + } + + @objc func videoButtonPressed(_ button: CallButton) { + outgoingVideo = !button.isSelected + delegate?.callActiveController(self, outgoingVideo: outgoingVideo) + } + + @objc func declineButtonPressed() { + delegate?.callActiveControllerDecline(self) + } + + @objc func switchCameraButtonPressed() { + delegate?.callActiveControllerSwitchCamera(self) + } +} + +private extension CallActiveController { + func createGestureRecognizers() { + let tapGR = UITapGestureRecognizer(target: self, action: #selector(CallActiveController.tapOnView)) + view.addGestureRecognizer(tapGR) + } + + func createVideoPreviewView() { + videoPreviewView = UIView() + videoPreviewView.backgroundColor = theme.colorForType(.CallVideoPreviewBackground) + view.addSubview(videoPreviewView) + + videoPreviewView.isHidden = !outgoingVideo + + let image = UIImage.templateNamed("switch-camera") + + switchCameraButton = UIButton() + switchCameraButton.tintColor = theme.colorForType(.CallButtonIconColor) + switchCameraButton.setImage(image, for: UIControlState()) + switchCameraButton.addTarget(self, action: #selector(CallActiveController.switchCameraButtonPressed), for: .touchUpInside) + videoPreviewView.addSubview(switchCameraButton) + } + + func createBigViews() { + bigContainerView = UIView() + bigContainerView.backgroundColor = .clear + view.addSubview(bigContainerView) + + bigCenterContainer = UIView() + bigCenterContainer.backgroundColor = .clear + bigContainerView.addSubview(bigCenterContainer) + + bigMuteButton = addButtonWithType(.mute, buttonSize: .big, action: #selector(CallActiveController.muteButtonPressed(_:)), container: bigCenterContainer) + bigSpeakerButton = addButtonWithType(.speaker, buttonSize: .big, action: #selector(CallActiveController.speakerButtonPressed(_:)), container: bigCenterContainer) + bigVideoButton = addButtonWithType(.video, buttonSize: .big, action: #selector(CallActiveController.videoButtonPressed(_:)), container: bigCenterContainer) + bigDeclineButton = addButtonWithType(.decline, buttonSize: .small, action: #selector(CallActiveController.declineButtonPressed), container: bigContainerView) + } + + func createSmallViews() { + smallContainerView = UIView() + smallContainerView.backgroundColor = .clear + view.addSubview(smallContainerView) + + smallMuteButton = addButtonWithType(.mute, buttonSize: .small, action: #selector(CallActiveController.muteButtonPressed(_:)), container: smallContainerView) + smallSpeakerButton = addButtonWithType(.speaker, buttonSize: .small, action: #selector(CallActiveController.speakerButtonPressed(_:)), container: smallContainerView) + smallVideoButton = addButtonWithType(.video, buttonSize: .small, action: #selector(CallActiveController.videoButtonPressed(_:)), container: smallContainerView) + smallDeclineButton = addButtonWithType(.decline, buttonSize: .small, action: #selector(CallActiveController.declineButtonPressed), container: smallContainerView) + } + + func addButtonWithType(_ type: CallButton.ButtonType, buttonSize: CallButton.ButtonSize, action: Selector, container: UIView) -> CallButton { + let button = CallButton(theme: theme, type: type, buttonSize: buttonSize) + button.addTarget(self, action: action, for: .touchUpInside) + container.addSubview(button) + + return button + } + + func installConstraints() { + videoPreviewView.snp.makeConstraints { + $0.trailing.equalTo(view).offset(Constants.VideoPreviewOffset) + $0.bottom.equalTo(smallContainerView.snp.top).offset(Constants.VideoPreviewOffset) + $0.width.equalTo(Constants.VideoPreviewSize.width) + $0.height.equalTo(Constants.VideoPreviewSize.height) + } + + switchCameraButton.snp.makeConstraints { + $0.top.equalTo(videoPreviewView).offset(Constants.SwitchCameraOffset) + $0.trailing.equalTo(videoPreviewView).offset(-Constants.SwitchCameraOffset) + } + + bigContainerView.snp.makeConstraints { + $0.top.equalTo(topContainer.snp.bottom) + $0.leading.trailing.bottom.equalTo(view) + } + + bigCenterContainer.snp.makeConstraints { + $0.centerX.equalTo(bigContainerView) + $0.centerY.equalTo(view) + } + + bigMuteButton!.snp.makeConstraints { + $0.top.equalTo(bigCenterContainer) + $0.leading.equalTo(bigCenterContainer) + } + + bigSpeakerButton!.snp.makeConstraints { + $0.top.equalTo(bigCenterContainer) + $0.trailing.equalTo(bigCenterContainer) + $0.leading.equalTo(bigMuteButton!.snp.trailing).offset(Constants.BigButtonOffset) + } + + bigVideoButton!.snp.makeConstraints { + $0.top.equalTo(bigMuteButton!.snp.bottom).offset(Constants.BigButtonOffset) + $0.leading.equalTo(bigCenterContainer) + $0.bottom.equalTo(bigCenterContainer) + } + + bigDeclineButton!.snp.makeConstraints { + $0.centerX.equalTo(bigContainerView) + $0.top.greaterThanOrEqualTo(bigCenterContainer).offset(Constants.BigButtonOffset) + $0.bottom.equalTo(bigContainerView).offset(-Constants.BigButtonOffset) + } + + smallContainerView.snp.makeConstraints { + smallContainerViewBottomConstraint = $0.bottom.equalTo(view).offset(Constants.SmallBottomOffset).constraint + $0.centerX.equalTo(view) + } + + smallMuteButton!.snp.makeConstraints { + $0.top.bottom.equalTo(smallContainerView) + $0.leading.equalTo(smallContainerView) + } + + smallSpeakerButton!.snp.makeConstraints { + $0.top.bottom.equalTo(smallContainerView) + $0.leading.equalTo(smallMuteButton!.snp.trailing).offset(Constants.SmallButtonOffset) + } + + smallVideoButton!.snp.makeConstraints { + $0.top.bottom.equalTo(smallContainerView) + $0.leading.equalTo(smallSpeakerButton!.snp.trailing).offset(Constants.SmallButtonOffset) + } + + smallDeclineButton!.snp.makeConstraints { + $0.top.bottom.equalTo(smallContainerView) + $0.leading.equalTo(smallVideoButton!.snp.trailing).offset(Constants.SmallButtonOffset) + $0.trailing.equalTo(smallContainerView) + } + } + + func setButtonsInitValues() { + bigMuteButton?.isSelected = mute + smallMuteButton?.isSelected = mute + + bigSpeakerButton?.isSelected = speaker + smallSpeakerButton?.isSelected = speaker + + bigVideoButton?.isSelected = outgoingVideo + smallVideoButton?.isSelected = outgoingVideo + } + + func updateViewsWithTraitCollection(_ traitCollection: UITraitCollection) { + if videoFeed != nil || videoPreviewLayer != nil { + bigContainerView.isHidden = true + smallContainerView.isHidden = false + return + } + + switch traitCollection.verticalSizeClass { + case .regular: + bigContainerView.isHidden = false + smallContainerView.isHidden = true + case .unspecified: + fallthrough + case .compact: + bigContainerView.isHidden = true + smallContainerView.isHidden = false + } + } +} diff --git a/Antidote/CallBaseController.swift b/Antidote/CallBaseController.swift new file mode 100644 index 0000000..595af78 --- /dev/null +++ b/Antidote/CallBaseController.swift @@ -0,0 +1,117 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit +import SnapKit + +private struct Constants { + static let TopContainerHeight = 80.0 + static let CallerLabelTopOffset = 20.0 + static let InfoLabelBottomOffset = -5.0 + static let LabelHorizontalOffset = 20.0 +} + +class CallBaseController: UIViewController { + let theme: Theme + + let callerName: String + + var topContainer: UIView! + var callerLabel: UILabel! + var infoLabel: UILabel! + + fileprivate var topContainerTopConstraint: Constraint! + + init(theme: Theme, callerName: String) { + self.theme = theme + self.callerName = callerName + + super.init(nibName: nil, bundle: nil) + } + + required convenience init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { + super.viewDidLoad() + // HINT: turn on ProximitySensor to blank screen when near the ear + UIDevice.current.isProximityMonitoringEnabled = true + } + + deinit { + // HINT: reset ProximitySensor when calling screen is closed + UIDevice.current.isProximityMonitoringEnabled = false + } + + override func loadView() { + loadViewWithBackgroundColor(.clear) + + addBlurredBackground() + createTopViews() + installConstraints() + } + + /** + Prepare for removal by disabling all active views. + */ + func prepareForRemoval() { + infoLabel.text = String(localized: "call_ended") + } + + func toggleTopContainer(hidden: Bool) { + let offset = hidden ? -topContainer.frame.size.height : 0.0 + topContainerTopConstraint.update(offset: offset) + } +} + +private extension CallBaseController { + func addBlurredBackground() { + let effectView = UIVisualEffectView(effect: UIBlurEffect(style: .dark)) + effectView.frame = view.bounds + + view.insertSubview(effectView, at: 0) + effectView.snp.makeConstraints { + $0.edges.equalTo(view) + } + } + + func createTopViews() { + topContainer = UIView() // UIVisualEffectView(effect: UIBlurEffect(style: .dark)) + view.addSubview(topContainer) + + callerLabel = UILabel() + callerLabel.text = callerName + callerLabel.textColor = theme.colorForType(.CallTextColor) + callerLabel.textAlignment = .center + callerLabel.font = UIFont.systemFont(ofSize: 20.0) + topContainer.addSubview(callerLabel) + + infoLabel = UILabel() + infoLabel.textColor = theme.colorForType(.CallTextColor) + infoLabel.textAlignment = .center + infoLabel.font = UIFont.antidoteFontWithSize(18.0, weight: .light) + topContainer.addSubview(infoLabel) + } + + func installConstraints() { + topContainer.snp.makeConstraints { + topContainerTopConstraint = $0.top.equalTo(view).constraint + $0.top.leading.trailing.equalTo(view) + $0.height.equalTo(Constants.TopContainerHeight) + } + + callerLabel.snp.makeConstraints { + $0.top.equalTo(topContainer).offset(Constants.CallerLabelTopOffset) + $0.leading.equalTo(topContainer).offset(Constants.LabelHorizontalOffset) + $0.trailing.equalTo(topContainer).offset(-Constants.LabelHorizontalOffset) + } + + infoLabel.snp.makeConstraints { + $0.bottom.equalTo(topContainer).offset(Constants.InfoLabelBottomOffset) + $0.leading.equalTo(topContainer).offset(Constants.LabelHorizontalOffset) + $0.trailing.equalTo(topContainer).offset(-Constants.LabelHorizontalOffset) + } + } +} diff --git a/Antidote/CallButton.swift b/Antidote/CallButton.swift new file mode 100644 index 0000000..3df51d4 --- /dev/null +++ b/Antidote/CallButton.swift @@ -0,0 +1,132 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit + +private struct Constants { + static let SmallSize: CGFloat = 60.0 + static let BigSize: CGFloat = 80.0 + static let ImageSize: CGFloat = 30.0 +} + +class CallButton: UIButton { + enum ButtonSize { + case small + case big + } + + enum ButtonType { + case decline + case answerAudio + case answerVideo + case mute + case speaker + case video + } + + override var isSelected: Bool { + didSet { + if let selectedTintColor = selectedTintColor { + tintColor = isSelected ? selectedTintColor : normalTintColor + } + } + } + + override var isHighlighted: Bool { + didSet { + if isHighlighted { + tintColor = normalTintColor + } + else { + if let selectedTintColor = selectedTintColor { + tintColor = isSelected ? selectedTintColor : normalTintColor + } + } + } + } + + fileprivate let buttonSize: ButtonSize + fileprivate let normalTintColor: UIColor + fileprivate var selectedTintColor: UIColor? + + init(theme: Theme, type: ButtonType, buttonSize: ButtonSize) { + self.buttonSize = buttonSize + self.normalTintColor = theme.colorForType(.CallButtonIconColor) + + super.init(frame: CGRect.zero) + + switch buttonSize { + case .small: + layer.cornerRadius = Constants.SmallSize / 2 + case .big: + layer.cornerRadius = Constants.BigSize / 2 + } + layer.masksToBounds = true + + let imageName: String + let backgroundColor: UIColor + var selectedBackgroundColor: UIColor? = nil + + switch type { + case .decline: + imageName = "end-call" + backgroundColor = theme.colorForType(.CallDeclineButtonBackground) + case .answerAudio: + imageName = "start-call-30" + backgroundColor = theme.colorForType(.CallAnswerButtonBackground) + case .answerVideo: + imageName = "video-call-30" + backgroundColor = theme.colorForType(.CallAnswerButtonBackground) + case .mute: + imageName = "mute" + backgroundColor = theme.colorForType(.CallControlBackground) + selectedTintColor = theme.colorForType(.CallButtonSelectedIconColor) + selectedBackgroundColor = theme.colorForType(.CallControlSelectedBackground) + case .speaker: + imageName = "speaker" + backgroundColor = theme.colorForType(.CallControlBackground) + selectedTintColor = theme.colorForType(.CallButtonSelectedIconColor) + selectedBackgroundColor = theme.colorForType(.CallControlSelectedBackground) + case .video: + imageName = "video-call-30" + backgroundColor = theme.colorForType(.CallControlBackground) + selectedTintColor = theme.colorForType(.CallButtonSelectedIconColor) + selectedBackgroundColor = theme.colorForType(.CallControlSelectedBackground) + } + + tintColor = normalTintColor + + switch type { + case .mute: + let image = UIImage.templateNamed("mute") + setImage(image, for: .normal) + let image2 = UIImage.templateNamed("mute-selected") + setImage(image2, for: .selected) + default: + let image = UIImage.templateNamed(imageName) + setImage(image, for: UIControlState()) + } + + let backgroundImage = UIImage.imageWithColor(backgroundColor, size: CGSize(width: 1.0, height: 1.0)) + setBackgroundImage(backgroundImage, for:UIControlState()) + + if let selected = selectedBackgroundColor { + let backgroundImage = UIImage.imageWithColor(selected, size: CGSize(width: 1.0, height: 1.0)) + setBackgroundImage(backgroundImage, for:UIControlState.selected) + } + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override var intrinsicContentSize : CGSize { + switch buttonSize { + case .small: + return CGSize(width: Constants.SmallSize, height: Constants.SmallSize) + case .big: + return CGSize(width: Constants.BigSize, height: Constants.BigSize) + } + } +} diff --git a/Antidote/CallCoordinator.swift b/Antidote/CallCoordinator.swift new file mode 100644 index 0000000..1ef8ce5 --- /dev/null +++ b/Antidote/CallCoordinator.swift @@ -0,0 +1,396 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation +import CallKit + +protocol CallCoordinatorDelegate: class { + func callCoordinator(_ coordinator: CallCoordinator, notifyAboutBackgroundCallFrom caller: String, userInfo: String) + func callCoordinatorDidStartCall(_ coordinator: CallCoordinator) + func callCoordinatorDidFinishCall(_ coordinator: CallCoordinator) +} + +private struct Constants { + static let DeclineAfterInterval = 1.5 +} + +private class ActiveCall { + var callToken: RLMNotificationToken? + + fileprivate let call: OCTCall + fileprivate let navigation: UINavigationController + + fileprivate var usingFrontCamera: Bool = true + + init(call: OCTCall, navigation: UINavigationController) { + self.call = call + self.navigation = navigation + } + + deinit { + callToken?.invalidate() + } +} + +class CallCoordinator: NSObject { + weak var delegate: CallCoordinatorDelegate? + + fileprivate let theme: Theme + fileprivate weak var presentingController: UIViewController! + fileprivate weak var submanagerCalls: OCTSubmanagerCalls! + fileprivate weak var submanagerObjects: OCTSubmanagerObjects! + fileprivate var providerdelegate: ProviderDelegate! + + fileprivate let audioPlayer = AudioPlayer() + + fileprivate var activeCall: ActiveCall? { + didSet { + switch (oldValue, activeCall) { + case (.none, .some): + delegate?.callCoordinatorDidStartCall(self) + case (.some, .none): + delegate?.callCoordinatorDidFinishCall(self) + default: + break + } + } + } + + init(theme: Theme, presentingController: UIViewController, submanagerCalls: OCTSubmanagerCalls, submanagerObjects: OCTSubmanagerObjects) { + self.theme = theme + self.presentingController = presentingController + self.submanagerCalls = submanagerCalls + self.submanagerObjects = submanagerObjects + + super.init() + + // CALL: + print("cc:controler:init:01") + + submanagerCalls.delegate = self + } + + func callToChat(_ chat: OCTChat, enableVideo: Bool) { + + // CALL: + print("cc:controler:callToChat:01") + + do { + let call = try submanagerCalls.call(to: chat, enableAudio: true, enableVideo: enableVideo) + var nickname = String(localized: "contact_deleted") + + if let friend = chat.friends.lastObject() as? OCTFriend { + nickname = friend.nickname + } + + let controller = CallActiveController(theme: theme, callerName: nickname) + controller.delegate = self + + // CALL: + print("cc:controler:callToChat:02") + + startActiveCallWithCall(call, controller: controller) + } + catch let error as NSError { + handleErrorWithType(.callToChat, error: error) + } + } + + func answerIncomingCallWithUserInfo(_ userInfo: String) { + + // CALL: + print("cc:controler:answerIncomingCallWithUserInfo:01") + + guard let activeCall = activeCall else { return } + guard activeCall.call.uniqueIdentifier == userInfo else { return } + guard activeCall.call.status == .ringing else { return } + + answerCall(enableVideo: false) + } +} + +extension CallCoordinator: CoordinatorProtocol { + func startWithOptions(_ options: CoordinatorOptions?) { + } +} + +extension CallCoordinator: OCTSubmanagerCallDelegate { + func callSubmanager(_ callSubmanager: OCTSubmanagerCalls!, receive call: OCTCall!, audioEnabled: Bool, videoEnabled: Bool) { + guard activeCall == nil else { + // Currently we support only one call at a time + _ = try? submanagerCalls.send(.cancel, to: call) + return + } + + let nickname = call.caller?.nickname ?? "" + + // CALL: start incoming call + print("cc:controler:incoming_call:01") + + if !UIApplication.isActive { + delegate?.callCoordinator(self, notifyAboutBackgroundCallFrom: nickname, userInfo: call.uniqueIdentifier) + // CALL: start incoming call + print("cc:controler:incoming_call:BG") + + let backgroundTaskIdentifier = UIApplication.shared.beginBackgroundTask(expirationHandler: nil) + DispatchQueue.main.asyncAfter(wallDeadline: DispatchWallTime.now() + 0.1) { + AppDelegate.shared.displayIncomingCall(uuid: UUID(), handle: nickname, hasVideo: false) { _ in + UIApplication.shared.endBackgroundTask(backgroundTaskIdentifier) + } + } + } + + let controller = CallIncomingController(theme: theme, callerName: nickname) + controller.delegate = self + + startActiveCallWithCall(call, controller: controller) + + print("cc:controler:incoming_call:99") + } +} + +extension CallCoordinator: CallIncomingControllerDelegate { + func callIncomingControllerDecline(_ controller: CallIncomingController) { + // CALL: + print("cc:controler:callIncomingControllerDecline:01") + declineCall(callWasRemoved: false) + } + + func callIncomingControllerAnswerAudio(_ controller: CallIncomingController) { + // CALL: + print("cc:controler:callIncomingControllerAnswerAudio:01") + answerCall(enableVideo: false) + } + + func callIncomingControllerAnswerVideo(_ controller: CallIncomingController) { + // CALL: + print("cc:controler:callIncomingControllerAnswerVideo:01") + answerCall(enableVideo: true) + } +} + +extension CallCoordinator: CallActiveControllerDelegate { + func callActiveController(_ controller: CallActiveController, mute: Bool) { + submanagerCalls.enableMicrophone = !mute + } + + func callActiveController(_ controller: CallActiveController, speaker: Bool) { + do { + try submanagerCalls.routeAudio(toSpeaker: speaker) + } + catch { + handleErrorWithType(.routeAudioToSpeaker) + controller.speaker = !speaker + } + } + + func callActiveController(_ controller: CallActiveController, outgoingVideo: Bool) { + guard let activeCall = activeCall else { + assert(false, "This method should be called only if active call is non-nil") + return + } + + do { + try submanagerCalls.enableVideoSending(outgoingVideo, for: activeCall.call) + } + catch { + handleErrorWithType(.enableVideoSending) + controller.outgoingVideo = !outgoingVideo + } + } + + func callActiveControllerDecline(_ controller: CallActiveController) { + // CALL: + print("cc:controler:callActiveControllerDecline:02") + declineCall(callWasRemoved: false) + } + + func callActiveControllerSwitchCamera(_ controller: CallActiveController) { + guard let activeCall = activeCall else { + assert(false, "This method should be called only if active call is non-nil") + return + } + + do { + let front = !activeCall.usingFrontCamera + try submanagerCalls.switch(toCameraFront: front) + + self.activeCall?.usingFrontCamera = front + } + catch { + handleErrorWithType(.callSwitchCamera) + } + } +} + +extension CallCoordinator { + func declineCall(callWasRemoved wasRemoved: Bool) { + // CALL: + print("cc:controler:declineCall:01") + + guard let activeCall = activeCall else { + // assert(false, "This method should be called only if active call is non-nil") + return + } + + if !wasRemoved { + _ = try? submanagerCalls.send(.cancel, to: activeCall.call) + } + + audioPlayer.stopAll() + + if let controller = activeCall.navigation.topViewController as? CallBaseController { + controller.prepareForRemoval() + } + + let backgroundTaskIdentifier = UIApplication.shared.beginBackgroundTask(expirationHandler: nil) + DispatchQueue.main.asyncAfter(wallDeadline: DispatchWallTime.now() + 0.1) { + AppDelegate.shared.endIncomingCalls() + UIApplication.shared.endBackgroundTask(backgroundTaskIdentifier) + } + // self.providerdelegate.endIncomingCall() + + let delayTime = DispatchTime.now() + Double(Int64(Constants.DeclineAfterInterval * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC) + DispatchQueue.main.asyncAfter(deadline: delayTime) { [weak self] in + self?.presentingController.dismiss(animated: true, completion: nil) + self?.activeCall = nil + } + } + + func startActiveCallWithCall(_ call: OCTCall, controller: CallBaseController) { + guard activeCall == nil else { + assert(false, "This method should be called only if there is no active call") + return + } + + // CALL: + print("cc:controler:startActiveCallWithCall:01") + + let navigation = UINavigationController(rootViewController: controller) + navigation.modalPresentationStyle = .overCurrentContext + navigation.isNavigationBarHidden = true + navigation.modalTransitionStyle = .crossDissolve + + activeCall = ActiveCall(call: call, navigation: navigation) + + let predicate = NSPredicate(format: "uniqueIdentifier == %@", call.uniqueIdentifier) + let results = submanagerObjects.calls(predicate: predicate) + activeCall!.callToken = results.addNotificationBlock { [unowned self] change in + switch change { + case .initial: + break + case .update(_, let deletions, _, let modifications): + if deletions.count > 0 { + self.declineCall(callWasRemoved: true) + } + else if modifications.count > 0 { + self.activeCallWasUpdated() + } + case .error(let error): + fatalError("\(error)") + } + } + + presentingController.present(navigation, animated: true, completion: nil) + activeCallWasUpdated() + } + + func answerCall(enableVideo: Bool) { + + // CALL: + print("cc:controler:answerCall:01") + + guard let activeCall = activeCall else { + // assert(false, "This method should be called only if active call is non-nil") + return + } + + guard activeCall.call.status == .ringing else { + // assert(false, "Call status should be .Ringing") + return + } + + do { + try submanagerCalls.answer(activeCall.call, enableAudio: true, enableVideo: enableVideo) + } + catch let error as NSError { + handleErrorWithType(.answerCall, error: error) + + declineCall(callWasRemoved: false) + } + } + + func activeCallWasUpdated() { + + // CALL: + print("cc:controler:activeCallWasUpdated:01") + + guard let activeCall = activeCall else { + assert(false, "This method should be called only if active call is non-nil") + return + } + + switch activeCall.call.status { + case .ringing: + if !audioPlayer.isPlayingSound(.Ringtone) { + audioPlayer.playSound(.Ringtone, loop: true) + } + + // no update for ringing status + return + case .dialing: + if !audioPlayer.isPlayingSound(.Calltone) { + audioPlayer.playSound(.Calltone, loop: true) + } + case .active: + if audioPlayer.isPlaying() { + audioPlayer.stopAll() + } + } + + var activeController = activeCall.navigation.topViewController as? CallActiveController + + if (activeController == nil) { + let nickname = activeCall.call.caller?.nickname ?? "" + activeController = CallActiveController(theme: theme, callerName: nickname) + activeController!.delegate = self + + activeCall.navigation.setViewControllers([activeController!], animated: false) + } + + switch activeCall.call.status { + case .ringing: + break + case .dialing: + activeController!.state = .reaching + case .active: + activeController!.state = .active(duration: activeCall.call.callDuration) + } + + activeController!.outgoingVideo = activeCall.call.videoIsEnabled + if activeCall.call.videoIsEnabled { + if activeController!.videoPreviewLayer == nil { + submanagerCalls.getVideoCallPreview { [weak activeController] layer in + activeController?.videoPreviewLayer = layer + } + } + } + else { + if activeController!.videoPreviewLayer != nil { + activeController!.videoPreviewLayer = nil + } + } + + if activeCall.call.friendSendingVideo { + if activeController!.videoFeed == nil { + activeController!.videoFeed = submanagerCalls.videoFeed() + } + } + else { + if activeController!.videoFeed != nil { + activeController!.videoFeed = nil + } + } + } +} diff --git a/Antidote/CallIncomingController.swift b/Antidote/CallIncomingController.swift new file mode 100644 index 0000000..3cded60 --- /dev/null +++ b/Antidote/CallIncomingController.swift @@ -0,0 +1,125 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit +import SnapKit + +private struct Constants { + static let AvatarSize: CGFloat = 140.0 + + static let ButtonContainerTopMinOffset = 10.0 + static let ButtonContainerBottomOffset = -50.0 + + static let ButtonHorizontalOffset = 20.0 +} + +protocol CallIncomingControllerDelegate: class { + func callIncomingControllerDecline(_ controller: CallIncomingController) + func callIncomingControllerAnswerAudio(_ controller: CallIncomingController) + func callIncomingControllerAnswerVideo(_ controller: CallIncomingController) +} + +class CallIncomingController: CallBaseController { + weak var delegate: CallIncomingControllerDelegate? + + fileprivate var avatarView: UIImageView! + + fileprivate var buttonContainer: UIView! + fileprivate var declineButton: CallButton! + fileprivate var audioButton: CallButton! + fileprivate var videoButton: CallButton! + fileprivate var uuid_call: UUID! + + override func loadView() { + super.loadView() + + createViews() + installConstraints() + + infoLabel.text = String(localized: "call_incoming") + } + + override func viewDidLoad() { + super.viewDidLoad() + } + + override func prepareForRemoval() { + super.prepareForRemoval() + + declineButton.isEnabled = false + audioButton.isEnabled = false + videoButton.isEnabled = false + } +} + +// MARK: Actions +extension CallIncomingController { + @objc func declineButtonPressed() { + + // CALL: end incoming call + delegate?.callIncomingControllerDecline(self) + } + + @objc func audioButtonPressed() { + delegate?.callIncomingControllerAnswerAudio(self) + } + + @objc func videoButtonPressed() { + delegate?.callIncomingControllerAnswerVideo(self) + } +} + +private extension CallIncomingController { + func createViews() { + let avatarManager = AvatarManager(theme: theme) + + avatarView = UIImageView() + avatarView.image = avatarManager.avatarFromString(callerName, diameter: Constants.AvatarSize, type: .Call) + view.addSubview(avatarView) + + buttonContainer = UIView() + buttonContainer.backgroundColor = .clear + view.addSubview(buttonContainer) + + declineButton = CallButton(theme: theme, type: .decline, buttonSize: .small) + declineButton.addTarget(self, action: #selector(CallIncomingController.declineButtonPressed), for: .touchUpInside) + buttonContainer.addSubview(declineButton) + + audioButton = CallButton(theme: theme, type: .answerAudio, buttonSize: .small) + audioButton.addTarget(self, action: #selector(CallIncomingController.audioButtonPressed), for: .touchUpInside) + buttonContainer.addSubview(audioButton) + + videoButton = CallButton(theme: theme, type: .answerVideo, buttonSize: .small) + videoButton.addTarget(self, action: #selector(CallIncomingController.videoButtonPressed), for: .touchUpInside) + buttonContainer.addSubview(videoButton) + } + + func installConstraints() { + avatarView.snp.makeConstraints { + $0.center.equalTo(view) + } + + buttonContainer.snp.makeConstraints { + $0.centerX.equalTo(view) + $0.top.greaterThanOrEqualTo(avatarView.snp.bottom).offset(Constants.ButtonContainerTopMinOffset) + $0.bottom.equalTo(view).offset(Constants.ButtonContainerBottomOffset).priority(250) + } + + declineButton.snp.makeConstraints { + $0.top.bottom.equalTo(buttonContainer) + $0.leading.equalTo(buttonContainer) + } + + audioButton.snp.makeConstraints { + $0.top.bottom.equalTo(buttonContainer) + $0.leading.equalTo(declineButton.snp.trailing).offset(Constants.ButtonHorizontalOffset) + } + + videoButton.snp.makeConstraints { + $0.top.bottom.equalTo(buttonContainer) + $0.leading.equalTo(audioButton.snp.trailing).offset(Constants.ButtonHorizontalOffset) + $0.trailing.equalTo(buttonContainer) + } + } +} diff --git a/Antidote/CallManagement/Call.swift b/Antidote/CallManagement/Call.swift new file mode 100644 index 0000000..ce5dea9 --- /dev/null +++ b/Antidote/CallManagement/Call.swift @@ -0,0 +1,93 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +/** + * Copyright (c) 2017 Razeware LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +import Foundation + +enum CallState { + case connecting + case active + case held + case ended +} + +enum ConnectedState { + case pending + case complete +} + +/// represents a phone call +class Call { + + let uuid: UUID + let outgoing: Bool + let handle: String + + var state: CallState = .ended { + // didSet is a property observer + // https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Properties.html + didSet { + stateChanged?() + } + } + + var connectedState: ConnectedState = .pending { + didSet { + connectedStateChanged?() + } + } + + var stateChanged: (() -> Void)? + var connectedStateChanged: (() -> Void)? + + init(uuid: UUID, outgoing: Bool = false, handle: String) { + self.uuid = uuid + self.outgoing = outgoing + self.handle = handle + } + + func start(completion: ((_ success: Bool) -> Void)?) { + completion?(true) + + DispatchQueue.main.asyncAfter(wallDeadline: DispatchWallTime.now() + 3) { + self.state = .connecting + self.connectedState = .pending + + DispatchQueue.main.asyncAfter(wallDeadline: DispatchWallTime.now() + 1.5) { + self.state = .active + self.connectedState = .complete + } + } + } + + func answer() { + state = .active + } + + func end() { + state = .ended + } + +} diff --git a/Antidote/CallManagement/CallManager.swift b/Antidote/CallManagement/CallManager.swift new file mode 100644 index 0000000..d131373 --- /dev/null +++ b/Antidote/CallManagement/CallManager.swift @@ -0,0 +1,101 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +/** + * Copyright (c) 2017 Razeware LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +import Foundation +import CallKit + +class CallManager { + + var callsChangedHandler: (() -> Void)? + + private(set) var calls = [Call]() + + private let callController = CXCallController() + + func callWithUUID(uuid: UUID) -> Call? { + guard let index = calls.index(where: { $0.uuid == uuid }) else { + return nil + } + return calls[index] + } + + func add(call: Call) { + calls.append(call) + call.stateChanged = { [weak self] in + guard let strongSelf = self else { return } + strongSelf.callsChangedHandler?() + } + callsChangedHandler?() + } + + func startCall(handle: String, videoEnabled: Bool) { + let handle = CXHandle(type: .phoneNumber, value: handle) + // generate a new UUID, use it to instantiate startCallAction + let startCallAction = CXStartCallAction(call: UUID(), handle: handle) + + startCallAction.isVideo = videoEnabled + let transaction = CXTransaction(action: startCallAction) + + requestTransaction(transaction) + } + + func end(call: Call) { + let endCallAction = CXEndCallAction(call: call.uuid) + // wrap action in a transaction + let transaction = CXTransaction(action: endCallAction) + // send transaction to system + requestTransaction(transaction) + } + + func setHeld(call: Call, onHold: Bool) { + let setHeldCallAction = CXSetHeldCallAction(call: call.uuid, onHold: onHold) + let transaction = CXTransaction() + transaction.addAction(setHeldCallAction) + + requestTransaction(transaction) + } + + private func requestTransaction(_ transaction: CXTransaction) { + callController.request(transaction) { error in + if let error = error { + print("Error requesting transaction: \(error)") + } else { + print("Requested transaction successfully") + } + } + } + + func remove(call: Call) { + guard let index = calls.index(where: { $0 === call }) else { return } + calls.remove(at: index) + callsChangedHandler?() + } + + func removeAllCalls() { + calls.removeAll() + callsChangedHandler?() + } +} diff --git a/Antidote/CallManagement/ProviderDelegate.swift b/Antidote/CallManagement/ProviderDelegate.swift new file mode 100644 index 0000000..aba54eb --- /dev/null +++ b/Antidote/CallManagement/ProviderDelegate.swift @@ -0,0 +1,238 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// +// ProviderDelegate.swift +// Hotline +// +// Created by Steve Baker on 10/27/17. +// Copyright © 2017 Razeware LLC. All rights reserved. +// + +import AVFoundation +import CallKit +import os + +class ProviderDelegate: NSObject { + + fileprivate let callManager: CallManager + fileprivate let provider: CXProvider + + init(callManager: CallManager) { + os_log("ProviderDelegate:init") + self.callManager = callManager + provider = CXProvider(configuration: type(of: self).providerConfiguration) + + super.init() + + provider.setDelegate(self, queue: nil) + } + + // static var belongs to the type + // subclasses can't override static + static var providerConfiguration: CXProviderConfiguration { + // initialize + let providerConfiguration = CXProviderConfiguration(localizedName: "Antidote") + + // set call capabilities + providerConfiguration.supportsVideo = true + providerConfiguration.maximumCallsPerCallGroup = 2 // Signal Messenger seems to think 2 is needed + providerConfiguration.supportedHandleTypes = [.generic] + + return providerConfiguration + } + + func endIncomingCalls() { + + os_log("ProviderDelegate:endIncomingCalls") + + for call in callManager.calls { + os_log("ProviderDelegate:endcall") + provider.reportCall(with: call.uuid, endedAt: Date(), reason: .remoteEnded) + call.end() + } + + callManager.removeAllCalls() + } + + func reportIncomingCall(uuid: UUID, handle: String, hasVideo: Bool = false, completion: ((NSError?) -> Void)?) { + + os_log("ProviderDelegate:reportIncomingCall") + + // prepare update to send to system + let update = CXCallUpdate() + // add call metadata + update.remoteHandle = CXHandle(type: .generic, value: handle) + update.hasVideo = hasVideo + + // use provider to notify system + provider.reportNewIncomingCall(with: uuid, update: update) { error in + + // now we are inside reportNewIncomingCall's final argument, a completion block + if error == nil { + // no error, so add call + let call = Call(uuid: uuid, handle: handle) + self.callManager.add(call: call) + } + + // execute "completion", the final argument that was passed to outer method reportIncomingCall + // execute if it isn't nil + completion?(error as NSError?) + } + } + +} + +extension ProviderDelegate: CXProviderDelegate { + + func providerDidReset(_ provider: CXProvider) { + os_log("ProviderDelegate:providerDidReset") + + // stopAudio() + + for call in callManager.calls { + call.end() + } + + callManager.removeAllCalls() + } + + func provider(_ provider: CXProvider, didActivate audioSession: AVAudioSession) { + os_log("cc:ProviderDelegate:didActivate") + print("cc:ProviderDelegate:didActivate %@", audioSession) + + // HINT: audio session has to be started here! + + // also answer Tox Call ------------- + // -- HaXX0r -- + // -- HaXX0r -- + // -- HaXX0r -- + let coord = AppDelegate.shared.coordinator.activeCoordinator + let runcoord = coord as! RunningCoordinator + runcoord.activeSessionCoordinator?.callCoordinator.answerCall(enableVideo: false) + // -- HaXX0r -- + // -- HaXX0r -- + // -- HaXX0r -- + // also answer Tox Call ------------- + + // startAudio() + } + + func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) { + + os_log("cc:ProviderDelegate:call-answer %@", action) + + guard let call = callManager.callWithUUID(uuid: action.callUUID) else { + action.fail() + return + } + + // HINT: audio session has to be configured here! + configureAudioSession() + os_log("cc:ProviderDelegate:call-answer:answer()") + call.answer() + // when processing an action, app should fulfill it or fail + os_log("cc:ProviderDelegate:call-answer:fulfill()") + action.fulfill() + } + + func configureAudioSession() + { + os_log("cc:ProviderDelegate:configureAudioSession:start") + + let session = AVAudioSession.sharedInstance() + do { + try session.setCategory(AVAudioSessionCategoryPlayAndRecord) + os_log("cc:ProviderDelegate:configureAudioSession:try_001") + try session.setMode(AVAudioSessionModeVoiceChat) + os_log("cc:ProviderDelegate:configureAudioSession:try_002") + // try session.setActive(true) + // os_log("cc:ProviderDelegate:configureAudioSession:try_003") + } catch (let error) { + os_log("cc:ProviderDelegate:configureAudioSession:EE_01") + print("cc:ProviderDelegate:configureAudioSession:Error while configuring audio session: \(error)") + } + + os_log("ProviderDelegate:configureAudioSession:end") + } + + func provider(_ provider: CXProvider, perform action: CXEndCallAction) { + + os_log("ProviderDelegate:call-end %@", action) + + guard let call = callManager.callWithUUID(uuid: action.callUUID) else { + action.fail() + return + } + + // also decline Tox Call ------------- + // -- HaXX0r -- + // -- HaXX0r -- + // -- HaXX0r -- + let coord = AppDelegate.shared.coordinator.activeCoordinator + let runcoord = coord as! RunningCoordinator + runcoord.activeSessionCoordinator?.callCoordinator.declineCall(callWasRemoved: false) + // -- HaXX0r -- + // -- HaXX0r -- + // -- HaXX0r -- + // also decline Tox Call ------------- + + // stopAudio() + // call.end changes the call's status, allows other classes to react to new state + call.end() + action.fulfill() + callManager.remove(call: call) + } + + func provider(_ provider: CXProvider, perform action: CXSetHeldCallAction) { + + os_log("ProviderDelegate:call-held %@", action) + + guard let call = callManager.callWithUUID(uuid: action.callUUID) else { + action.fail() + return + } + + call.state = action.isOnHold ? .held : .active + + if call.state == .held { + // stopAudio() + } else { + // startAudio() + } + + action.fulfill() + } + + func provider(_ provider: CXProvider, perform action: CXStartCallAction) { + let call = Call(uuid: action.callUUID, outgoing: true, handle: action.handle.value) + // configure. provider(_:didActivate) will start audio + configureAudioSession() + + os_log("cc:ProviderDelegate:call-start %s", action.handle.value) + + // set connectedStateChanged as a closure to monitor call lifecycle + call.connectedStateChanged = { [weak self, weak call] in + guard let strongSelf = self, let call = call else { return } + + if call.connectedState == .pending { + strongSelf.provider.reportOutgoingCall(with: call.uuid, startedConnectingAt: nil) + } else if call.connectedState == .complete { + strongSelf.provider.reportOutgoingCall(with: call.uuid, connectedAt: nil) + } + } + + call.start { [weak self, weak call] success in + guard let strongSelf = self, let call = call else { return } + + if success { + action.fulfill() + strongSelf.callManager.add(call: call) + } else { + action.fail() + } + } + } + +} diff --git a/Antidote/ChangeAutodownloadImagesController.swift b/Antidote/ChangeAutodownloadImagesController.swift new file mode 100644 index 0000000..8e52003 --- /dev/null +++ b/Antidote/ChangeAutodownloadImagesController.swift @@ -0,0 +1,78 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit + +protocol ChangeAutodownloadImagesControllerDelegate: class { + func changeAutodownloadImagesControllerDidChange(_ controller: ChangeAutodownloadImagesController) +} + +class ChangeAutodownloadImagesController: StaticTableController { + weak var delegate: ChangeAutodownloadImagesControllerDelegate? + + fileprivate let userDefaults: UserDefaultsManager + fileprivate let selectedStatus: UserDefaultsManager.AutodownloadImages + + fileprivate let neverModel = StaticTableDefaultCellModel() + fileprivate let wifiModel = StaticTableDefaultCellModel() + fileprivate let alwaysModel = StaticTableDefaultCellModel() + + init(theme: Theme) { + self.userDefaults = UserDefaultsManager() + self.selectedStatus = userDefaults.autodownloadImages + + super.init(theme: theme, style: .plain, model: [ + [ + neverModel, + wifiModel, + alwaysModel, + ], + ]) + + updateModels() + + title = String(localized: "settings_autodownload_images") + } + + required convenience init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +private extension ChangeAutodownloadImagesController { + func updateModels() { + neverModel.value = String(localized: "settings_never") + neverModel.didSelectHandler = changeNever + + wifiModel.value = String(localized: "settings_using_wifi") + wifiModel.didSelectHandler = changeUsingWifi + + alwaysModel.value = String(localized: "settings_always") + alwaysModel.didSelectHandler = changeAlways + + switch selectedStatus { + case .Never: + neverModel.rightImageType = .checkmark + case .UsingWiFi: + wifiModel.rightImageType = .checkmark + case .Always: + alwaysModel.rightImageType = .checkmark + } + } + + func changeNever(_: StaticTableBaseCell) { + userDefaults.autodownloadImages = .Never + delegate?.changeAutodownloadImagesControllerDidChange(self) + } + + func changeUsingWifi(_: StaticTableBaseCell) { + userDefaults.autodownloadImages = .UsingWiFi + delegate?.changeAutodownloadImagesControllerDidChange(self) + } + + func changeAlways(_: StaticTableBaseCell) { + userDefaults.autodownloadImages = .Always + delegate?.changeAutodownloadImagesControllerDidChange(self) + } +} diff --git a/Antidote/ChangePasswordController.swift b/Antidote/ChangePasswordController.swift new file mode 100644 index 0000000..b379d50 --- /dev/null +++ b/Antidote/ChangePasswordController.swift @@ -0,0 +1,254 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit +import SnapKit + +private struct Constants { + static let HorizontalOffset = 40.0 + static let ButtonVerticalOffset = 20.0 + static let FieldsOffset = 10.0 + + static let MaxFormWidth = 350.0 +} + +protocol ChangePasswordControllerDelegate: class { + func changePasswordControllerDidFinishPresenting(_ controller: ChangePasswordController) +} + +class ChangePasswordController: KeyboardNotificationController { + weak var delegate: ChangePasswordControllerDelegate? + + fileprivate let theme: Theme + + fileprivate weak var toxManager: OCTManager! + + fileprivate var scrollView: UIScrollView! + fileprivate var containerView: IncompressibleView! + + fileprivate var oldPasswordField: ExtendedTextField! + fileprivate var newPasswordField: ExtendedTextField! + fileprivate var repeatPasswordField: ExtendedTextField! + fileprivate var button: RoundedButton! + + init(theme: Theme, toxManager: OCTManager) { + self.theme = theme + self.toxManager = toxManager + + super.init() + + edgesForExtendedLayout = UIRectEdge() + addNavigationButtons() + + title = String(localized: "change_password") + } + + required convenience init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func loadView() { + loadViewWithBackgroundColor(theme.colorForType(.NormalBackground)) + + createViews() + installConstraints() + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + if let old = oldPasswordField { + _ = old.becomeFirstResponder() + } + else if let new = newPasswordField { + _ = new.becomeFirstResponder() + } + } + + override func keyboardWillShowAnimated(keyboardFrame frame: CGRect) { + scrollView.contentInset.bottom = frame.size.height + scrollView.scrollIndicatorInsets.bottom = frame.size.height + } + + override func keyboardWillHideAnimated(keyboardFrame frame: CGRect) { + scrollView.contentInset.bottom = 0.0 + scrollView.scrollIndicatorInsets.bottom = 0.0 + } + + override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + + scrollView.contentSize.width = scrollView.frame.size.width + scrollView.contentSize.height = containerView.frame.maxY + } +} + +// MARK: Actions +extension ChangePasswordController { + @objc func cancelButtonPressed() { + delegate?.changePasswordControllerDidFinishPresenting(self) + } + + @objc func buttonPressed() { + guard validatePasswordFields() else { + return + } + + let oldPassword = oldPasswordField.text! + let newPassword = newPasswordField.text! + + let hud = JGProgressHUD(style: .dark) + hud?.show(in: view) + + DispatchQueue.global(qos: .default).async { [unowned self] in + let result = self.toxManager.changeEncryptPassword(newPassword, oldPassword: oldPassword) + + if result { + let keychainManager = KeychainManager() + if keychainManager.toxPasswordForActiveAccount != nil { + keychainManager.toxPasswordForActiveAccount = newPassword + } + } + + DispatchQueue.main.async { [unowned self] in + hud?.dismiss() + + if result { + self.delegate?.changePasswordControllerDidFinishPresenting(self) + } + else { + handleErrorWithType(.wrongOldPassword) + } + } + } + } +} + +extension ChangePasswordController: ExtendedTextFieldDelegate { + func loginExtendedTextFieldReturnKeyPressed(_ field: ExtendedTextField) { + if field === oldPasswordField { + _ = newPasswordField!.becomeFirstResponder() + } + else if field === newPasswordField { + _ = repeatPasswordField!.becomeFirstResponder() + } + else if field === repeatPasswordField { + buttonPressed() + } + } +} + +private extension ChangePasswordController { + func addNavigationButtons() { + navigationItem.leftBarButtonItem = UIBarButtonItem( + barButtonSystemItem: .cancel, + target: self, + action: #selector(ChangePasswordController.cancelButtonPressed)) + } + + func createViews() { + scrollView = UIScrollView() + view.addSubview(scrollView) + + containerView = IncompressibleView() + containerView.backgroundColor = .clear + scrollView.addSubview(containerView) + + button = RoundedButton(theme: theme, type: .runningPositive) + button.setTitle(String(localized: "change_password_done"), for: UIControlState()) + button.addTarget(self, action: #selector(ChangePasswordController.buttonPressed), for: .touchUpInside) + containerView.addSubview(button) + + oldPasswordField = createPasswordFieldWithTitle(String(localized: "old_password")) + newPasswordField = createPasswordFieldWithTitle(String(localized: "new_password")) + repeatPasswordField = createPasswordFieldWithTitle(String(localized: "repeat_password")) + + oldPasswordField.returnKeyType = .next + newPasswordField.returnKeyType = .next + repeatPasswordField.returnKeyType = .done + } + + func createPasswordFieldWithTitle(_ title: String) -> ExtendedTextField { + let field = ExtendedTextField(theme: theme, type: .normal) + field.delegate = self + field.title = title + field.secureTextEntry = true + containerView.addSubview(field) + + return field + } + + func installConstraints() { + scrollView.snp.makeConstraints { + $0.edges.equalTo(view) + } + + containerView.customIntrinsicContentSize.width = CGFloat(Constants.MaxFormWidth) + containerView.snp.makeConstraints { + $0.top.equalTo(scrollView) + $0.centerX.equalTo(scrollView) + $0.width.lessThanOrEqualTo(Constants.MaxFormWidth) + $0.width.lessThanOrEqualTo(scrollView).offset(-2 * Constants.HorizontalOffset) + } + + var topConstraint = containerView.snp.top + + if installConstraintsForField(oldPasswordField, topConstraint: topConstraint) { + topConstraint = oldPasswordField!.snp.bottom + } + + if installConstraintsForField(newPasswordField, topConstraint: topConstraint) { + topConstraint = newPasswordField!.snp.bottom + } + + if installConstraintsForField(repeatPasswordField, topConstraint: topConstraint) { + topConstraint = repeatPasswordField!.snp.bottom + } + + button.snp.makeConstraints { + $0.top.equalTo(topConstraint).offset(Constants.ButtonVerticalOffset) + $0.leading.trailing.equalTo(containerView) + $0.bottom.equalTo(containerView) + } + } + + /** + Returns true if field exists, no otherwise. + */ + func installConstraintsForField(_ field: ExtendedTextField?, topConstraint: ConstraintItem) -> Bool { + guard let field = field else { + return false + } + + field.snp.makeConstraints { + $0.top.equalTo(topConstraint).offset(Constants.FieldsOffset) + $0.leading.trailing.equalTo(containerView) + } + + return true + } + + func validatePasswordFields() -> Bool { + guard let oldText = oldPasswordField.text, !oldText.isEmpty else { + handleErrorWithType(.passwordIsEmpty) + return false + } + guard let newText = newPasswordField.text, !newText.isEmpty else { + handleErrorWithType(.passwordIsEmpty) + return false + } + + guard let repeatText = repeatPasswordField.text, !repeatText.isEmpty else { + handleErrorWithType(.passwordIsEmpty) + return false + } + + guard newText == repeatText else { + handleErrorWithType(.passwordsDoNotMatch) + return false + } + + return true + } +} diff --git a/Antidote/ChangePinTimeoutController.swift b/Antidote/ChangePinTimeoutController.swift new file mode 100644 index 0000000..8628e6d --- /dev/null +++ b/Antidote/ChangePinTimeoutController.swift @@ -0,0 +1,111 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit + +protocol ChangePinTimeoutControllerDelegate: class { + func changePinTimeoutControllerDone(_ controller: ChangePinTimeoutController) +} + +class ChangePinTimeoutController: StaticTableController { + weak var delegate: ChangePinTimeoutControllerDelegate? + + fileprivate weak var submanagerObjects: OCTSubmanagerObjects! + + fileprivate let immediatelyModel = StaticTableDefaultCellModel() + fileprivate let seconds30Model = StaticTableDefaultCellModel() + fileprivate let minute1Model = StaticTableDefaultCellModel() + fileprivate let minute2Model = StaticTableDefaultCellModel() + fileprivate let minute5Model = StaticTableDefaultCellModel() + + init(theme: Theme, submanagerObjects: OCTSubmanagerObjects) { + self.submanagerObjects = submanagerObjects + + super.init(theme: theme, style: .plain, model: [ + [ + immediatelyModel, + seconds30Model, + minute1Model, + minute2Model, + minute5Model, + ], + ]) + + updateModels() + + title = String(localized: "pin_lock_timeout") + } + + required convenience init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +private extension ChangePinTimeoutController { + func updateModels() { + let settings = submanagerObjects.getProfileSettings() + + immediatelyModel.value = String(localized: "pin_lock_immediately") + immediatelyModel.didSelectHandler = immediatelyHandler + immediatelyModel.rightImageType = .none + + seconds30Model.value = String(localized: "pin_lock_30_seconds") + seconds30Model.didSelectHandler = seconds30Handler + seconds30Model.rightImageType = .none + + minute1Model.value = String(localized: "pin_lock_1_minute") + minute1Model.didSelectHandler = minute1Handler + minute1Model.rightImageType = .none + + minute2Model.value = String(localized: "pin_lock_2_minutes") + minute2Model.didSelectHandler = minute2Handler + minute2Model.rightImageType = .none + + minute5Model.value = String(localized: "pin_lock_5_minutes") + minute5Model.didSelectHandler = minute5Handler + minute5Model.rightImageType = .none + + + switch settings.lockTimeout { + case .Immediately: + immediatelyModel.rightImageType = .checkmark + case .Seconds30: + seconds30Model.rightImageType = .checkmark + case .Minute1: + minute1Model.rightImageType = .checkmark + case .Minute2: + minute2Model.rightImageType = .checkmark + case .Minute5: + minute5Model.rightImageType = .checkmark + } + } + + func immediatelyHandler(_: StaticTableBaseCell) { + selectedTimeout(.Immediately) + } + + func seconds30Handler(_: StaticTableBaseCell) { + selectedTimeout(.Seconds30) + } + + func minute1Handler(_: StaticTableBaseCell) { + selectedTimeout(.Minute1) + } + + func minute2Handler(_: StaticTableBaseCell) { + selectedTimeout(.Minute2) + } + + func minute5Handler(_: StaticTableBaseCell) { + selectedTimeout(.Minute5) + } + + func selectedTimeout(_ timeout: ProfileSettings.LockTimeout) { + let settings = submanagerObjects.getProfileSettings() + settings.lockTimeout = timeout + submanagerObjects.saveProfileSettings(settings) + + delegate?.changePinTimeoutControllerDone(self) + } +} diff --git a/Antidote/ChangeUserStatusController.swift b/Antidote/ChangeUserStatusController.swift new file mode 100644 index 0000000..3ffc55f --- /dev/null +++ b/Antidote/ChangeUserStatusController.swift @@ -0,0 +1,81 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit + +protocol ChangeUserStatusControllerDelegate: class { + func changeUserStatusController(_ controller: ChangeUserStatusController, selectedStatus: OCTToxUserStatus) +} + +class ChangeUserStatusController: StaticTableController { + weak var delegate: ChangeUserStatusControllerDelegate? + + fileprivate let selectedStatus: OCTToxUserStatus + + fileprivate let onlineModel = StaticTableDefaultCellModel() + fileprivate let awayModel = StaticTableDefaultCellModel() + fileprivate let busyModel = StaticTableDefaultCellModel() + + init(theme: Theme, selectedStatus: OCTToxUserStatus) { + self.selectedStatus = selectedStatus + + super.init(theme: theme, style: .plain, model: [ + [ + onlineModel, + awayModel, + busyModel, + ], + ]) + + updateModels() + + title = String(localized: "status_title") + } + + required convenience init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +private extension ChangeUserStatusController { + func updateModels() { + // Hardcoding any connected status to show only online/away/busy statuses here. + let online = UserStatus(connectionStatus: OCTToxConnectionStatus.TCP, userStatus: OCTToxUserStatus.none) + let away = UserStatus(connectionStatus: OCTToxConnectionStatus.TCP, userStatus: OCTToxUserStatus.away) + let busy = UserStatus(connectionStatus: OCTToxConnectionStatus.TCP, userStatus: OCTToxUserStatus.busy) + + onlineModel.userStatus = online + onlineModel.value = online.toString() + onlineModel.didSelectHandler = changeOnlineStatus + + awayModel.userStatus = away + awayModel.value = away.toString() + awayModel.didSelectHandler = changeAwayStatus + + busyModel.userStatus = busy + busyModel.value = busy.toString() + busyModel.didSelectHandler = changeBusyStatus + + switch selectedStatus { + case .none: + onlineModel.rightImageType = .checkmark + case .away: + awayModel.rightImageType = .checkmark + case .busy: + busyModel.rightImageType = .checkmark + } + } + + func changeOnlineStatus(_: StaticTableBaseCell) { + delegate?.changeUserStatusController(self, selectedStatus: .none) + } + + func changeAwayStatus(_: StaticTableBaseCell) { + delegate?.changeUserStatusController(self, selectedStatus: .away) + } + + func changeBusyStatus(_: StaticTableBaseCell) { + delegate?.changeUserStatusController(self, selectedStatus: .busy) + } +} diff --git a/Antidote/ChatBaseTextCell.swift b/Antidote/ChatBaseTextCell.swift new file mode 100644 index 0000000..5735e4c --- /dev/null +++ b/Antidote/ChatBaseTextCell.swift @@ -0,0 +1,100 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit + +class ChatBaseTextCell: ChatMovableDateCell { + struct Constants { + static let BubbleVerticalOffset = 1.0 + static let BubbleHorizontalOffset = 10.0 + } + + var bubbleNormalBackground: UIColor? + var bubbleView: BubbleView! + + override func setupWithTheme(_ theme: Theme, model: BaseCellModel) { + super.setupWithTheme(theme, model: model) + + guard let textModel = model as? ChatBaseTextCellModel else { + assert(false, "Wrong model \(model) passed to cell \(self)") + return + } + + canBeCopied = true + bubbleView.text = textModel.message + bubbleView.textColor = theme.colorForType(.NormalText) + } + + override func createViews() { + super.createViews() + + bubbleView = BubbleView() + contentView.addSubview(bubbleView) + } + + override func setEditing(_ editing: Bool, animated: Bool) { + super.setEditing(editing, animated: animated) + + bubbleView.isUserInteractionEnabled = !editing + } + + override func setHighlighted(_ highlighted: Bool, animated: Bool) { + super.setHighlighted(highlighted, animated: animated) + bubbleView.backgroundColor = bubbleNormalBackground + } + + override func setSelected(_ selected: Bool, animated: Bool) { + super.setSelected(selected, animated: animated) + + if isEditing { + bubbleView.backgroundColor = bubbleNormalBackground + return + } + + if selected { + bubbleView.backgroundColor = bubbleNormalBackground?.darkerColor() + } + else { + bubbleView.backgroundColor = bubbleNormalBackground + } + } +} + +// Accessibility +extension ChatBaseTextCell { + override var accessibilityValue: String? { + get { + var value = bubbleView.text! + if let sValue = super.accessibilityValue { + value += ", " + sValue + } + + return value + } + set {} + } +} + +// ChatEditable +extension ChatBaseTextCell { + override func shouldShowMenu() -> Bool { + return true + } + + override func menuTargetRect() -> CGRect { + return bubbleView.frame + } + + override func willShowMenu() { + super.willShowMenu() + + bubbleView.selectable = false + } + + override func willHideMenu() { + super.willHideMenu() + + bubbleView.selectable = true + } +} diff --git a/Antidote/ChatBaseTextCellModel.swift b/Antidote/ChatBaseTextCellModel.swift new file mode 100644 index 0000000..9dbe82e --- /dev/null +++ b/Antidote/ChatBaseTextCellModel.swift @@ -0,0 +1,9 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +class ChatBaseTextCellModel: ChatMovableDateCellModel { + var message: String = "" +} diff --git a/Antidote/ChatBottomStatusViewManager.swift b/Antidote/ChatBottomStatusViewManager.swift new file mode 100644 index 0000000..e2ff37e --- /dev/null +++ b/Antidote/ChatBottomStatusViewManager.swift @@ -0,0 +1,88 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// +// ChatBottomStatusViewManager.swift +// Antidote +// +// Created by Dmytro Vorobiov on 26/04/2017. +// Copyright © 2017 dvor. All rights reserved. +// + +import Foundation + +class ChatBottomStatusViewManager { + fileprivate weak var submanagerObjects: OCTSubmanagerObjects! + + fileprivate let friend: OCTFriend? + fileprivate let undeliveredMessages: Results + + fileprivate var friendToken: RLMNotificationToken? + fileprivate var undeliveredMessagesToken: RLMNotificationToken? + + init(friend: OCTFriend?, messages: Results, submanagerObjects: OCTSubmanagerObjects) { + self.submanagerObjects = submanagerObjects + self.friend = friend + self.undeliveredMessages = messages.undeliveredMessages() + + addFriendNotification() + addMessagesNotification() + } + + deinit { + friendToken?.invalidate() + undeliveredMessagesToken?.invalidate() + } +} + +private extension ChatBottomStatusViewManager { + func addFriendNotification() { + guard let friend = self.friend else { + return + } + + friendToken = submanagerObjects.notificationBlock(for: friend) { [unowned self] change in + switch change { + case .initial: + break + case .update: + self.updateTableHeaderView() + case .error(let error): + break + } + } + } + + func addMessagesNotification() { + // self.undeliveredMessagesToken = undeliveredMessages.addNotificationBlock { [unowned self] change in + // guard let tableView = self.tableView else { + // return + // } + // switch change { + // case .initial: + // break + // case .update(_, let deletions, let insertions, let modifications): + // tableView.beginUpdates() + // self.updateTableViewWithDeletions(deletions) + // self.updateTableViewWithInsertions(insertions) + // self.updateTableViewWithModifications(modifications) + + // self.visibleMessages = self.visibleMessages + insertions.count - deletions.count + // tableView.endUpdates() + + // self.updateTableHeaderView() + + // if insertions.contains(0) { + // self.handleNewMessage() + // } + // case .error(let error): + // fatalError("\(error)") + // } + // } + } + + func updateTableHeaderView() { + + } +} diff --git a/Antidote/ChatEditable.swift b/Antidote/ChatEditable.swift new file mode 100644 index 0000000..196b4b0 --- /dev/null +++ b/Antidote/ChatEditable.swift @@ -0,0 +1,29 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +/** + Chat cell can confirm to this protocol to support editing with UIMenuController. + */ +protocol ChatEditable { + /** + Return true to show menu for given cell, false otherwise. + */ + func shouldShowMenu() -> Bool + + /** + Target rect in view to show menu from. + + - Returns: rect to show menu from. + */ + func menuTargetRect() -> CGRect + + /** + Methods fired when menu is going to be shown/hide. + If you override this methods, you must call super at some point in your implementation. + */ + func willShowMenu() + func willHideMenu() +} diff --git a/Antidote/ChatFauxOfflineHeaderView.swift b/Antidote/ChatFauxOfflineHeaderView.swift new file mode 100644 index 0000000..7ddc86f --- /dev/null +++ b/Antidote/ChatFauxOfflineHeaderView.swift @@ -0,0 +1,49 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation +import SnapKit + +fileprivate struct Constants { + static let verticalOffset = 7.0 + static let maxLabelWidth: CGFloat = 280.0 +} + +class ChatFauxOfflineHeaderView: UIView { + fileprivate var label: UILabel! + + init(theme: Theme) { + super.init(frame: CGRect.zero) + + backgroundColor = theme.colorForType(.NormalBackground) + createViews(theme: theme) + installConstraints() + } + + required convenience init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +private extension ChatFauxOfflineHeaderView { + func createViews(theme: Theme) { + label = UILabel() + label.text = String(localized: "chat_pending_faux_offline_messages") + label.font = UIFont.antidoteFontWithSize(14.0, weight: .medium) + label.textAlignment = .center + label.textColor = theme.colorForType(.ChatInformationText) + label.numberOfLines = 0 + label.preferredMaxLayoutWidth = Constants.maxLabelWidth + addSubview(label) + } + + func installConstraints() { + label.snp.makeConstraints { + $0.top.equalTo(self).offset(Constants.verticalOffset) + $0.bottom.equalTo(self).offset(-Constants.verticalOffset) + $0.centerX.equalTo(self) + $0.width.equalTo(Constants.maxLabelWidth) + } + } +} diff --git a/Antidote/ChatGenericFileCell.swift b/Antidote/ChatGenericFileCell.swift new file mode 100644 index 0000000..39c95e5 --- /dev/null +++ b/Antidote/ChatGenericFileCell.swift @@ -0,0 +1,178 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit +import SnapKit + +class ChatGenericFileCell: ChatMovableDateCell { + var loadingView: LoadingImageView! + var cancelButton: UIButton! + var retryButton: UIButton! + + var progressObject: ChatProgressProtocol? { + didSet { + progressObject?.updateProgress = { [weak self] (progress: Float) -> Void in + self?.updateProgress(CGFloat(progress)) + } + + progressObject?.updateEta = { [weak self] (eta: CFTimeInterval, bytesPerSecond: OCTToxFileSize) -> Void in + self?.updateEta(String(timeInterval: eta)) + self?.updateBytesPerSecond(bytesPerSecond) + } + } + } + + var state: ChatGenericFileCellModel.State = .waitingConfirmation + + var startLoadingHandle: (() -> Void)? + var cancelHandle: (() -> Void)? + var retryHandle: (() -> Void)? + var pauseOrResumeHandle: (() -> Void)? + var openHandle: (() -> Void)? + + /** + This method should be called after setupWithTheme:model: + */ + func setButtonImage(_ image: UIImage) { + let square: UIImage + + canBeCopied = true + + if image.size.width == image.size.height { + square = image + } + else { + let side = min(image.size.width, image.size.height) + let x = (image.size.width - side) / 2 + let y = (image.size.height - side) / 2 + let rect = CGRect(x: x, y: y, width: side, height: side) + + square = image.cropWithRect(rect) + } + + loadingView.imageButton.setBackgroundImage(square, for: UIControlState()) + + if state == .waitingConfirmation || state == .done { + loadingView.centerImageView.image = nil + } + } + + override func setupWithTheme(_ theme: Theme, model: BaseCellModel) { + super.setupWithTheme(theme, model: model) + + guard let fileModel = model as? ChatGenericFileCellModel else { + assert(false, "Wrong model \(model) passed to cell \(self)") + return + } + + state = fileModel.state + startLoadingHandle = fileModel.startLoadingHandle + cancelHandle = fileModel.cancelHandle + retryHandle = fileModel.retryHandle + pauseOrResumeHandle = fileModel.pauseOrResumeHandle + openHandle = fileModel.openHandle + + canBeCopied = false + + switch state { + case .loading: + loadingView.centerImageView.image = UIImage.templateNamed("chat-file-pause-big") + case .paused: + loadingView.centerImageView.image = UIImage.templateNamed("chat-file-play-big") + case .waitingConfirmation: + fallthrough + case .cancelled: + fallthrough + case .done: + var fileExtension: String? = nil + + if let fileName = fileModel.fileName { + fileExtension = (fileName as NSString).pathExtension + } + + loadingView.setImageWithUti(fileModel.fileUTI, fileExtension: fileExtension) + } + + updateViewsWithState(fileModel.state, fileModel: fileModel) + + loadingView.imageButton.setImage(nil, for: UIControlState()) + + let backgroundColor = theme.colorForType(.FileImageBackgroundActive) + let backgroundImage = UIImage.imageWithColor(backgroundColor, size: CGSize(width: 1.0, height: 1.0)) + loadingView.imageButton.setBackgroundImage(backgroundImage, for: UIControlState()) + + loadingView.progressView.backgroundLineColor = theme.colorForType(.FileImageAcceptButtonTint).withAlphaComponent(0.3) + loadingView.progressView.lineColor = theme.colorForType(.FileImageAcceptButtonTint) + + loadingView.centerImageView.tintColor = theme.colorForType(.FileImageAcceptButtonTint) + + loadingView.topLabel.textColor = theme.colorForType(.FileImageCancelledText) + loadingView.bottomLabel.textColor = theme.colorForType(.FileImageCancelledText) + + cancelButton.tintColor = theme.colorForType(.FileImageCancelButtonTint) + retryButton.tintColor = theme.colorForType(.FileImageCancelButtonTint) + } + + override func createViews() { + super.createViews() + + loadingView = LoadingImageView() + loadingView.pressedHandle = loadingViewPressed + + let cancelImage = UIImage.templateNamed("chat-file-cancel") + + cancelButton = UIButton() + cancelButton.setImage(cancelImage, for: UIControlState()) + cancelButton.addTarget(self, action: #selector(ChatGenericFileCell.cancelButtonPressed), for: .touchUpInside) + + let retryImage = UIImage.templateNamed("chat-file-retry") + + retryButton = UIButton() + retryButton.setImage(retryImage, for: UIControlState()) + retryButton.addTarget(self, action: #selector(ChatGenericFileCell.retryButtonPressed), for: .touchUpInside) + } + + override func setEditing(_ editing: Bool, animated: Bool) { + super.setEditing(editing, animated: animated) + + loadingView.isUserInteractionEnabled = !editing + cancelButton.isUserInteractionEnabled = !editing + retryButton.isUserInteractionEnabled = !editing + } + + func updateProgress(_ progress: CGFloat) { + loadingView.progressView.progress = progress + } + + func updateEta(_ eta: String) { + loadingView.bottomLabel.text = eta + } + + func updateBytesPerSecond(_ bytesPerSecond: OCTToxFileSize) {} + + @objc func cancelButtonPressed() { + cancelHandle?() + } + + @objc func retryButtonPressed() { + retryHandle?() + } + + /// Override in subclass + func updateViewsWithState(_ state: ChatGenericFileCellModel.State, fileModel: ChatGenericFileCellModel) {} + + /// Override in subclass + func loadingViewPressed() {} +} + +// ChatEditable +extension ChatGenericFileCell { + override func shouldShowMenu() -> Bool { + return true + } + + override func menuTargetRect() -> CGRect { + return loadingView.frame + } +} diff --git a/Antidote/ChatGenericFileCellModel.swift b/Antidote/ChatGenericFileCellModel.swift new file mode 100644 index 0000000..1c9a573 --- /dev/null +++ b/Antidote/ChatGenericFileCellModel.swift @@ -0,0 +1,26 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +class ChatGenericFileCellModel: ChatMovableDateCellModel { + enum State { + case waitingConfirmation + case loading + case paused + case cancelled + case done + } + + var state: State = .waitingConfirmation + var fileName: String? + var fileSize: String? + var fileUTI: String? + + var startLoadingHandle: (() -> Void)? + var cancelHandle: (() -> Void)? + var retryHandle: (() -> Void)? + var pauseOrResumeHandle: (() -> Void)? + var openHandle: (() -> Void)? +} diff --git a/Antidote/ChatIncomingCallCell.swift b/Antidote/ChatIncomingCallCell.swift new file mode 100644 index 0000000..23ace11 --- /dev/null +++ b/Antidote/ChatIncomingCallCell.swift @@ -0,0 +1,86 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit +import SnapKit + +private struct Constants { + static let LeftOffset = 20.0 + static let ImageViewToLabelOffset = 5.0 + static let ImageViewYOffset = -1.0 + static let VerticalOffset = 8.0 +} + +class ChatIncomingCallCell: ChatMovableDateCell { + fileprivate var callImageView: UIImageView! + fileprivate var label: UILabel! + + override func setupWithTheme(_ theme: Theme, model: BaseCellModel) { + super.setupWithTheme(theme, model: model) + + guard let incomingModel = model as? ChatIncomingCallCellModel else { + assert(false, "Wrong model \(model) passed to cell \(self)") + return + } + + label.textColor = theme.colorForType(.ChatListCellMessage) + callImageView.tintColor = theme.colorForType(.LinkText) + + if incomingModel.answered { + label.text = String(localized: "chat_call_message") + String(timeInterval: incomingModel.callDuration) + } + else { + label.text = String(localized: "chat_missed_call_message") + } + } + + override func createViews() { + super.createViews() + + let image = UIImage.templateNamed("start-call-small") + + callImageView = UIImageView(image: image) + contentView.addSubview(callImageView) + + label = UILabel() + label.font = UIFont.antidoteFontWithSize(16.0, weight: .light) + contentView.addSubview(label) + } + + override func installConstraints() { + super.installConstraints() + + callImageView.snp.makeConstraints { + $0.centerY.equalTo(label).offset(Constants.ImageViewYOffset) + $0.leading.equalTo(contentView).offset(Constants.LeftOffset) + } + + label.snp.makeConstraints { + $0.top.equalTo(contentView).offset(Constants.VerticalOffset) + $0.bottom.equalTo(contentView).offset(-Constants.VerticalOffset) + $0.leading.equalTo(callImageView.snp.trailing).offset(Constants.ImageViewToLabelOffset) + } + } +} + +// Accessibility +extension ChatIncomingCallCell { + override var accessibilityLabel: String? { + get { + return label.text + } + set {} + } +} + +// ChatEditable +extension ChatIncomingCallCell { + override func shouldShowMenu() -> Bool { + return true + } + + override func menuTargetRect() -> CGRect { + return label.frame + } +} diff --git a/Antidote/ChatIncomingCallCellModel.swift b/Antidote/ChatIncomingCallCellModel.swift new file mode 100644 index 0000000..136c7ee --- /dev/null +++ b/Antidote/ChatIncomingCallCellModel.swift @@ -0,0 +1,10 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +class ChatIncomingCallCellModel: ChatMovableDateCellModel { + var callDuration: TimeInterval = 0 + var answered: Bool = true +} diff --git a/Antidote/ChatIncomingFileCell.swift b/Antidote/ChatIncomingFileCell.swift new file mode 100644 index 0000000..acb8947 --- /dev/null +++ b/Antidote/ChatIncomingFileCell.swift @@ -0,0 +1,88 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit +import SnapKit + +private struct Constants { + static let BigOffset = 20.0 + static let SmallOffset = 8.0 + static let ImageButtonSize = 180.0 + static let CloseButtonSize = 25.0 +} + +class ChatIncomingFileCell: ChatGenericFileCell { + override func setButtonImage(_ image: UIImage) { + super.setButtonImage(image) + loadingView.bottomLabel.isHidden = true + } + + override func createViews() { + super.createViews() + + contentView.addSubview(loadingView) + contentView.addSubview(cancelButton) + } + + override func installConstraints() { + super.installConstraints() + + loadingView.snp.makeConstraints { + $0.leading.equalTo(contentView).offset(Constants.BigOffset) + $0.top.equalTo(contentView).offset(Constants.SmallOffset) + $0.bottom.equalTo(contentView).offset(-Constants.SmallOffset) + $0.size.equalTo(Constants.ImageButtonSize) + } + + cancelButton.snp.makeConstraints { + $0.leading.equalTo(loadingView.snp.trailing).offset(Constants.SmallOffset) + $0.top.equalTo(loadingView) + $0.size.equalTo(Constants.CloseButtonSize) + } + } + + override func updateViewsWithState(_ state: ChatGenericFileCellModel.State, fileModel: ChatGenericFileCellModel) { + loadingView.imageButton.isUserInteractionEnabled = true + loadingView.progressView.isHidden = true + loadingView.topLabel.isHidden = false + loadingView.topLabel.text = fileModel.fileName + loadingView.bottomLabel.text = fileModel.fileSize + loadingView.bottomLabel.isHidden = false + + cancelButton.isHidden = false + + switch state { + case .waitingConfirmation: + loadingView.centerImageView.image = UIImage.templateNamed("chat-file-download-big") + case .loading: + loadingView.progressView.isHidden = false + case .paused: + break + case .cancelled: + loadingView.setCancelledImage() + loadingView.imageButton.isUserInteractionEnabled = false + cancelButton.isHidden = true + loadingView.bottomLabel.text = String(localized: "chat_file_cancelled") + case .done: + cancelButton.isHidden = true + loadingView.topLabel.isHidden = true + loadingView.bottomLabel.text = fileModel.fileName + } + } + + override func loadingViewPressed() { + switch state { + case .waitingConfirmation: + startLoadingHandle?() + case .loading: + pauseOrResumeHandle?() + case .paused: + pauseOrResumeHandle?() + case .cancelled: + break + case .done: + openHandle?() + } + } +} diff --git a/Antidote/ChatIncomingFileCellModel.swift b/Antidote/ChatIncomingFileCellModel.swift new file mode 100644 index 0000000..6738127 --- /dev/null +++ b/Antidote/ChatIncomingFileCellModel.swift @@ -0,0 +1,8 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +class ChatIncomingFileCellModel: ChatGenericFileCellModel { +} diff --git a/Antidote/ChatIncomingTextCell.swift b/Antidote/ChatIncomingTextCell.swift new file mode 100644 index 0000000..0d35762 --- /dev/null +++ b/Antidote/ChatIncomingTextCell.swift @@ -0,0 +1,37 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit +import SnapKit + +class ChatIncomingTextCell: ChatBaseTextCell { + override func setupWithTheme(_ theme: Theme, model: BaseCellModel) { + super.setupWithTheme(theme, model: model) + + bubbleNormalBackground = theme.colorForType(.ChatIncomingBubble) + bubbleView.backgroundColor = bubbleNormalBackground + bubbleView.tintColor = theme.colorForType(.LinkText) + bubbleView.font = UIFont.preferredFont(forTextStyle: .body) + } + + override func installConstraints() { + super.installConstraints() + + bubbleView.snp.makeConstraints { + $0.top.equalTo(contentView).offset(ChatBaseTextCell.Constants.BubbleVerticalOffset) + $0.bottom.equalTo(contentView).offset(-ChatBaseTextCell.Constants.BubbleVerticalOffset) + $0.leading.equalTo(contentView).offset(ChatBaseTextCell.Constants.BubbleHorizontalOffset) + } + } +} + +// Accessibility +extension ChatIncomingTextCell { + override var accessibilityLabel: String? { + get { + return String(localized: "accessibility_incoming_message_label") + } + set {} + } +} diff --git a/Antidote/ChatInputView.swift b/Antidote/ChatInputView.swift new file mode 100644 index 0000000..5c60624 --- /dev/null +++ b/Antidote/ChatInputView.swift @@ -0,0 +1,217 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit +import SnapKit + +private struct Constants { + static let TopBorderHeight = 0.5 + static let Offset: CGFloat = 5.0 + static let CameraHorizontalOffset: CGFloat = 10.0 + static let CameraBottomOffset: CGFloat = -10.0 + static let TextViewMinHeight: CGFloat = 35.0 + static let MIN_MYHEIGHT: CGFloat = 45 + static let MAX_MYHEIGHT: CGFloat = 90 + static let MARGIN_MYHEIGHT: CGFloat = 5 + static let MAX_TEXT_INPUT_CHARS = 1000 +} + +protocol ChatInputViewDelegate: class { + func chatInputViewCameraButtonPressed(_ view: ChatInputView, cameraView: UIView) + func chatInputViewSendButtonPressed(_ view: ChatInputView) + func chatInputViewTextDidChange(_ view: ChatInputView) +} + +class ChatInputView: UIView { + weak var delegate: ChatInputViewDelegate? + + var text: String { + get { + return textView.text + } + set { + textView.text = newValue + updateViews() + } + } + + var maxHeight: CGFloat { + didSet { + updateViews() + } + } + + var cameraButtonEnabled: Bool = true{ + didSet { + updateViews() + } + } + + fileprivate var topBorder: UIView! + fileprivate var cameraButton: UIButton! + fileprivate var textView: UITextView! + fileprivate var sendButton: UIButton! + fileprivate var myHeight: Constraint! + fileprivate var didconstraint = 0 + + init(theme: Theme) { + self.maxHeight = 0.0 + + super.init(frame: CGRect.zero) + + backgroundColor = theme.colorForType(.ChatInputBackground) + + createViews(theme) + installConstraints() + updateViews() + } + + required convenience init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func becomeFirstResponder() -> Bool { + return textView.becomeFirstResponder() + } + + override func resignFirstResponder() -> Bool { + return textView.resignFirstResponder() + } +} + +// MARK: Actions +extension ChatInputView { + @objc func cameraButtonPressed() { + delegate?.chatInputViewCameraButtonPressed(self, cameraView: cameraButton) + } + + @objc func sendButtonPressed() { + delegate?.chatInputViewSendButtonPressed(self) + updateTextviewHeight(textView) + } +} + +extension ChatInputView: UITextViewDelegate { + func textViewDidChange(_ textView: UITextView) { + updateViews() + updateTextviewHeight(textView) + delegate?.chatInputViewTextDidChange(self) + } + + override func didMoveToWindow() { + updateTextviewHeight(textView) + } + + func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool { + // get the current text, or use an empty string if that failed + let currentText = textView.text ?? "" + + // attempt to read the range they are trying to change, or exit if we can't + guard let stringRange = Range(range, in: currentText) else { return false } + + // add their new text to the existing text + let updatedText = currentText.replacingCharacters(in: stringRange, with: text) + + // make sure the result is under MAX_TEXT_INPUT_CHARS characters + return updatedText.count <= Constants.MAX_TEXT_INPUT_CHARS + } +} + +private extension ChatInputView { + + func createViews(_ theme: Theme) { + topBorder = UIView() + topBorder.backgroundColor = theme.colorForType(.SeparatorsAndBorders) + addSubview(topBorder) + + let cameraImage = UIImage.templateNamed("chat-camera") + + cameraButton = UIButton() + cameraButton.setImage(cameraImage, for: UIControlState()) + cameraButton.tintColor = theme.colorForType(.LinkText) + cameraButton.addTarget(self, action: #selector(ChatInputView.cameraButtonPressed), for: .touchUpInside) + cameraButton.setContentCompressionResistancePriority(UILayoutPriority.required, for: .horizontal) + addSubview(cameraButton) + + textView = UITextView() + textView.delegate = self + textView.font = UIFont.systemFont(ofSize: 16.0) + textView.backgroundColor = theme.colorForType(.NormalBackground) + textView.layer.cornerRadius = 5.0 + textView.layer.borderWidth = 0.5 + textView.layer.borderColor = theme.colorForType(.SeparatorsAndBorders).cgColor + textView.layer.masksToBounds = true + textView.setContentHuggingPriority(UILayoutPriority(rawValue: 0.0), for: .horizontal) + textView.autocapitalizationType = .none + + addSubview(textView) + + sendButton = UIButton(type: .system) + sendButton.setTitle(String(localized: "chat_send_button"), for: UIControlState()) + sendButton.titleLabel?.font = UIFont.antidoteFontWithSize(16.0, weight: .bold) + sendButton.addTarget(self, action: #selector(ChatInputView.sendButtonPressed), for: .touchUpInside) + sendButton.setContentCompressionResistancePriority(UILayoutPriority.required, for: .horizontal) + addSubview(sendButton) + } + + func installConstraints() { + topBorder.snp.makeConstraints { + $0.top.leading.trailing.equalTo(self) + $0.height.equalTo(Constants.TopBorderHeight) + } + + cameraButton.snp.makeConstraints { + $0.leading.equalTo(self).offset(Constants.CameraHorizontalOffset) + $0.bottom.equalTo(self).offset(Constants.CameraBottomOffset) + } + + textView.snp.makeConstraints { + $0.leading.equalTo(cameraButton.snp.trailing).offset(Constants.CameraHorizontalOffset) + $0.top.equalTo(self).offset(Constants.Offset) + $0.bottom.equalTo(self).offset(-Constants.Offset) + $0.height.greaterThanOrEqualTo(Constants.TextViewMinHeight) + } + + sendButton.snp.makeConstraints { + $0.leading.equalTo(textView.snp.trailing).offset(Constants.Offset) + $0.trailing.equalTo(self).offset(-Constants.Offset) + $0.bottom.equalTo(self).offset(-Constants.Offset) + } + } + + func updateTextviewHeight(_ t : UITextView) + { + if (self.didconstraint == 1) + { + self.myHeight.uninstall() + self.didconstraint = 0 + } + + let text_needs_size = t.sizeThatFits( + CGSize(width: t.frame.size.width, + height: CGFloat.greatestFiniteMagnitude)) + var new_height = text_needs_size.height + Constants.MARGIN_MYHEIGHT + if (text_needs_size.height > Constants.MAX_MYHEIGHT) + { + new_height = Constants.MAX_MYHEIGHT + } + else if (text_needs_size.height < Constants.MIN_MYHEIGHT) { + new_height = Constants.MIN_MYHEIGHT + } + + if (self.didconstraint == 0) { + self.didconstraint = 1 + self.snp.makeConstraints { + self.myHeight = $0.height.equalTo(new_height).constraint + } + } + } + + func updateViews() { + textView.isScrollEnabled = true + textView.autocapitalizationType = .none + cameraButton.isEnabled = cameraButtonEnabled + sendButton.isEnabled = !textView.text.isEmpty + } +} diff --git a/Antidote/ChatInputViewManager.swift b/Antidote/ChatInputViewManager.swift new file mode 100644 index 0000000..c83a2e8 --- /dev/null +++ b/Antidote/ChatInputViewManager.swift @@ -0,0 +1,195 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation +import MobileCoreServices +import Photos +import os + +fileprivate struct Constants { + static let inactivityTimeout = 4.0 +} + +/** + Manager responsible for sending messages and files, updating typing notification, + saving entered text in database. + */ +class ChatInputViewManager: NSObject { + fileprivate var chat: OCTChat! + fileprivate weak var inputView: ChatInputView? + + fileprivate weak var submanagerChats: OCTSubmanagerChats! + fileprivate weak var submanagerFiles: OCTSubmanagerFiles! + fileprivate weak var submanagerObjects: OCTSubmanagerObjects! + + fileprivate weak var presentingViewController: UIViewController! + + fileprivate var inactivityTimer: Timer? + + init(inputView: ChatInputView, + chat: OCTChat, + submanagerChats: OCTSubmanagerChats, + submanagerFiles: OCTSubmanagerFiles, + submanagerObjects: OCTSubmanagerObjects, + presentingViewController: UIViewController) { + + self.chat = chat + self.inputView = inputView + self.submanagerChats = submanagerChats + self.submanagerFiles = submanagerFiles + self.submanagerObjects = submanagerObjects + self.presentingViewController = presentingViewController + + super.init() + + inputView.delegate = self + inputView.text = chat.enteredText ?? "" + } + + deinit { + endUserInteraction() + } +} + +extension ChatInputViewManager: ChatInputViewDelegate { + func chatInputViewCameraButtonPressed(_ view: ChatInputView, cameraView: UIView) { + let alert = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) + alert.popoverPresentationController?.sourceView = cameraView + alert.popoverPresentationController?.sourceRect = CGRect(x: cameraView.frame.size.width / 2, y: cameraView.frame.size.height / 2, width: 1.0, height: 1.0) + + func addAction(title: String, sourceType: UIImagePickerControllerSourceType) { + if UIImagePickerController.isSourceTypeAvailable(sourceType) { + alert.addAction(UIAlertAction(title: title, style: .default) { [unowned self] _ -> Void in + let controller = UIImagePickerController() + controller.delegate = self + controller.sourceType = sourceType + controller.mediaTypes = [kUTTypeImage as String, kUTTypeMovie as String] + controller.videoQuality = .typeHigh + self.presentingViewController.present(controller, animated: true, completion: nil) + }) + } + } + + addAction(title: String(localized: "photo_from_camera"), sourceType: .camera) + addAction(title: String(localized: "photo_from_photo_library"), sourceType: .photoLibrary) + alert.addAction(UIAlertAction(title: String(localized: "alert_cancel"), style: .cancel, handler: nil)) + + presentingViewController.present(alert, animated: true, completion: nil) + } + + func chatInputViewSendButtonPressed(_ view: ChatInputView) { + // HINT: call OCTSubmanagerChatsImpl.m -> sendMessageToChat() + submanagerChats.sendMessage(to: chat, text: view.text, type: .normal, successBlock: nil, failureBlock: nil) + DispatchQueue.main.asyncAfter(deadline: .now() + 10) { + os_log("PUSH:10_seconds") + self.submanagerChats.sendMessagePush(to: self.chat) + } + + view.text = "" + endUserInteraction() + } + + func chatInputViewTextDidChange(_ view: ChatInputView) { + try? submanagerChats.setIsTyping(true, in: chat) + inactivityTimer?.invalidate() + + inactivityTimer = Timer.scheduledTimer(timeInterval: Constants.inactivityTimeout, closure: {[weak self] _ -> Void in + self?.endUserInteraction() + }, repeats: false) + } +} + +extension ChatInputViewManager: UIImagePickerControllerDelegate { + func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) { + presentingViewController.dismiss(animated: true, completion: nil) + + guard let type = info[UIImagePickerControllerMediaType] as? String else { + return + } + + let typeImage = kUTTypeImage as String + let typeMovie = kUTTypeMovie as String + + switch type { + case typeImage: + sendImage(imagePickerInfo: info) + case typeMovie: + sendMovie(imagePickerInfo: info) + default: + return + } + } + + func imagePickerControllerDidCancel(_ picker: UIImagePickerController) { + presentingViewController.dismiss(animated: true, completion: nil) + } +} + +extension ChatInputViewManager: UINavigationControllerDelegate {} + +fileprivate extension ChatInputViewManager { + func endUserInteraction() { + try? submanagerChats.setIsTyping(false, in: chat) + inactivityTimer?.invalidate() + + if let inputView = inputView { + submanagerObjects.change(chat, enteredText: inputView.text) + } + } + + func sendImage(imagePickerInfo: [String : Any]) { + guard let image = imagePickerInfo[UIImagePickerControllerOriginalImage] as? UIImage else { + return + } + guard let data = UIImageJPEGRepresentation(image, 0.9) else { + return + } + + var fileName: String? = fileNameFromImageInfo(imagePickerInfo) + + if fileName == nil { + let dateString = DateFormatter(type: .dateAndTime).string(from: Date()) + fileName = "Photo \(dateString).jpg".replacingOccurrences(of: "/", with: "-") + } + + submanagerFiles.send(data, withFileName: fileName!, to: chat) { (error: Error) in + handleErrorWithType(.sendFileToFriend, error: error as NSError) + } + } + + func sendMovie(imagePickerInfo: [String : Any]) { + guard let url = imagePickerInfo[UIImagePickerControllerMediaURL] as? URL else { + return + } + + submanagerFiles.sendFile(atPath: url.path, moveToUploads: true, to: chat) { (error: Error) in + handleErrorWithType(.sendFileToFriend, error: error as NSError) + } + } + + func fileNameFromImageInfo(_ info: [String: Any]) -> String? { + guard let url = info[UIImagePickerControllerReferenceURL] as? URL else { + return nil + } + + let fetchResult = PHAsset.fetchAssets(withALAssetURLs: [url], options: nil) + + guard let asset = fetchResult.firstObject else { + return nil + } + + if #available(iOS 9.0, *) { + if let resource = PHAssetResource.assetResources(for: asset).first { + return resource.originalFilename + } + } else { + // Fallback on earlier versions + if let name = asset.value(forKey: "filename") as? String { + return name + } + } + + return nil + } +} diff --git a/Antidote/ChatListCell.swift b/Antidote/ChatListCell.swift new file mode 100644 index 0000000..ba034dc --- /dev/null +++ b/Antidote/ChatListCell.swift @@ -0,0 +1,160 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit +import SnapKit + +class ChatListCell: BaseCell { + struct Constants { + static let AvatarSize = 40.0 + static let AvatarLeftOffset = 10.0 + static let AvatarRightOffset = 16.0 + + static let NicknameLabelHeight = 22.0 + static let MessageLabelHeight = 22.0 + + static let NicknameToDateMinOffset = 5.0 + static let DateToArrowOffset = 5.0 + + static let RightOffset = -7.0 + static let VerticalOffset = 3.0 + } + + fileprivate var avatarView: ImageViewWithStatus! + fileprivate var nicknameLabel: UILabel! + fileprivate var messageLabel: UILabel! + fileprivate var dateLabel: UILabel! + fileprivate var arrowImageView: UIImageView! + + override func setupWithTheme(_ theme: Theme, model: BaseCellModel) { + super.setupWithTheme(theme, model: model) + + guard let chatModel = model as? ChatListCellModel else { + assert(false, "Wrong model \(model) passed to cell \(self)") + return + } + + separatorInset.left = CGFloat(Constants.AvatarLeftOffset + Constants.AvatarSize + Constants.AvatarRightOffset) + + avatarView.imageView.image = chatModel.avatar + avatarView.userStatusView.theme = theme + avatarView.userStatusView.userStatus = chatModel.status + avatarView.userStatusView.connectionStatus = chatModel.connectionstatus + + nicknameLabel.text = chatModel.nickname + nicknameLabel.textColor = theme.colorForType(.NormalText) + + messageLabel.text = chatModel.message + messageLabel.textColor = theme.colorForType(.ChatListCellMessage) + + dateLabel.text = chatModel.dateText + dateLabel.textColor = theme.colorForType(.ChatListCellMessage) + + backgroundColor = chatModel.isUnread ? theme.colorForType(.ChatListCellUnreadBackground) : .clear + + if (chatModel.isUnread) { + arrowImageView.backgroundColor = theme.colorForType(.ChatListCellUnreadArrowBackground) + } else { + arrowImageView.backgroundColor = .clear + } + + // HINT: make the arrow image view a nice circle shape + arrowImageView.layer.cornerRadius = arrowImageView.frame.height / 2 + } + + override func createViews() { + super.createViews() + + avatarView = ImageViewWithStatus() + contentView.addSubview(avatarView) + + nicknameLabel = UILabel() + nicknameLabel.font = UIFont.systemFont(ofSize: 18.0) + contentView.addSubview(nicknameLabel) + + messageLabel = UILabel() + messageLabel.font = UIFont.systemFont(ofSize: 12.0) + contentView.addSubview(messageLabel) + + dateLabel = UILabel() + dateLabel.font = UIFont.antidoteFontWithSize(12.0, weight: .light) + contentView.addSubview(dateLabel) + + let image = UIImage(named: "right-arrow")!.flippedToCorrectLayout() + + arrowImageView = UIImageView(image: image) + arrowImageView.setContentCompressionResistancePriority(UILayoutPriority.required, for: .horizontal) + contentView.addSubview(arrowImageView) + } + + override func installConstraints() { + super.installConstraints() + + avatarView.snp.makeConstraints { + $0.leading.equalTo(contentView).offset(Constants.AvatarLeftOffset) + $0.centerY.equalTo(contentView) + $0.size.equalTo(Constants.AvatarSize) + } + + nicknameLabel.snp.makeConstraints { + $0.leading.equalTo(avatarView.snp.trailing).offset(Constants.AvatarRightOffset) + $0.top.equalTo(contentView).offset(Constants.VerticalOffset) + $0.height.equalTo(Constants.NicknameLabelHeight) + } + + messageLabel.snp.makeConstraints { + $0.leading.equalTo(nicknameLabel) + $0.trailing.equalTo(contentView).offset(Constants.RightOffset) + $0.top.equalTo(nicknameLabel.snp.bottom) + $0.bottom.equalTo(contentView).offset(-Constants.VerticalOffset) + $0.height.equalTo(Constants.MessageLabelHeight) + } + + dateLabel.snp.makeConstraints { + $0.leading.greaterThanOrEqualTo(nicknameLabel.snp.trailing).offset(Constants.NicknameToDateMinOffset) + $0.top.equalTo(nicknameLabel) + $0.height.equalTo(nicknameLabel) + } + + arrowImageView.snp.makeConstraints { + $0.centerY.equalTo(dateLabel) + $0.leading.greaterThanOrEqualTo(dateLabel.snp.trailing).offset(Constants.DateToArrowOffset) + $0.trailing.equalTo(contentView).offset(Constants.RightOffset) + } + } +} + +// Accessibility +extension ChatListCell { + override var isAccessibilityElement: Bool { + get { + return true + } + set {} + } + + override var accessibilityLabel: String? { + get { + var label = nicknameLabel.text ?? "" + label += ", " + avatarView.userStatusView.userStatus.toString() + + return label + } + set {} + } + + override var accessibilityValue: String? { + get { + return messageLabel.text! + ", " + dateLabel.text! + } + set {} + } + + override var accessibilityTraits: UIAccessibilityTraits { + get { + return UIAccessibilityTraitSelected + } + set {} + } +} diff --git a/Antidote/ChatListCellModel.swift b/Antidote/ChatListCellModel.swift new file mode 100644 index 0000000..f1f0952 --- /dev/null +++ b/Antidote/ChatListCellModel.swift @@ -0,0 +1,18 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +class ChatListCellModel: BaseCellModel { + var avatar: UIImage? + + var nickname: String = "" + var message: String = "" + var dateText: String = "" + + var status: UserStatus = .offline + var connectionstatus: ConnectionStatus = .none + + var isUnread: Bool = false +} diff --git a/Antidote/ChatListController.swift b/Antidote/ChatListController.swift new file mode 100644 index 0000000..340e8f2 --- /dev/null +++ b/Antidote/ChatListController.swift @@ -0,0 +1,107 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +protocol ChatListControllerDelegate: class { + func chatListController(_ controller: ChatListController, didSelectChat chat: OCTChat) +} + +class ChatListController: UIViewController { + weak var delegate: ChatListControllerDelegate? + + fileprivate let theme: Theme + fileprivate weak var submanagerChats: OCTSubmanagerChats! + fileprivate weak var submanagerObjects: OCTSubmanagerObjects! + + fileprivate var placeholderLabel: UILabel! + fileprivate var tableManager: ChatListTableManager! + + init(theme: Theme, submanagerChats: OCTSubmanagerChats, submanagerObjects: OCTSubmanagerObjects) { + self.theme = theme + self.submanagerChats = submanagerChats + self.submanagerObjects = submanagerObjects + + super.init(nibName: nil, bundle: nil) + + edgesForExtendedLayout = UIRectEdge() + title = String(localized: "chats_title") + } + + required convenience init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func loadView() { + loadViewWithBackgroundColor(theme.colorForType(.NormalBackground)) + + createTableView() + createPlaceholderView() + installConstraints() + + updateViewsVisibility() + } + + override func setEditing(_ editing: Bool, animated: Bool) { + super.setEditing(editing, animated: animated) + + tableManager.tableView.setEditing(editing, animated: animated) + } +} + +extension ChatListController: ChatListTableManagerDelegate { + func chatListTableManager(_ manager: ChatListTableManager, didSelectChat chat: OCTChat) { + delegate?.chatListController(self, didSelectChat: chat) + } + + func chatListTableManager(_ manager: ChatListTableManager, presentAlertController controller: UIAlertController) { + present(controller, animated: true, completion: nil) + } + + func chatListTableManagerWasUpdated(_ manager: ChatListTableManager) { + updateViewsVisibility() + } +} + +private extension ChatListController { + func updateViewsVisibility() { + navigationItem.leftBarButtonItem = tableManager.isEmpty ? nil : editButtonItem + placeholderLabel.isHidden = !tableManager.isEmpty + } + + func createTableView() { + let tableView = UITableView() + tableView.estimatedRowHeight = 44.0 + tableView.backgroundColor = theme.colorForType(.NormalBackground) + tableView.sectionIndexColor = theme.colorForType(.LinkText) + // removing separators on empty lines + tableView.tableFooterView = UIView() + + view.addSubview(tableView) + + tableView.register(ChatListCell.self, forCellReuseIdentifier: ChatListCell.staticReuseIdentifier) + + tableManager = ChatListTableManager(theme: theme, tableView: tableView, submanagerChats: submanagerChats, submanagerObjects: submanagerObjects) + tableManager.delegate = self + } + + func createPlaceholderView() { + placeholderLabel = UILabel() + placeholderLabel.text = String(localized: "chat_no_chats") + placeholderLabel.textColor = theme.colorForType(.EmptyScreenPlaceholderText) + placeholderLabel.font = UIFont.antidoteFontWithSize(26.0, weight: .light) + view.addSubview(placeholderLabel) + } + + func installConstraints() { + tableManager.tableView.snp.makeConstraints { + $0.edges.equalTo(view) + } + + placeholderLabel.snp.makeConstraints { + $0.center.equalTo(view) + $0.size.equalTo(placeholderLabel.sizeThatFits(CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude))) + } + } +} diff --git a/Antidote/ChatListTableManager.swift b/Antidote/ChatListTableManager.swift new file mode 100644 index 0000000..fbfa6f1 --- /dev/null +++ b/Antidote/ChatListTableManager.swift @@ -0,0 +1,222 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +protocol ChatListTableManagerDelegate: class { + func chatListTableManager(_ manager: ChatListTableManager, didSelectChat chat: OCTChat) + func chatListTableManager(_ manager: ChatListTableManager, presentAlertController controller: UIAlertController) + func chatListTableManagerWasUpdated(_ manager: ChatListTableManager) +} + +class ChatListTableManager: NSObject { + weak var delegate: ChatListTableManagerDelegate? + + let tableView: UITableView + + var isEmpty: Bool { + get { + return chats.count == 0 + } + } + + fileprivate let theme: Theme + fileprivate let avatarManager: AvatarManager + fileprivate let dateFormatter: DateFormatter + fileprivate let timeFormatter: DateFormatter + + fileprivate weak var submanagerChats: OCTSubmanagerChats! + + fileprivate let chats: Results + fileprivate var chatsToken: RLMNotificationToken? + fileprivate let friends: Results + fileprivate var friendsToken: RLMNotificationToken? + + init(theme: Theme, tableView: UITableView, submanagerChats: OCTSubmanagerChats, submanagerObjects: OCTSubmanagerObjects) { + self.tableView = tableView + + self.theme = theme + self.avatarManager = AvatarManager(theme: theme) + self.dateFormatter = DateFormatter(type: .relativeDate) + self.timeFormatter = DateFormatter(type: .time) + + self.submanagerChats = submanagerChats + + self.chats = submanagerObjects.chats().sortedResultsUsingProperty("lastActivityDateInterval", ascending: false) + self.friends = submanagerObjects.friends() + + super.init() + + tableView.delegate = self + tableView.dataSource = self + + addNotificationBlocks() + } + + deinit { + chatsToken?.invalidate() + friendsToken?.invalidate() + } +} + +extension ChatListTableManager: UITableViewDataSource { + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + var avatarData: Data? + var nickname = String(localized: "contact_deleted") + var connectionStatus = OCTToxConnectionStatus.none + var userStatus = OCTToxUserStatus.none + + let chat = chats[indexPath.row] + let friend = chat.friends.lastObject() as? OCTFriend + + if let friend = friend { + avatarData = friend.avatarData + nickname = friend.nickname + connectionStatus = friend.connectionStatus + userStatus = friend.status + } + + let model = ChatListCellModel() + if let data = avatarData { + model.avatar = UIImage(data: data) + } + else { + model.avatar = avatarManager.avatarFromString( + nickname, + diameter: CGFloat(ChatListCell.Constants.AvatarSize)) + } + + model.nickname = nickname + model.message = lastMessage(in: chat, friend: friend) + if let date = chat.lastActivityDate() { + model.dateText = dateTextFromDate(date) + } + + model.status = UserStatus(connectionStatus: connectionStatus, userStatus: userStatus) + model.connectionstatus = ConnectionStatus(connectionStatus: connectionStatus) + model.isUnread = chat.hasUnreadMessages() + + let cell = tableView.dequeueReusableCell(withIdentifier: ChatListCell.staticReuseIdentifier) as! ChatListCell + cell.setupWithTheme(theme, model: model) + + return cell + } + + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return chats.count + } + + func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) { + if editingStyle == .delete { + let alert = UIAlertController(title: String(localized:"delete_chat_title"), message: nil, preferredStyle: .alert) + + alert.addAction(UIAlertAction(title: String(localized: "alert_cancel"), style: .default, handler: nil)) + alert.addAction(UIAlertAction(title: String(localized: "alert_delete"), style: .destructive) { [unowned self] _ -> Void in + let chat = self.chats[indexPath.row] + self.submanagerChats.removeAllMessages(in: chat, removeChat: true) + }) + + delegate?.chatListTableManager(self, presentAlertController: alert) + } + } +} + +extension ChatListTableManager: UITableViewDelegate { + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + tableView.deselectRow(at: indexPath, animated: true) + + let chat = self.chats[indexPath.row] + delegate?.chatListTableManager(self, didSelectChat: chat) + } +} + +private extension ChatListTableManager { + func addNotificationBlocks() { + chatsToken = chats.addNotificationBlock { [unowned self] change in + switch change { + case .initial: + break + case .update(_, let deletions, let insertions, let modifications): + // TODO: fix me, this is a hack to avoid the crash + self.tableView.reloadData() + self.tableView.beginUpdates() + /* + self.tableView.deleteRows(at: deletions.map { IndexPath(row: $0, section: 0) }, + with: .automatic) + self.tableView.insertRows(at: insertions.map { IndexPath(row: $0, section: 0) }, + with: .automatic) + self.tableView.reloadRows(at: modifications.map { IndexPath(row: $0, section: 0) }, + with: .none) + */ + self.tableView.endUpdates() + + self.delegate?.chatListTableManagerWasUpdated(self) + case .error(let error): + fatalError("\(error)") + } + } + + friendsToken = friends.addNotificationBlock { [unowned self] change in + switch change { + case .initial: + break + case .update(let friends, _, _, let modifications): + guard let friends = friends else { + break + } + + for index in modifications { + let friend = friends[index] + + let pathsToUpdate = self.tableView.indexPathsForVisibleRows?.filter { + let chat = self.chats[$0.row] + + return Int(chat.friends.index(of: friend)) != NSNotFound + } + + if let paths = pathsToUpdate { + // TODO: fix me, this crashes + // self.tableView.reloadRows(at: paths, with: .none) + } + } + case .error(let error): + fatalError("\(error)") + } + } + } + + func lastMessage(in chat: OCTChat, friend: OCTFriend?) -> String { + guard let message = chat.lastMessage else { + return "" + } + + if let friend = friend, friend.isTyping { + return String(localized: "chat_is_typing_text") + } + else if let text = message.messageText { + return text.text ?? "" + } + else if let file = message.messageFile { + let fileName = file.fileName ?? "" + return String(localized: message.isOutgoing() ? "chat_outgoing_file" : "chat_incoming_file") + " \(fileName)" + } + else if let call = message.messageCall { + switch call.callEvent { + case .answered: + let timeString = String(timeInterval: call.callDuration) + return String(localized: "chat_call_finished") + " - \(timeString)" + case .unanswered: + return message.isOutgoing() ? String(localized: "chat_unanwered_call") : String(localized: "chat_missed_call_message") + } + } + + return "" + } + + func dateTextFromDate(_ date: Date) -> String { + let isToday = (Calendar.current as NSCalendar).compare(Date(), to: date, toUnitGranularity: .day) == .orderedSame + + return isToday ? timeFormatter.string(from: date) : dateFormatter.string(from: date) + } +} diff --git a/Antidote/ChatMovableDateCell.swift b/Antidote/ChatMovableDateCell.swift new file mode 100644 index 0000000..15233d6 --- /dev/null +++ b/Antidote/ChatMovableDateCell.swift @@ -0,0 +1,189 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit +import SnapKit + +protocol ChatMovableDateCellDelegate: class { + func chatMovableDateCellCopyPressed(_ cell: ChatMovableDateCell) + func chatMovableDateCellDeletePressed(_ cell: ChatMovableDateCell) + func chatMovableDateCellMorePressed(_ cell: ChatMovableDateCell) +} + +class ChatMovableDateCell: BaseCell { + private static var __once: () = { + var items = UIMenuController.shared.menuItems ?? [UIMenuItem]() + items += [ + UIMenuItem(title: String(localized: "chat_more_menu_item"), action: #selector(moreAction)) + ] + + UIMenuController.shared.menuItems = items + }() + weak var delegate: ChatMovableDateCellDelegate? + + var canBeCopied = false + + /** + Superview for content that should move while panning table to the left. + */ + var movableContentView: UIView! + + var movableOffset: CGFloat = 0 { + didSet { + var offset = movableOffset + + if (UserDefaultsManager().DateonmessageMode == true) { + offset = 39 + } + + if #available(iOS 9.0, *) { + if UIView.userInterfaceLayoutDirection(for: self.semanticContentAttribute) == .rightToLeft { + offset = -offset + } + } + + if offset > 0.0 { + offset = 0.0 + } + + let minOffset = -dateLabel.frame.size.width - 5.0 + + if offset < minOffset { + offset = minOffset + } + + movableContentViewLeftConstraint.update(offset: offset) + layoutIfNeeded() + } + } + + fileprivate var movableContentViewLeftConstraint: Constraint! + fileprivate var dateLabel: UILabel! + + fileprivate var isShowingMenu: Bool = false + fileprivate static var setupOnceToken: Int = 0 + + override func setupWithTheme(_ theme: Theme, model: BaseCellModel) { + super.setupWithTheme(theme, model: model) + + guard let movableModel = model as? ChatMovableDateCellModel else { + assert(false, "Wrong model \(model) passed to cell \(self)") + return + } + + _ = ChatMovableDateCell.__once + + dateLabel.text = movableModel.dateString + dateLabel.numberOfLines = 0 // --> multiline label + dateLabel.textColor = theme.colorForType(.ChatListCellMessage) + } + + override func createViews() { + super.createViews() + + movableContentView = UIView() + movableContentView.backgroundColor = .clear + contentView.addSubview(movableContentView) + + dateLabel = UILabel() + dateLabel.font = UIFont.antidoteFontWithSize(11.0, weight: .medium) + movableContentView.addSubview(dateLabel) + + // Using empty view for multiple selection background. + multipleSelectionBackgroundView = UIView() + } + + override func installConstraints() { + super.installConstraints() + + movableContentView.snp.makeConstraints { + $0.top.equalTo(contentView) + if (UserDefaultsManager().DateonmessageMode == true) { + movableContentViewLeftConstraint = $0.leading.equalTo(contentView).constraint.update(offset: -39) + } else { + movableContentViewLeftConstraint = $0.leading.equalTo(contentView).constraint + } + $0.size.equalTo(contentView) + } + + dateLabel.snp.makeConstraints { + $0.centerY.equalTo(movableContentView) + $0.leading.equalTo(movableContentView.snp.trailing) + } + } + + override func setSelected(_ selected: Bool, animated: Bool) { + if !isEditing { + // don't call super in case of editing to avoid background change + return + } + + super.setSelected(selected, animated: animated) + } +} + +// Accessibility +extension ChatMovableDateCell { + override var isAccessibilityElement: Bool { + get { + return true + } + set {} + } + + override var accessibilityValue: String? { + get { + return dateLabel.text! + } + set {} + } +} + +extension ChatMovableDateCell: ChatEditable { + // Override in subclass to enable menu + @objc func shouldShowMenu() -> Bool { + return false + } + + // Override in subclass to enable menu + @objc func menuTargetRect() -> CGRect { + return CGRect.zero + } + + @objc func willShowMenu() { + isShowingMenu = true + } + + @objc func willHideMenu() { + isShowingMenu = false + } +} + +// Methods to make UIMenuController work. +extension ChatMovableDateCell { + func isMenuActionSupportedByCell(_ action: Selector) -> Bool { + switch action { + case #selector(copy(_:)): + return canBeCopied + case #selector(delete(_:)): + return true + case #selector(moreAction): + return true + default: + return false + } + } + + override func copy(_ sender: Any?) { + delegate?.chatMovableDateCellCopyPressed(self) + } + + override func delete(_ sender: Any?) { + delegate?.chatMovableDateCellDeletePressed(self) + } + + @objc func moreAction() { + delegate?.chatMovableDateCellMorePressed(self) + } +} diff --git a/Antidote/ChatMovableDateCellModel.swift b/Antidote/ChatMovableDateCellModel.swift new file mode 100644 index 0000000..c5fdf40 --- /dev/null +++ b/Antidote/ChatMovableDateCellModel.swift @@ -0,0 +1,9 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +class ChatMovableDateCellModel: BaseCellModel { + var dateString: String = "" +} diff --git a/Antidote/ChatOutgoingCallCell.swift b/Antidote/ChatOutgoingCallCell.swift new file mode 100644 index 0000000..e27c6ef --- /dev/null +++ b/Antidote/ChatOutgoingCallCell.swift @@ -0,0 +1,86 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit +import SnapKit + +private struct Constants { + static let RightOffset = -20.0 + static let ImageViewToLabelOffset = -5.0 + static let ImageViewYOffset = -1.0 + static let VerticalOffset = 8.0 +} + +class ChatOutgoingCallCell: ChatMovableDateCell { + fileprivate var callImageView: UIImageView! + fileprivate var label: UILabel! + + override func setupWithTheme(_ theme: Theme, model: BaseCellModel) { + super.setupWithTheme(theme, model: model) + + guard let outgoingModel = model as? ChatOutgoingCallCellModel else { + assert(false, "Wrong model \(model) passed to cell \(self)") + return + } + + label.textColor = theme.colorForType(.ChatListCellMessage) + callImageView.tintColor = theme.colorForType(.LinkText) + + if outgoingModel.answered { + label.text = String(localized: "chat_call_message") + String(timeInterval: outgoingModel.callDuration) + } + else { + label.text = String(localized: "chat_unanwered_call") + } + } + + override func createViews() { + super.createViews() + + let image = UIImage.templateNamed("start-call-small") + + callImageView = UIImageView(image: image) + movableContentView.addSubview(callImageView) + + label = UILabel() + label.font = UIFont.antidoteFontWithSize(16.0, weight: .light) + movableContentView.addSubview(label) + } + + override func installConstraints() { + super.installConstraints() + + callImageView.snp.makeConstraints { + $0.centerY.equalTo(label).offset(Constants.ImageViewYOffset) + $0.trailing.equalTo(label.snp.leading).offset(Constants.ImageViewToLabelOffset) + } + + label.snp.makeConstraints { + $0.top.equalTo(contentView).offset(Constants.VerticalOffset) + $0.bottom.equalTo(contentView).offset(-Constants.VerticalOffset) + $0.trailing.equalTo(movableContentView).offset(Constants.RightOffset) + } + } +} + +// Accessibility +extension ChatOutgoingCallCell { + override var accessibilityLabel: String? { + get { + return label.text + } + set {} + } +} + +// ChatEditable +extension ChatOutgoingCallCell { + override func shouldShowMenu() -> Bool { + return true + } + + override func menuTargetRect() -> CGRect { + return label.frame + } +} diff --git a/Antidote/ChatOutgoingCallCellModel.swift b/Antidote/ChatOutgoingCallCellModel.swift new file mode 100644 index 0000000..9518f93 --- /dev/null +++ b/Antidote/ChatOutgoingCallCellModel.swift @@ -0,0 +1,10 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +class ChatOutgoingCallCellModel: ChatMovableDateCellModel { + var callDuration: TimeInterval = 0 + var answered: Bool = true +} diff --git a/Antidote/ChatOutgoingFileCell.swift b/Antidote/ChatOutgoingFileCell.swift new file mode 100644 index 0000000..4943bb7 --- /dev/null +++ b/Antidote/ChatOutgoingFileCell.swift @@ -0,0 +1,98 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit +import SnapKit + +private struct Constants { + static let BigOffset = 20.0 + static let SmallOffset = 8.0 + static let ImageButtonSize = 180.0 + static let CloseButtonSize = 25.0 +} + +class ChatOutgoingFileCell: ChatGenericFileCell { + override func setButtonImage(_ image: UIImage) { + super.setButtonImage(image) + + loadingView.bottomLabel.isHidden = true + + if state == .cancelled { + loadingView.bottomLabel.isHidden = false + loadingView.centerImageView.image = nil + } + } + + override func createViews() { + super.createViews() + + movableContentView.addSubview(loadingView) + movableContentView.addSubview(cancelButton) + movableContentView.addSubview(retryButton) + } + + override func installConstraints() { + super.installConstraints() + + cancelButton.snp.makeConstraints { + $0.trailing.equalTo(loadingView.snp.leading).offset(-Constants.SmallOffset) + $0.top.equalTo(loadingView) + $0.size.equalTo(Constants.CloseButtonSize) + } + + retryButton.snp.makeConstraints { + $0.center.equalTo(cancelButton) + $0.size.equalTo(cancelButton) + } + + loadingView.snp.makeConstraints { + $0.trailing.equalTo(movableContentView).offset(-Constants.BigOffset) + $0.top.equalTo(movableContentView).offset(Constants.SmallOffset) + $0.bottom.equalTo(movableContentView).offset(-Constants.SmallOffset) + $0.size.equalTo(Constants.ImageButtonSize) + } + } + + override func updateViewsWithState(_ state: ChatGenericFileCellModel.State, fileModel: ChatGenericFileCellModel) { + loadingView.imageButton.isUserInteractionEnabled = true + loadingView.progressView.isHidden = true + loadingView.topLabel.isHidden = true + loadingView.bottomLabel.isHidden = false + loadingView.bottomLabel.text = fileModel.fileName + + cancelButton.isHidden = false + retryButton.isHidden = true + + switch state { + case .waitingConfirmation: + loadingView.imageButton.isUserInteractionEnabled = false + loadingView.bottomLabel.text = String(localized: "chat_waiting") + case .loading: + loadingView.progressView.isHidden = false + case .paused: + break + case .cancelled: + loadingView.bottomLabel.text = String(localized: "chat_file_cancelled") + cancelButton.isHidden = true + retryButton.isHidden = false + case .done: + cancelButton.isHidden = true + } + } + + override func loadingViewPressed() { + switch state { + case .waitingConfirmation: + break + case .loading: + pauseOrResumeHandle?() + case .paused: + pauseOrResumeHandle?() + case .cancelled: + openHandle?() + case .done: + openHandle?() + } + } +} diff --git a/Antidote/ChatOutgoingFileCellModel.swift b/Antidote/ChatOutgoingFileCellModel.swift new file mode 100644 index 0000000..de6f906 --- /dev/null +++ b/Antidote/ChatOutgoingFileCellModel.swift @@ -0,0 +1,9 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +class ChatOutgoingFileCellModel: ChatGenericFileCellModel { + +} diff --git a/Antidote/ChatOutgoingTextCell.swift b/Antidote/ChatOutgoingTextCell.swift new file mode 100644 index 0000000..6356fbd --- /dev/null +++ b/Antidote/ChatOutgoingTextCell.swift @@ -0,0 +1,51 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit +import SnapKit + +class ChatOutgoingTextCell: ChatBaseTextCell { + override func setupWithTheme(_ theme: Theme, model: BaseCellModel) { + super.setupWithTheme(theme, model: model) + + guard let textModel = model as? ChatOutgoingTextCellModel else { + assert(false, "Wrong model \(model) passed to cell \(self)") + return + } + + bubbleNormalBackground = theme.colorForType(.ChatOutgoingBubble) + if !textModel.delivered { + if !textModel.sentpush { + bubbleNormalBackground = theme.colorForType(.ChatOutgoingUnreadBubble) + } else { + bubbleNormalBackground = theme.colorForType(.ChatOutgoingSentPushBubble) + } + } + + bubbleView.textColor = theme.colorForType(.ConnectingText) + bubbleView.backgroundColor = bubbleNormalBackground + bubbleView.tintColor = theme.colorForType(.NormalText) + bubbleView.font = UIFont.preferredFont(forTextStyle: .body) + } + + override func installConstraints() { + super.installConstraints() + + bubbleView.snp.makeConstraints { + $0.top.equalTo(movableContentView).offset(ChatBaseTextCell.Constants.BubbleVerticalOffset) + $0.bottom.equalTo(movableContentView).offset(-ChatBaseTextCell.Constants.BubbleVerticalOffset) + $0.trailing.equalTo(movableContentView).offset(-ChatBaseTextCell.Constants.BubbleHorizontalOffset) + } + } +} + +// Accessibility +extension ChatOutgoingTextCell { + override var accessibilityLabel: String? { + get { + return String(localized: "accessibility_outgoing_message_label") + } + set {} + } +} diff --git a/Antidote/ChatOutgoingTextCellModel.swift b/Antidote/ChatOutgoingTextCellModel.swift new file mode 100644 index 0000000..f92b695 --- /dev/null +++ b/Antidote/ChatOutgoingTextCellModel.swift @@ -0,0 +1,10 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +class ChatOutgoingTextCellModel : ChatBaseTextCellModel { + var delivered: Bool = false + var sentpush: Bool = false +} diff --git a/Antidote/ChatPrivateController.swift b/Antidote/ChatPrivateController.swift new file mode 100644 index 0000000..e23686e --- /dev/null +++ b/Antidote/ChatPrivateController.swift @@ -0,0 +1,1508 @@ + +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit +import CoreLocation +import SnapKit +import MobileCoreServices +import os + +private struct Constants { + static let MessagesPortionSize = 50 + + static let InputViewTopOffset: CGFloat = 50.0 + + static let NewMessageViewAllowedDelta: CGFloat = 20.0 + static let NewMessageViewEdgesOffset: CGFloat = 5.0 + static let NewMessageViewTopOffset: CGFloat = -15.0 + static let NewMessageViewAnimationDuration = 0.2 + + static let ResetPanAnimationDuration = 0.3 + + static let MaxImageSizeToShowInline: OCTToxFileSize = 20 * 1024 * 1024 + + static let MaxInlineImageSide: CGFloat = LoadingImageView.Constants.ImageButtonSize * UIScreen.main.scale +} + +protocol ChatPrivateControllerDelegate: class { + func chatPrivateControllerWillAppear(_ controller: ChatPrivateController) + func chatPrivateControllerWillDisappear(_ controller: ChatPrivateController) + func chatPrivateControllerCallToChat(_ controller: ChatPrivateController, enableVideo: Bool) + func chatPrivateControllerShowQuickLookController( + _ controller: ChatPrivateController, + dataSource: QuickLookPreviewControllerDataSource, + selectedIndex: Int) +} + +class ChatPrivateController: KeyboardNotificationController, CLLocationManagerDelegate { + let chat: OCTChat + + fileprivate weak var delegate: ChatPrivateControllerDelegate? + + let location_manager = CLLocationManager() + fileprivate let theme: Theme + fileprivate weak var submanagerChats: OCTSubmanagerChats! + fileprivate weak var submanagerObjects: OCTSubmanagerObjects! + fileprivate weak var submanagerFiles: OCTSubmanagerFiles! + + fileprivate let messages: Results + fileprivate var messagesToken: RLMNotificationToken? + fileprivate var visibleMessages: Int + + fileprivate let friend: OCTFriend? + fileprivate var friendToken: RLMNotificationToken? + + fileprivate let imageCache = NSCache() + + fileprivate let timeFormatter: DateFormatter + fileprivate let dateFormatter: DateFormatter + + fileprivate var audioButton: UIBarButtonItem! + fileprivate var videoButton: UIBarButtonItem! + fileprivate var locationButton: UIBarButtonItem! + fileprivate var CallWaitingView: UIView! + fileprivate var callwaiting_running: Bool! + fileprivate var CallWaitingCancelButton: CallButton? + fileprivate let linearBar: LinearProgressBar = LinearProgressBar() + + fileprivate var titleView: ChatPrivateTitleView! + fileprivate var tableView: UITableView? + fileprivate var typingHeaderView: ChatTypingHeaderView! + fileprivate var fauxOfflineHeaderView: ChatFauxOfflineHeaderView! + fileprivate var newMessagesView: UIView! + fileprivate var chatInputView: ChatInputView! + fileprivate var editMessagesToolbar: UIToolbar! + + fileprivate var chatInputViewManager: ChatInputViewManager! + + fileprivate var tableViewTapGestureRecognizer: UITapGestureRecognizer! + + fileprivate var tableViewToChatInputConstraint: Constraint! + fileprivate var typingViewToChatInputConstraint: Constraint! + + fileprivate var newMessageViewTopConstraint: Constraint? + fileprivate var chatInputViewBottomConstraint: Constraint? + + fileprivate var newMessagesViewVisible = false + + /// Index path for cell with UIMenu presented. + fileprivate var selectedMenuIndexPath: IndexPath? + + fileprivate let showKeyboardOnAppear: Bool + fileprivate var disableNextInputViewAnimation = false + + init(theme: Theme, chat: OCTChat, submanagerChats: OCTSubmanagerChats, submanagerObjects: OCTSubmanagerObjects, submanagerFiles: OCTSubmanagerFiles, delegate: ChatPrivateControllerDelegate, showKeyboardOnAppear: Bool = false) { + self.theme = theme + self.chat = chat + self.friend = chat.friends.lastObject() as? OCTFriend + self.submanagerChats = submanagerChats + self.submanagerObjects = submanagerObjects + self.submanagerFiles = submanagerFiles + self.delegate = delegate + self.showKeyboardOnAppear = showKeyboardOnAppear + self.callwaiting_running = false + + let predicate = NSPredicate(format: "chatUniqueIdentifier == %@", chat.uniqueIdentifier) + self.messages = submanagerObjects.messages(predicate: predicate).sortedResultsUsingProperty("dateInterval", ascending: false) + self.visibleMessages = Constants.MessagesPortionSize + + self.timeFormatter = DateFormatter(type: .time) + self.dateFormatter = DateFormatter() + dateFormatter.dateFormat = "MMMdd" + + super.init() + + edgesForExtendedLayout = UIRectEdge() + hidesBottomBarWhenPushed = true + + NotificationCenter.default.addObserver( + self, + selector: #selector(ChatPrivateController.applicationDidBecomeActive), + name: NSNotification.Name.UIApplicationDidBecomeActive, + object: nil) + + NotificationCenter.default.addObserver( + self, + selector: #selector(ChatPrivateController.willShowMenuNotification(_:)), + name: NSNotification.Name.UIMenuControllerWillShowMenu, + object: nil) + NotificationCenter.default.addObserver( + self, + selector: #selector(ChatPrivateController.willHideMenuNotification), + name: NSNotification.Name.UIMenuControllerWillHideMenu, + object: nil) + } + + deinit { + NotificationCenter.default.removeObserver(self) + + messagesToken?.invalidate() + friendToken?.invalidate() + } + + required convenience init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func loadView() { + loadViewWithBackgroundColor(theme.colorForType(.NormalBackground)) + + createTableView() + createTableHeaderViews() + createNewMessagesView() + createInputView() + createEditMessageToolbar() + installConstraints() + } + + override func viewDidLoad() { + super.viewDidLoad() + + addMessagesNotification() + + createNavigationViews() + addFriendNotification() + + // HINT: request Location updates here + LocationManager.shared.requestAccess() + + // HINT: location manager to get location on button pressed + location_manager.delegate = self + + self.configureLinearProgressBar() + } + + func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { + if let location = locations.first { + let lat_str = String(format: "%.5f", location.coordinate.latitude) + let lon_str = String(format: "%.5f", location.coordinate.longitude) + let location_string = lat_str + ", " + lon_str + let zoom_level = "14" + print("location: \(location_string)") + // let location_url = "https://www.openstreetmap.org/search?query=" + lat_str + "%2C%20" + lon_str + "#map=" + zoom_level + "/" + lat_str + "/" + lon_str + let location_url = "https://www.openstreetmap.org/?mlat=" + lat_str + "&mlon=" + lon_str + "#map=" + zoom_level + "/" + lat_str + "/" + lon_str + + // chatInputView.text = "my Location: " + location_string + "\n" + location_url + + //DispatchQueue.main.async { + self.submanagerChats.sendMessage(to: self.chat, text: "my Location: " + location_string + "\n" + location_url, type: .normal, successBlock: nil, failureBlock: nil) + //} + } + } + + func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) { + // print("Failed to find user's location: \(error.localizedDescription)") + } + + fileprivate func configureLinearProgressBar(){ + linearBar.backgroundColor = UIColor(red:0.68, green:0.81, blue:0.72, alpha:1.0) + linearBar.progressBarColor = UIColor(red:0.26, green:0.65, blue:0.45, alpha:1.0) + linearBar.heightForLinearBar = 5 + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + updateLastReadDate() + delegate?.chatPrivateControllerWillAppear(self) + } + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + + delegate?.chatPrivateControllerWillDisappear(self) + } + + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + + if showKeyboardOnAppear { + disableNextInputViewAnimation = true + _ = chatInputView.becomeFirstResponder() + } + } + + override func keyboardWillShowAnimated(keyboardFrame frame: CGRect) { + super.keyboardWillShowAnimated(keyboardFrame: frame) + + guard let constraint = chatInputViewBottomConstraint else { + return + } + + constraint.update(offset: -frame.size.height) + + if disableNextInputViewAnimation { + disableNextInputViewAnimation = false + + UIView.setAnimationsEnabled(false) + view.layoutIfNeeded() + UIView.setAnimationsEnabled(true) + } + else { + view.layoutIfNeeded() + } + } + + override func keyboardWillHideAnimated(keyboardFrame frame: CGRect) { + super.keyboardWillHideAnimated(keyboardFrame: frame) + + guard let constraint = chatInputViewBottomConstraint else { + return + } + + // TODO: this moves the input view a bit more to the top, because the home button "line" is in the way otherwise + // please fix me properly in the future + constraint.update(offset: 0.0) + if #available(iOS 11.0, *) { + let keyWindow = UIApplication.shared.keyWindow + let b = keyWindow?.safeAreaInsets.bottom + constraint.update(offset: -(b ?? 20)) + } + + if disableNextInputViewAnimation { + disableNextInputViewAnimation = false + + UIView.setAnimationsEnabled(false) + view.layoutIfNeeded() + UIView.setAnimationsEnabled(true) + } + else { + view.layoutIfNeeded() + } + } + + override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + + updateInputViewMaxHeight() + } +} + +// MARK: Actions +extension ChatPrivateController { + @objc func tapOnTableView() { + _ = chatInputView.resignFirstResponder() + } + + @objc func panOnTableView(_ recognizer: UIPanGestureRecognizer) { + guard let tableView = tableView else { + return + } + + if (UserDefaultsManager().DateonmessageMode == true) { + return + } + + let translation = recognizer.translation(in: recognizer.view) + recognizer.setTranslation(CGPoint.zero, in: recognizer.view) + + _ = tableView.visibleCells.filter { + $0 is ChatMovableDateCell + }.map { + $0 as! ChatMovableDateCell + }.map { + switch recognizer.state { + case .possible: + fallthrough + case .began: + // nop + break + case .changed: + $0.movableOffset += translation.x + case .ended: + fallthrough + case .cancelled: + fallthrough + case .failed: + let cell = $0 + UIView.animate(withDuration: Constants.ResetPanAnimationDuration, animations: { + cell.movableOffset = 0.0 + }) + } + } + } + + @objc func newMessagesViewPressed() { + guard let tableView = tableView else { + return + } + + tableView.setContentOffset(CGPoint.zero, animated: true) + + // iOS is broken =\ + // See https://stackoverflow.com/a/30804874 + let delayTime = DispatchTime.now() + Double(Int64(0.2 * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC) + DispatchQueue.main.asyncAfter(deadline: delayTime) { [weak self] in + self?.tableView?.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: true) + } + } + + func messageBox(messageTitle: String, messageAlert: String, messageBoxStyle: UIAlertControllerStyle, alertActionStyle: UIAlertActionStyle, completionHandler: @escaping () -> Void) + { + let alert = UIAlertController(title: messageTitle, message: messageAlert, preferredStyle: messageBoxStyle) + + let okAction = UIAlertAction(title: "Cancel", style: alertActionStyle) { _ in + completionHandler() // This will only get called after okay is tapped in the alert + } + + alert.addAction(okAction) + present(alert, animated: true, completion: nil) + } + + @objc + func buttonCallWaitingCancel() { + callwaiting_running = false + CallWaitingView.removeFromSuperview() + self.linearBar.stopAnimation() + } + + @objc func audioCallButtonPressed() { + + if let friend = self.friend { + let connection_status = ConnectionStatus(connectionStatus: friend.connectionStatus) + if (connection_status != .none) + { + // HINT: friend is online, so start the call now + callwaiting_running = false + delegate?.chatPrivateControllerCallToChat(self, enableVideo: false) + } + else + { + // HINT: friend is not online, show call waiting screen + callwaiting_running = true + let window = UIApplication.shared.keyWindow! + CallWaitingView = UIView(frame: window.bounds) + window.addSubview(CallWaitingView) + CallWaitingView.backgroundColor = .black + + CallWaitingCancelButton = CallButton(theme: theme, type: .decline, buttonSize: .big) + CallWaitingCancelButton!.addTarget(self, + action: #selector(buttonCallWaitingCancel), + for: .touchUpInside) + // CallWaitingCancelButton!.backgroundColor = .white + + let lb1 = UILabel(frame: CGRect(x: 0, y: 0, width: 200, height: 80)) + lb1.text = "Call" + lb1.textAlignment = .center; + lb1.font = lb1.font.withSize(35) + lb1.textColor = .white + lb1.backgroundColor = .black + lb1.numberOfLines = 0; + lb1.sizeToFit() + + let lb2 = UILabel(frame: CGRect(x: 0, y: 0, width: 200, height: 80)) + lb2.text = friend.nickname + lb2.textAlignment = .center; + lb2.font = lb1.font.withSize(30) + lb2.textColor = .white + lb2.backgroundColor = .black + lb2.numberOfLines = 0; + lb2.sizeToFit() + + let lb3 = UILabel(frame: CGRect(x: 0, y: 0, width: 200, height: 80)) + lb3.text = "waiting for friend to come online ..." + lb3.textAlignment = .center; + lb3.font = lb1.font.withSize(20) + lb3.textColor = .white + lb3.backgroundColor = .black + lb3.numberOfLines = 0; + lb3.lineBreakMode = .byWordWrapping + lb3.sizeToFit() + + + CallWaitingView.addSubview(CallWaitingCancelButton!) + CallWaitingView.addSubview(lb1) + CallWaitingView.addSubview(lb2) + CallWaitingView.addSubview(lb3) + CallWaitingCancelButton!.center = CallWaitingView.center + CallWaitingView.bringSubview(toFront: lb1) + CallWaitingView.bringSubview(toFront: lb2) + CallWaitingView.bringSubview(toFront: lb3) + CallWaitingView.bringSubview(toFront: CallWaitingCancelButton!) + + let BigButtonOffset = 30.0 + + CallWaitingView.snp.makeConstraints { make in + make.leading.trailing.bottom.equalToSuperview() + // make.top.equalTo(view.safeAreaLayoutGuide) // --> that leave too much see through space at the top. strange + make.top.equalToSuperview() + } + + CallWaitingCancelButton!.snp.makeConstraints { make in + make.centerX.equalToSuperview() + make.top.greaterThanOrEqualToSuperview().offset(BigButtonOffset) + make.bottom.equalToSuperview().offset(-BigButtonOffset) + } + + lb1.snp.makeConstraints { make in + make.centerX.equalToSuperview() + make.top.equalToSuperview().offset(60) + make.leading.trailing.equalToSuperview() + } + + lb2.snp.makeConstraints { make in + make.centerX.equalToSuperview() + make.top.equalTo(lb1.snp.bottom).offset(35) + make.leading.trailing.equalToSuperview() + } + + lb3.snp.makeConstraints { make in + make.centerX.equalToSuperview() + make.top.equalTo(lb2.snp.bottom).offset(35) + make.leading.trailing.equalToSuperview() + } + + DispatchQueue.global(qos: .userInitiated).async { + + print("cc:call_waiting_bg_queue") + if self.friend != nil { + + DispatchQueue.main.async { + // send a text message to trigger PUSH notification, and make friend come online (hopefully) + // HINT: call OCTSubmanagerChatsImpl.m -> sendMessageToChat() + self.submanagerChats.sendMessage(to: self.chat, text: "calling you", type: .normal, successBlock: nil, failureBlock: nil) + DispatchQueue.main.asyncAfter(deadline: .now() + 10) { + os_log("PUSH:10_seconds") + self.submanagerChats.sendMessagePush(to: self.chat) + } + + self.linearBar.startAnimation(viewToAddto: self.CallWaitingView, viewToAlignToBottomOf: lb3, bottom_margin: 10) + self.CallWaitingView.bringSubview(toFront: self.linearBar) + } + + var connection_status2: ConnectionStatus = .none + + while true { + + DispatchQueue.main.async { + connection_status2 = ConnectionStatus(connectionStatus: friend.connectionStatus) + } + + print("cc:while_friend_not_online, %@", connection_status2) + if (connection_status2 != .none) + { + DispatchQueue.main.async { + print("cc:main_queue") + if (self.callwaiting_running) + { + self.callwaiting_running = false + self.CallWaitingView.removeFromSuperview() + self.linearBar.stopAnimation() + self.delegate?.chatPrivateControllerCallToChat(self, enableVideo: false) + } + } + break + } + + // HINT: sleep for 1 second + if (self.callwaiting_running) + { + sleep(1) + } + else + { + DispatchQueue.main.async { + self.CallWaitingView.removeFromSuperview() + self.linearBar.stopAnimation() + } + break + } + } + print("cc:while_loop_end") + } + } + + } + } else { + print("Call_ERROR:no friend?") + } + } + + @objc func displayalert() { + var alert = UIAlertController(title: "Location Sharing", message: "Would you like to enable location sharing with this contact?\nYou can disable this feature by clicking on the location icon after it has been enabled.", preferredStyle: UIAlertControllerStyle.alert) + var action_title = "Enable" + + if (AppDelegate.location_sharing_contact_pubkey != "-1") + { + alert = UIAlertController(title: "Location Sharing", message: "Disable sharing with this contact " + AppDelegate.location_sharing_contact_pubkey + " ?" , preferredStyle: UIAlertControllerStyle.alert) + action_title = "Disable" + } + + alert.addAction((UIAlertAction(title: action_title, style: .default, handler: { [self] (action) -> Void in + if (action_title == "Disable") + { + AppDelegate.location_sharing_contact_pubkey = "-1" + let locationImage = UIImage(named: "location-call-medium")!.withRenderingMode(.alwaysOriginal) + locationButton.setBackgroundImage(locationImage, for: .normal, barMetrics: .default) + } + else + { + AppDelegate.location_sharing_contact_pubkey = self.friend?.publicKey ?? "-1" + let locationImage = UIImage(named: "location-call-activated-medium")!.withRenderingMode(.alwaysOriginal) + locationButton.setBackgroundImage(locationImage, for: .normal, barMetrics: .default) + + DispatchQueue.global(qos: .userInitiated).async { + + print("ll:location_sharing") + if self.friend != nil { + + while AppDelegate.location_sharing_contact_pubkey != "-1" { + location_manager.requestLocation() + // HINT: sleep for 30 seconds + sleep(30) + } + print("ll:while_loop_end") + } + } + } + alert.dismiss(animated: true, completion: nil) + }))) + + alert.addAction( + UIAlertAction(title: "Cancel", style: .cancel, handler: { (action) -> Void in + alert.dismiss(animated: true, completion: nil) + })) + + self.present(alert, animated: true, completion: nil) + } + + @objc func videoCallButtonPressed() { + delegate?.chatPrivateControllerCallToChat(self, enableVideo: true) + } + + @objc func locationButtonPressed() { + displayalert() + } + + @objc func editMessagesDeleteButtonPressed(_ barButtonItem: UIBarButtonItem) { + guard let selectedRows = tableView?.indexPathsForSelectedRows else { + return + } + + showMessageDeletionConfirmation(messagesCount: selectedRows.count, + showFromItem: barButtonItem, + deleteClosure: { [unowned self] in + self.toggleTableViewEditing(false, animated: true) + + let toRemove = selectedRows.map { + return self.messages[$0.row] + } + + self.submanagerChats.removeMessages(toRemove) + }) + } + + @objc func deleteAllMessagesButtonPressed(_ barButtonItem: UIBarButtonItem) { + toggleTableViewEditing(false, animated: true) + + showMessageDeletionConfirmation(messagesCount: messages.count, + showFromItem: barButtonItem, + deleteClosure: { [unowned self] in + self.submanagerChats.removeAllMessages(in: self.chat, removeChat: false) + }) + } + + @objc func cancelEditingButtonPressed() { + toggleTableViewEditing(false, animated: true) + } +} + +// MARK: Notifications +extension ChatPrivateController { + @objc func applicationDidBecomeActive() { + updateLastReadDate() + } + + @objc func willShowMenuNotification(_ notification: Notification) { + guard let indexPath = selectedMenuIndexPath else { + return + } + guard let cell = tableView?.cellForRow(at: indexPath) else { + return + } + guard let editable = cell as? ChatEditable else { + return + } + guard let menu = notification.object as? UIMenuController else { + return + } + + NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIMenuControllerWillShowMenu, object: nil) + + menu.setMenuVisible(false, animated: false) + + let rect = cell.convert(editable.menuTargetRect(), to: view) + + menu.setTargetRect(rect, in: view) + menu.setMenuVisible(true, animated: true) + + NotificationCenter.default.addObserver( + self, + selector: #selector(ChatPrivateController.willShowMenuNotification(_:)), + name: NSNotification.Name.UIMenuControllerWillShowMenu, + object: nil) + } + + @objc func willHideMenuNotification() { + guard let indexPath = selectedMenuIndexPath else { + return + } + selectedMenuIndexPath = nil + + guard let editable = tableView?.cellForRow(at: indexPath) as? ChatEditable else { + return + } + + editable.willHideMenu() + } +} + +extension ChatPrivateController: UITableViewDataSource { + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let message = messages[indexPath.row] + + // setting default values to avoid crash + var model: ChatMovableDateCellModel = ChatMovableDateCellModel() + var cell: ChatMovableDateCell = tableView.dequeueReusableCell(withIdentifier: ChatMovableDateCell.staticReuseIdentifier) as! ChatMovableDateCell + + if message.isOutgoing() { + if let messageText = message.messageText { + let outgoingModel = ChatOutgoingTextCellModel() + + if (UserDefaultsManager().DebugMode == false) { + outgoingModel.message = messageText.text ?? "" + } else { + let s1 = (messageText.text ?? "") + let s2 = (messageText.msgv3HashHex ?? "") + let s3 = (message.senderUniqueIdentifier ?? "") + let s4 = (message.chatUniqueIdentifier ) + let s5 = String(messageText.isDelivered) + let s6 = String(messageText.sentPush) + let s7 = String(message.tssent) + let s8 = String(message.tsrcvd) + let s9 = String(message.dateInterval) + outgoingModel.message = s1 + "\n" + + "msgv3HashHex:\n" + s2 + "\n" + + "senderUniqueIdentifier:\n" + s3 + "\n" + + "chatUniqueIdentifier:\n" + s4 + "\n" + + "isDelivered:\n" + s5 + "\n" + + "sentPush:\n" + s6 + "\n" + + "tssent:\n" + s7 + "\n" + + "tsrcvd:\n" + s8 + "\n" + + "dateInterval:\n" + s9 + "\n" + } + + outgoingModel.delivered = messageText.isDelivered + outgoingModel.sentpush = messageText.sentPush + + model = outgoingModel + + cell = tableView.dequeueReusableCell(withIdentifier: ChatOutgoingTextCell.staticReuseIdentifier) as! ChatOutgoingTextCell + } + else if let messageCall = message.messageCall { + let outgoingModel = ChatOutgoingCallCellModel() + outgoingModel.callDuration = messageCall.callDuration + outgoingModel.answered = (messageCall.callEvent == .answered) + model = outgoingModel + + cell = tableView.dequeueReusableCell(withIdentifier: ChatOutgoingCallCell.staticReuseIdentifier) as! ChatOutgoingCallCell + } + else if let _ = message.messageFile { + (model, cell) = imageCellWithMessage(message, incoming: false) + } + } + else { + if let messageText = message.messageText { + let incomingModel = ChatBaseTextCellModel() + + if (UserDefaultsManager().DebugMode == false) { + incomingModel.message = messageText.text ?? "" + } else { + let s1 = (messageText.text ?? "") + let s2 = (messageText.msgv3HashHex ?? "") + let s3 = (message.senderUniqueIdentifier ?? "") + let s4 = (message.chatUniqueIdentifier) + let s5 = String(messageText.isDelivered) + let s6 = String(message.tssent) + let s7 = String(message.tsrcvd) + let s8 = String(message.dateInterval) + incomingModel.message = "" + s1 + "\n" + + "msgv3HashHex:\n" + s2 + "\n" + + "senderUniqueIdentifier:\n" + s3 + "\n" + + "chatUniqueIdentifier:\n" + s4 + "\n" + + "isDelivered:\n" + s5 + "\n" + + "tssent:\n" + s6 + "\n" + + "tsrcvd:\n" + s7 + "\n" + + "dateInterval:\n" + s8 + "\n" + } + + model = incomingModel + + cell = tableView.dequeueReusableCell(withIdentifier: ChatIncomingTextCell.staticReuseIdentifier) as! ChatIncomingTextCell + } + else if let messageCall = message.messageCall { + let incomingModel = ChatIncomingCallCellModel() + incomingModel.callDuration = messageCall.callDuration + incomingModel.answered = (messageCall.callEvent == .answered) + model = incomingModel + + cell = tableView.dequeueReusableCell(withIdentifier: ChatIncomingCallCell.staticReuseIdentifier) as! ChatIncomingCallCell + } + else if let _ = message.messageFile { + (model, cell) = imageCellWithMessage(message, incoming: true) + } + } + + var incoming_text_message: Bool = false + if (!message.isOutgoing()) { + if let messageText = message.messageText { + incoming_text_message = true + } + } + + if (incoming_text_message) { + if (message.tssent == 0) { + model.dateString = timeFormatter.string(from: message.date()) + "\n" + dateFormatter.string(from: message.date()) + } else { + let real_datetime = Date(timeIntervalSince1970: TimeInterval(message.tssent)) + model.dateString = timeFormatter.string(from: real_datetime) + "\n" + dateFormatter.string(from: real_datetime) + // os_log("mmm:%s", timeFormatter.string(from: real_datetime)) + } + } else { + model.dateString = timeFormatter.string(from: message.date()) + "\n" + dateFormatter.string(from: message.date()) + } + + cell.delegate = self + cell.setupWithTheme(theme, model: model) + cell.transform = tableView.transform; + + return cell + } + + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return min(visibleMessages, messages.count) + } +} + +extension ChatPrivateController: UITableViewDelegate { + func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { + if indexPath.row == 0 { + toggleNewMessageView(show: false) + } + + maybeLoadImageForCellAtPath(cell, indexPath: indexPath) + } + + func tableView(_ tableView: UITableView, shouldShowMenuForRowAt indexPath: IndexPath) -> Bool { + guard !tableView.isEditing else { + return false + } + guard let editable = tableView.cellForRow(at: indexPath) as? ChatEditable else { + return false + } + + if !editable.shouldShowMenu() { + return false + } + + selectedMenuIndexPath = indexPath + editable.willShowMenu() + + return true + } + + func tableView(_ tableView: UITableView, canPerformAction action: Selector, forRowAt indexPath: IndexPath, withSender sender: Any?) -> Bool { + guard let cell = tableView.cellForRow(at: indexPath) as? ChatMovableDateCell else { + return false + } + + return cell.isMenuActionSupportedByCell(action) + } + + func tableView(_ tableView: UITableView, performAction action: Selector, forRowAt indexPath: IndexPath, withSender sender: Any?) { + // Dummy method to make tableView:shouldShowMenuForRowAtIndexPath: work. + } +} + +extension ChatPrivateController: UIScrollViewDelegate { + func scrollViewDidScroll(_ scrollView: UIScrollView) { + guard let tableView = tableView else { + return + } + guard scrollView === tableView else { + return + } + + if tableView.contentOffset.y > (tableView.contentSize.height - tableView.frame.size.height) { + let previous = visibleMessages + + visibleMessages = visibleMessages + Constants.MessagesPortionSize + + if visibleMessages > messages.count { + visibleMessages = messages.count + } + + if visibleMessages != previous { + tableView.reloadData() + } + } + } +} + +extension ChatPrivateController: ChatMovableDateCellDelegate { + func chatMovableDateCellCopyPressed(_ cell: ChatMovableDateCell) { + guard let indexPath = tableView?.indexPath(for: cell) else { + return + } + + let message = messages[indexPath.row] + + if let messageText = message.messageText { + UIPasteboard.general.string = messageText.text + } + else if let _ = message.messageCall { + fatalError("Message call cannot be copied") + } + else if let messageFile = message.messageFile { + guard UTTypeConformsTo(messageFile.fileUTI as CFString? ?? "" as CFString, kUTTypeImage) else { + fatalError("Cannot copy non-image file") + } + guard let file = messageFile.filePath() else { + assertionFailure("Tried to copy non-existing file") + return + } + guard let image = UIImage(contentsOfFile: file) else { + assertionFailure("Cannot create image from file") + return + } + + UIPasteboard.general.image = image + } + } + + func chatMovableDateCellDeletePressed(_ cell: ChatMovableDateCell) { + guard let indexPath = tableView?.indexPath(for: cell) else { + return + } + + let message = messages[indexPath.row] + + submanagerChats.removeMessages([message]) + } + + func chatMovableDateCellMorePressed(_ cell: ChatMovableDateCell) { + toggleTableViewEditing(true, animated: true) + + // TODO select row + // guard let indexPath = tableView?.indexPathForCell(cell) else { + // return + // } + + // tableView?.selectRowAtIndexPath(indexPath, animated: false, scrollPosition: .None) + } +} + +extension ChatPrivateController: UIGestureRecognizerDelegate { + func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { + guard let panGR = gestureRecognizer as? UIPanGestureRecognizer else { + return false + } + + let translation = panGR.translation(in: panGR.view) + + return fabsf(Float(translation.x)) > fabsf(Float(translation.y)) + } +} + +private extension ChatPrivateController { + func createNavigationViews() { + titleView = ChatPrivateTitleView(theme: theme) + navigationItem.titleView = titleView + + // create correct navigation buttons + toggleTableViewEditing(false, animated: false) + } + + func createTableView() { + let tableView = UITableView() + self.tableView = tableView + tableView.dataSource = self + tableView.delegate = self + tableView.transform = CGAffineTransform(a: 1, b: 0, c: 0, d: -1, tx: 0, ty: 0) + tableView.scrollsToTop = false + tableView.allowsSelection = false + tableView.estimatedRowHeight = 44.0 + tableView.backgroundColor = theme.colorForType(.NormalBackground) + tableView.allowsMultipleSelectionDuringEditing = true + tableView.separatorStyle = .none + + view.addSubview(tableView) + + tableView.register(ChatMovableDateCell.self, forCellReuseIdentifier: ChatMovableDateCell.staticReuseIdentifier) + tableView.register(ChatIncomingTextCell.self, forCellReuseIdentifier: ChatIncomingTextCell.staticReuseIdentifier) + tableView.register(ChatOutgoingTextCell.self, forCellReuseIdentifier: ChatOutgoingTextCell.staticReuseIdentifier) + tableView.register(ChatIncomingCallCell.self, forCellReuseIdentifier: ChatIncomingCallCell.staticReuseIdentifier) + tableView.register(ChatOutgoingCallCell.self, forCellReuseIdentifier: ChatOutgoingCallCell.staticReuseIdentifier) + tableView.register(ChatIncomingFileCell.self, forCellReuseIdentifier: ChatIncomingFileCell.staticReuseIdentifier) + tableView.register(ChatOutgoingFileCell.self, forCellReuseIdentifier: ChatOutgoingFileCell.staticReuseIdentifier) + + tableViewTapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(ChatPrivateController.tapOnTableView)) + tableView.addGestureRecognizer(tableViewTapGestureRecognizer) + + let panGR = UIPanGestureRecognizer(target: self, action: #selector(ChatPrivateController.panOnTableView(_:))) + panGR.delegate = self + tableView.addGestureRecognizer(panGR) + } + + func createTableHeaderViews() { + typingHeaderView = ChatTypingHeaderView(theme: theme) + typingHeaderView.transform = tableView!.transform + view.addSubview(typingHeaderView) + + fauxOfflineHeaderView = ChatFauxOfflineHeaderView(theme: theme) + fauxOfflineHeaderView.transform = tableView!.transform + view.addSubview(fauxOfflineHeaderView) + } + + func createNewMessagesView() { + newMessagesView = UIView() + newMessagesView.backgroundColor = theme.colorForType(.ConnectingBackground) + newMessagesView.layer.cornerRadius = 5.0 + newMessagesView.layer.masksToBounds = true + newMessagesView.isHidden = true + view.addSubview(newMessagesView) + + let label = UILabel() + label.text = String(localized: "chat_new_messages") + label.textColor = theme.colorForType(.ConnectingText) + label.backgroundColor = .clear + label.font = UIFont.systemFont(ofSize: 12.0) + newMessagesView.addSubview(label) + + let button = UIButton() + button.addTarget(self, action: #selector(ChatPrivateController.newMessagesViewPressed), for: .touchUpInside) + newMessagesView.addSubview(button) + + label.snp.makeConstraints { + $0.leading.equalTo(newMessagesView).offset(Constants.NewMessageViewEdgesOffset) + $0.trailing.equalTo(newMessagesView).offset(-Constants.NewMessageViewEdgesOffset) + $0.top.equalTo(newMessagesView).offset(Constants.NewMessageViewEdgesOffset) + $0.bottom.equalTo(newMessagesView).offset(-Constants.NewMessageViewEdgesOffset) + } + + button.snp.makeConstraints { + $0.edges.equalTo(newMessagesView) + } + } + + func createInputView() { + chatInputView = ChatInputView(theme: theme) + view.addSubview(chatInputView) + + chatInputViewManager = ChatInputViewManager(inputView: chatInputView, + chat: chat, + submanagerChats: submanagerChats, + submanagerFiles: submanagerFiles, + submanagerObjects: submanagerObjects, + presentingViewController: self) + } + + func createEditMessageToolbar() { + editMessagesToolbar = UIToolbar() + editMessagesToolbar.isHidden = true + editMessagesToolbar.tintColor = theme.colorForType(.LinkText) + editMessagesToolbar.items = [ + UIBarButtonItem(barButtonSystemItem: .trash, target: self, action: #selector(ChatPrivateController.editMessagesDeleteButtonPressed(_:))) + ] + view.addSubview(editMessagesToolbar) + } + + func installConstraints() { + tableView!.snp.makeConstraints { + $0.top.leading.trailing.equalTo(view) + + tableViewToChatInputConstraint = $0.bottom.equalTo(chatInputView.snp.top).constraint + } + + typingHeaderView.snp.makeConstraints { + $0.leading.trailing.equalTo(view) + $0.top.equalTo(tableView!.snp.bottom) + typingViewToChatInputConstraint = $0.bottom.equalTo(chatInputView.snp.top).constraint + } + + typingViewToChatInputConstraint.deactivate() + + newMessagesView.snp.makeConstraints { + $0.centerX.equalTo(tableView!) + newMessageViewTopConstraint = $0.top.equalTo(chatInputView.snp.top).constraint + } + + chatInputView.snp.makeConstraints { + $0.leading.trailing.equalTo(view) + $0.top.greaterThanOrEqualTo(view).offset(Constants.InputViewTopOffset) + chatInputViewBottomConstraint = $0.bottom.equalTo(view).constraint + // TODO: this moves the input view a bit more to the top, because the home button "line" is in the way otherwise + // please fix me properly in the future + if #available(iOS 11.0, *) { + let keyWindow = UIApplication.shared.keyWindow + let b = keyWindow?.safeAreaInsets.bottom + chatInputViewBottomConstraint?.update(offset: -(b ?? 20)) + } + } + + editMessagesToolbar.snp.makeConstraints { + $0.edges.equalTo(chatInputView) + } + } + + func addMessagesNotification() { + self.messagesToken = messages.addNotificationBlock { [unowned self] change in + guard let tableView = self.tableView else { + return + } + switch change { + case .initial: + break + case .update(_, let deletions, let insertions, let modifications): + + // TODO: this is a very bad workaround. when more than 1 message is incoming + // those would crash. + /* + tableView.beginUpdates() + self.updateTableViewWithDeletions(deletions) + self.updateTableViewWithInsertions(insertions) + self.updateTableViewWithModifications(modifications) + + self.visibleMessages = self.visibleMessages + insertions.count - deletions.count + tableView.endUpdates() + */ + // now just reload the whole table to avoid the crash, until there is a fix + tableView.reloadData() + + self.updateTableHeaderView() + + if insertions.contains(0) { + self.handleNewMessage() + } + case .error(let error): + fatalError("\(error)") + } + } + } + + func updateTableViewWithDeletions(_ deletions: [Int]) { + guard let tableView = tableView else { + return + } + + for index in deletions { + if index >= visibleMessages { + continue + } + let indexPath = IndexPath(row: index, section: 0) + tableView.deleteRows(at: [indexPath], with: .top) + } + } + + func updateTableViewWithInsertions(_ insertions: [Int]) { + guard let tableView = tableView else { + return + } + + for index in insertions { + if index >= visibleMessages { + continue + } + let indexPath = IndexPath(row: index, section: 0) + tableView.insertRows(at: [indexPath], with: .top) + } + } + + func updateTableViewWithModifications(_ modifications: [Int]) { + guard let tableView = tableView else { + return + } + + for index in modifications { + if index >= visibleMessages { + continue + } + let message = messages[index] + let indexPath = IndexPath(row: index, section: 0) + + if message.messageFile == nil { + tableView.reloadRows(at: [indexPath], with: .none) + continue + } + + guard let cell = tableView.cellForRow(at: indexPath) as? ChatGenericFileCell else { + continue + } + + let model = ChatIncomingFileCellModel() + prepareFileCell(cell, andModel: model, withMessage: message) + cell.setupWithTheme(theme, model: model) + + maybeLoadImageForCellAtPath(cell, indexPath: indexPath) + } + } + + func addFriendNotification() { + guard let friend = self.friend else { + titleView.name = String(localized: "contact_deleted") + titleView.userStatus = UserStatus(connectionStatus: .none, userStatus: .none) + titleView.connectionStatus = ConnectionStatus(connectionStatus: .none) + audioButton.isEnabled = true + videoButton.isEnabled = false + locationButton.isEnabled = true + chatInputView.cameraButtonEnabled = false + return + } + + titleView.name = friend.nickname + titleView.userStatus = UserStatus(connectionStatus: friend.connectionStatus, userStatus: friend.status) + titleView.connectionStatus = ConnectionStatus(connectionStatus: friend.connectionStatus) + + let predicate = NSPredicate(format: "uniqueIdentifier == %@", friend.uniqueIdentifier) + let results = submanagerObjects.friends(predicate: predicate) + + friendToken = results.addNotificationBlock { [unowned self] change in + guard let friend = self.friend else { + return + } + + switch change { + case .initial: + fallthrough + case .update: + self.titleView.name = friend.nickname + self.titleView.userStatus = UserStatus(connectionStatus: friend.connectionStatus, userStatus: friend.status) + self.titleView.connectionStatus = ConnectionStatus(connectionStatus: friend.connectionStatus) + + let isConnected = friend.isConnected + + self.audioButton.isEnabled = true + self.videoButton.isEnabled = isConnected + self.locationButton.isEnabled = true + self.chatInputView.cameraButtonEnabled = isConnected + + self.updateTableHeaderView() + case .error(let error): + fatalError("\(error)") + } + } + } + + func updateTableHeaderView() { + guard let tableView = tableView else { + return + } + + guard let friend = friend else { + // tableView.tableHeaderView = nil + return + } + + UIView.animate(withDuration: Constants.NewMessageViewAnimationDuration, animations: { + if friend.isConnected { + if friend.isTyping { + self.tableViewToChatInputConstraint.deactivate() + self.typingViewToChatInputConstraint.activate() + self.typingHeaderView.isHidden = false + self.typingHeaderView.startAnimation() + } + else { + self.tableViewToChatInputConstraint.activate() + self.typingViewToChatInputConstraint.deactivate() + self.typingHeaderView.isHidden = true + self.typingHeaderView.stopAnimation() + } + + self.view.layoutIfNeeded() + } + else { + // let predicate = NSPredicate(format: "messageText.isDelivered == NO AND senderUniqueIdentifier == nil") + // let hasUnsendMessages = self.messages.objects(with: predicate).count > 0 + + // tableView.tableHeaderView = hasUnsendMessages ? self.fauxOfflineHeaderView : nil + } + }) + + updateTableHeaderViewLayout() + } + + func updateTableHeaderViewLayout() { + guard let headerView = tableView?.tableHeaderView else { + return + } + + headerView.setNeedsLayout() + headerView.layoutIfNeeded() + let height = headerView.systemLayoutSizeFitting(UILayoutFittingCompressedSize).height + headerView.frame.size.height = height + tableView?.tableHeaderView = headerView + } + + func updateInputViewMaxHeight() { + chatInputView.maxHeight = chatInputView.frame.maxY - Constants.InputViewTopOffset + } + + func handleNewMessage() { + if UIApplication.isActive { + updateLastReadDate() + } + + guard let tableView = tableView else { + return + } + guard let visible = tableView.indexPathsForVisibleRows else { + return + } + + let first = IndexPath(row: 0, section: 0) + + if !visible.contains(first) { + toggleNewMessageView(show: true) + } + } + + func toggleNewMessageView(show: Bool) { + guard show != newMessagesViewVisible else { + return + } + newMessagesViewVisible = show + + if show { + newMessagesView.isHidden = false + } + + UIView.animate(withDuration: Constants.NewMessageViewAnimationDuration, animations: { + if show { + self.newMessageViewTopConstraint?.update(offset: Constants.NewMessageViewTopOffset - self.newMessagesView.frame.size.height) + } + else { + self.newMessageViewTopConstraint?.update(offset: 0.0) + } + + self.view.layoutIfNeeded() + + }, completion: { finished in + if !show { + self.newMessagesView.isHidden = true + } + }) + } + + func updateLastReadDate() { + submanagerObjects.change(chat, lastReadDateInterval: Date().timeIntervalSince1970) + } + + func imageCellWithMessage(_ message: OCTMessageAbstract, incoming: Bool) -> (ChatMovableDateCellModel, ChatMovableDateCell) { + let cell: ChatGenericFileCell + + if incoming { + cell = tableView!.dequeueReusableCell(withIdentifier: ChatIncomingFileCell.staticReuseIdentifier) as! ChatIncomingFileCell + } + else { + cell = tableView!.dequeueReusableCell(withIdentifier: ChatOutgoingFileCell.staticReuseIdentifier) as! ChatOutgoingFileCell + } + let model = ChatIncomingFileCellModel() + + prepareFileCell(cell, andModel: model, withMessage: message) + + return (model, cell) + } + + func prepareFileCell(_ cell: ChatGenericFileCell, andModel model: ChatGenericFileCellModel, withMessage message: OCTMessageAbstract) { + cell.progressObject = nil + + model.fileName = message.messageFile!.fileName + model.fileSize = ByteCountFormatter.string(fromByteCount: message.messageFile!.fileSize, countStyle: .file) + model.fileUTI = message.messageFile!.fileUTI + + switch message.messageFile!.fileType { + case .waitingConfirmation: + model.state = .waitingConfirmation + case .loading: + model.state = .loading + + let bridge = ChatProgressBridge() + cell.progressObject = bridge + _ = try? self.submanagerFiles.add(bridge, forFileTransfer: message) + case .paused: + model.state = .paused + case .canceled: + model.state = .cancelled + case .ready: + model.state = .done + } + + if !message.isOutgoing() { + model.startLoadingHandle = { [weak self] in + self?.submanagerFiles.acceptFileTransfer(message) { (error: Error) -> Void in + handleErrorWithType(.acceptIncomingFile, error: error as NSError) + } + } + } + + model.cancelHandle = { [weak self] in + do { + try self?.submanagerFiles.cancelFileTransfer(message) + } + catch let error as NSError { + handleErrorWithType(.cancelFileTransfer, error: error) + } + } + + model.retryHandle = { [weak self] in + self?.submanagerFiles.retrySendingFile(message) { (error: Error) in + handleErrorWithType(.sendFileToFriend, error: error as NSError) + } + } + + model.pauseOrResumeHandle = { [weak self] in + let isPaused = (message.messageFile!.pausedBy.rawValue & OCTMessageFilePausedBy.user.rawValue) != 0 + + do { + try self?.submanagerFiles.pauseFileTransfer(!isPaused, message: message) + } + catch let error as NSError { + handleErrorWithType(.cancelFileTransfer, error: error) + } + } + + model.openHandle = { [weak self] in + guard let sself = self else { + return + } + let qlDataSource = FilePreviewControllerDataSource(chat: sself.chat, submanagerObjects: sself.submanagerObjects) + guard let index = qlDataSource.indexOfMessage(message) else { + return + } + + sself.delegate?.chatPrivateControllerShowQuickLookController(sself, dataSource: qlDataSource, selectedIndex: index) + } + } + + func maybeLoadImageForCellAtPath(_ cell: UITableViewCell, indexPath: IndexPath) { + let message = messages[indexPath.row] + + guard let messageFile = message.messageFile else { + return + } + + guard UTTypeConformsTo(messageFile.fileUTI as CFString? ?? "" as CFString, kUTTypeImage) else { + return + } + + guard let file = messageFile.filePath() else { + return + } + + if messageFile.fileSize >= Constants.MaxImageSizeToShowInline { + return + } + + if let image = imageCache.object(forKey: file as AnyObject) as? UIImage { + let cell = (cell as? ChatIncomingFileCell) ?? (cell as? ChatOutgoingFileCell) + + cell?.setButtonImage(image) + } + else { + loadImageForCellAtIndexPath(indexPath, fromFile: file) + } + } + + func loadImageForCellAtIndexPath(_ indexPath: IndexPath, fromFile: String) { + DispatchQueue.global(qos: .default).async { [weak self] in + guard var image = UIImage(contentsOfFile: fromFile) else { + return + } + + var size = image.size + guard size.width > 0 || size.height > 0 else { + return + } + + let delta = (size.width > size.height) ? (Constants.MaxInlineImageSide / size.width) : (Constants.MaxInlineImageSide / size.height) + + size.width *= delta + size.height *= delta + + image = image.scaleToSize(size) + self?.imageCache.setObject(image, forKey: fromFile as AnyObject) + + DispatchQueue.main.async { + let optionalCell = self?.tableView?.cellForRow(at: indexPath) + guard let cell = (optionalCell as? ChatIncomingFileCell) ?? (optionalCell as? ChatOutgoingFileCell) else { + return + } + + cell.setButtonImage(image) + } + } + } + + func toggleTableViewEditing(_ editing: Bool, animated: Bool) { + tableView?.setEditing(editing, animated: animated) + + tableViewTapGestureRecognizer.isEnabled = !editing + editMessagesToolbar.isHidden = !editing + + if editing { + _ = chatInputView.resignFirstResponder() + + navigationItem.leftBarButtonItems = [UIBarButtonItem( + title: String(localized: "delete_all_messages"), + style: .plain, + target: self, + action: #selector(ChatPrivateController.deleteAllMessagesButtonPressed(_:)))] + + navigationItem.rightBarButtonItems = [UIBarButtonItem( + barButtonSystemItem: .cancel, + target: self, + action: #selector(ChatPrivateController.cancelEditingButtonPressed))] + } + else { + let audioImage = UIImage(named: "start-call-medium")! + let videoImage = UIImage(named: "video-call-medium")! + let locationImage = UIImage(named: "location-call-medium")!.withRenderingMode(.alwaysOriginal) + audioButton = UIBarButtonItem(image: audioImage, style: .plain, target: self, action: #selector(ChatPrivateController.audioCallButtonPressed)) + videoButton = UIBarButtonItem(image: videoImage, style: .plain, target: self, action: #selector(ChatPrivateController.videoCallButtonPressed)) + locationButton = UIBarButtonItem(image: locationImage, style: .plain, target: self, action: #selector(ChatPrivateController.locationButtonPressed)) + + if (AppDelegate.location_sharing_contact_pubkey != "-1") { + let locationImage = UIImage(named: "location-call-activated-medium")!.withRenderingMode(.alwaysOriginal) + locationButton.setBackgroundImage(locationImage, for: .normal, barMetrics: .default) + } + + navigationItem.leftBarButtonItems = nil + navigationItem.rightBarButtonItems = [ + videoButton, + audioButton, + locationButton + ] + } + } + + func showMessageDeletionConfirmation(messagesCount: Int, + showFromItem barButtonItem: UIBarButtonItem, + deleteClosure: @escaping () -> Void) { + let deleteButtonText = messagesCount > 1 ? + String(localized: "delete_multiple_messages") + " (\(messagesCount))" : + String(localized: "delete_single_message") + + let alert = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) + alert.popoverPresentationController?.barButtonItem = barButtonItem + + alert.addAction(UIAlertAction(title: deleteButtonText, style: .destructive) { _ -> Void in + deleteClosure() + }) + + alert.addAction(UIAlertAction(title: String(localized: "alert_cancel"), style: .cancel, handler: nil)) + + present(alert, animated: true, completion: nil) + } +} diff --git a/Antidote/ChatPrivateTitleView.swift b/Antidote/ChatPrivateTitleView.swift new file mode 100644 index 0000000..34e9861 --- /dev/null +++ b/Antidote/ChatPrivateTitleView.swift @@ -0,0 +1,111 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit +import SnapKit + +private struct Constants { + static let StatusViewLeftOffset: CGFloat = 5.0 + static let StatusViewSize: CGFloat = 10.0 +} + +class ChatPrivateTitleView: UIView { + var name: String { + get { + return nameLabel.text ?? "" + } + set { + nameLabel.text = newValue + + updateFrame() + } + } + + var userStatus: UserStatus { + get { + return statusView.userStatus + } + set { + statusView.userStatus = newValue + statusLabel.text = newValue.toString() + + updateFrame() + } + } + + var connectionStatus: ConnectionStatus { + get { + return statusView.connectionStatus + } + set { + statusView.connectionStatus = newValue + + updateFrame() + } + } + + fileprivate var nameLabel: UILabel! + fileprivate var statusView: UserStatusView! + fileprivate var statusLabel: UILabel! + + init(theme: Theme) { + super.init(frame: CGRect.zero) + + backgroundColor = .clear + + createViews(theme) + } + + required convenience init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +private extension ChatPrivateTitleView { + func createViews(_ theme: Theme) { + nameLabel = UILabel() + nameLabel.textAlignment = .center + nameLabel.textColor = theme.colorForType(.NormalText) + nameLabel.font = UIFont.antidoteFontWithSize(16.0, weight: .bold) + addSubview(nameLabel) + + statusView = UserStatusView() + statusView.showExternalCircle = false + statusView.theme = theme + addSubview(statusView) + + statusLabel = UILabel() + statusLabel.textAlignment = .center + statusLabel.textColor = theme.colorForType(.NormalText) + statusLabel.font = UIFont.antidoteFontWithSize(12.0, weight: .light) + addSubview(statusLabel) + + nameLabel.snp.makeConstraints { + $0.top.equalTo(self) + $0.leading.equalTo(self) + } + + statusView.snp.makeConstraints { + $0.centerY.equalTo(nameLabel) + $0.leading.equalTo(nameLabel.snp.trailing).offset(Constants.StatusViewLeftOffset) + $0.trailing.equalTo(self) + $0.size.equalTo(Constants.StatusViewSize) + } + + statusLabel.snp.makeConstraints { + $0.top.equalTo(nameLabel.snp.bottom) + $0.leading.equalTo(nameLabel) + $0.trailing.equalTo(nameLabel) + $0.bottom.equalTo(self) + } + } + + func updateFrame() { + nameLabel.sizeToFit() + statusLabel.sizeToFit() + + frame.size.width = max(nameLabel.frame.size.width, statusLabel.frame.size.width) + Constants.StatusViewLeftOffset + Constants.StatusViewSize + frame.size.height = nameLabel.frame.size.height + statusLabel.frame.size.height + } +} diff --git a/Antidote/ChatProgressBridge.swift b/Antidote/ChatProgressBridge.swift new file mode 100644 index 0000000..d6ab275 --- /dev/null +++ b/Antidote/ChatProgressBridge.swift @@ -0,0 +1,23 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +/** + Bridge between objcTox subscriber and chat progress protocol. + */ +class ChatProgressBridge: NSObject, ChatProgressProtocol { + var updateProgress: ((_ progress: Float) -> Void)? + var updateEta: ((_ eta: CFTimeInterval, _ bytesPerSecond: OCTToxFileSize) -> Void)? +} + +extension ChatProgressBridge: OCTSubmanagerFilesProgressSubscriber { + func submanagerFiles(onProgressUpdate progress: Float, message: OCTMessageAbstract) { + updateProgress?(progress) + } + + func submanagerFiles(onEtaUpdate eta: CFTimeInterval, bytesPerSecond: OCTToxFileSize, message: OCTMessageAbstract) { + updateEta?(eta, bytesPerSecond) + } +} diff --git a/Antidote/ChatProgressProtocol.swift b/Antidote/ChatProgressProtocol.swift new file mode 100644 index 0000000..7bfa58b --- /dev/null +++ b/Antidote/ChatProgressProtocol.swift @@ -0,0 +1,10 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +protocol ChatProgressProtocol { + var updateProgress: ((_ progress: Float) -> Void)? { get set } + var updateEta: ((_ eta: CFTimeInterval, _ bytesPerSecond: OCTToxFileSize) -> Void)? { get set } +} diff --git a/Antidote/ChatTypingHeaderView.swift b/Antidote/ChatTypingHeaderView.swift new file mode 100644 index 0000000..bd999c9 --- /dev/null +++ b/Antidote/ChatTypingHeaderView.swift @@ -0,0 +1,101 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation +import SnapKit + +fileprivate struct Constants { + static let verticalOffset = 7.0 + static let horizontalOffset = 20.0 + + static let animationStepDuration = 0.7 +} + +class ChatTypingHeaderView: UIView { + fileprivate let theme: Theme + + fileprivate var bubbleView: BubbleView! + fileprivate var label: UILabel! + + fileprivate var animationTimer: Timer? + fileprivate var animationStep: Int = 0 + + init(theme: Theme) { + self.theme = theme + + super.init(frame: CGRect.zero) + + createViews() + installConstraints() + } + + required convenience init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func startAnimation() { + animationTimer = Timer.scheduledTimer(timeInterval: Constants.animationStepDuration, closure: {[weak self] _ -> Void in + guard let sself = self else { + return + } + + sself.animationStep += 1 + if sself.animationStep > 2 { + sself.animationStep = 0 + } + + sself.updateDotsString() + }, repeats: true) + } + + func stopAnimation() { + animationTimer?.invalidate() + animationTimer = nil + } + +} + +private extension ChatTypingHeaderView { + func createViews() { + bubbleView = BubbleView() + bubbleView.text = " " + bubbleView.backgroundColor = theme.colorForType(.ChatIncomingBubble) + bubbleView.isUserInteractionEnabled = false + addSubview(bubbleView) + + label = UILabel() + addSubview(label) + + updateDotsString() + } + + func installConstraints() { + bubbleView.snp.makeConstraints() { + $0.top.equalTo(self).offset(Constants.verticalOffset) + $0.bottom.equalTo(self).offset(-Constants.verticalOffset) + $0.leading.equalTo(self).offset(Constants.horizontalOffset) + } + + label.snp.makeConstraints() { + $0.center.equalTo(bubbleView) + } + } + + func updateDotsString() { + let mutable = NSMutableAttributedString() + let font = UIFont.systemFont(ofSize: 22.0) + let colorNormal = theme.colorForType(.ChatInformationText) + let colorSelected = colorNormal.darkerColor().darkerColor() + + for i in 0..<3 { + let color = (i == animationStep) ? colorSelected : colorNormal + // HINT: u{2022} --> UTF-8 BULLET --> e2 80 a2 + mutable.append(NSMutableAttributedString(string: "\u{2022}", + attributes: [NSAttributedStringKey.font : font, + NSAttributedStringKey.foregroundColor: color])) + } + + label.attributedText = mutable + } +} diff --git a/Antidote/ChatsTabCoordinator.swift b/Antidote/ChatsTabCoordinator.swift new file mode 100644 index 0000000..c37fa7c --- /dev/null +++ b/Antidote/ChatsTabCoordinator.swift @@ -0,0 +1,94 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit + +protocol ChatsTabCoordinatorDelegate: class { + func chatsTabCoordinator(_ coordinator: ChatsTabCoordinator, chatWillAppear chat: OCTChat) + func chatsTabCoordinator(_ coordinator: ChatsTabCoordinator, chatWillDisapper chat: OCTChat) + func chatsTabCoordinator(_ coordinator: ChatsTabCoordinator, callToChat chat: OCTChat, enableVideo: Bool) +} + +class ChatsTabCoordinator: ActiveSessionNavigationCoordinator { + weak var delegate: ChatsTabCoordinatorDelegate? + + fileprivate weak var submanagerObjects: OCTSubmanagerObjects! + fileprivate weak var submanagerChats: OCTSubmanagerChats! + fileprivate weak var submanagerFiles: OCTSubmanagerFiles! + + init(theme: Theme, submanagerObjects: OCTSubmanagerObjects, submanagerChats: OCTSubmanagerChats, submanagerFiles: OCTSubmanagerFiles) { + self.submanagerObjects = submanagerObjects + self.submanagerChats = submanagerChats + self.submanagerFiles = submanagerFiles + + super.init(theme: theme) + } + + override func startWithOptions(_ options: CoordinatorOptions?) { + let controller = ChatListController(theme: theme, submanagerChats: submanagerChats, submanagerObjects: submanagerObjects) + controller.delegate = self + + navigationController.pushViewController(controller, animated: false) + } + + func showChat(_ chat: OCTChat, animated: Bool) { + if let top = navigationController.topViewController as? ChatPrivateController { + if top.chat == chat { + // controller is already visible + return + } + } + + let controller = ChatPrivateController( + theme: theme, + chat: chat, + submanagerChats: submanagerChats, + submanagerObjects: submanagerObjects, + submanagerFiles: submanagerFiles, + delegate: self) + + navigationController.popToRootViewController(animated: false) + navigationController.pushViewController(controller, animated: animated) + } + + /** + Returns active chat controller if it is visible, nil otherwise. + */ + func activeChatController() -> ChatPrivateController? { + return navigationController.topViewController as? ChatPrivateController + } +} + +extension ChatsTabCoordinator: ChatListControllerDelegate { + func chatListController(_ controller: ChatListController, didSelectChat chat: OCTChat) { + showChat(chat, animated: true) + } +} + +extension ChatsTabCoordinator: ChatPrivateControllerDelegate { + func chatPrivateControllerWillAppear(_ controller: ChatPrivateController) { + delegate?.chatsTabCoordinator(self, chatWillAppear: controller.chat) + } + + func chatPrivateControllerWillDisappear(_ controller: ChatPrivateController) { + delegate?.chatsTabCoordinator(self, chatWillDisapper: controller.chat) + } + + func chatPrivateControllerCallToChat(_ controller: ChatPrivateController, enableVideo: Bool) { + delegate?.chatsTabCoordinator(self, callToChat: controller.chat, enableVideo: enableVideo) + } + + func chatPrivateControllerShowQuickLookController( + _ controller: ChatPrivateController, + dataSource: QuickLookPreviewControllerDataSource, + selectedIndex: Int) + { + let controller = QuickLookPreviewController() + controller.dataSource = dataSource + controller.dataSourceStorage = dataSource + controller.currentPreviewItemIndex = selectedIndex + + navigationController.present(controller, animated: true, completion: nil) + } +} diff --git a/Antidote/ConnectionStatus.swift b/Antidote/ConnectionStatus.swift new file mode 100644 index 0000000..82323f4 --- /dev/null +++ b/Antidote/ConnectionStatus.swift @@ -0,0 +1,24 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +enum ConnectionStatus { + case none + case tcp + case udp + + init(connectionStatus: OCTToxConnectionStatus) { + switch (connectionStatus) { + case (.none): + self = .none + case (.TCP): + self = .tcp + case (.UDP): + self = .udp + default: + self = .none + } + } +} diff --git a/Antidote/CoordinatorProtocol.swift b/Antidote/CoordinatorProtocol.swift new file mode 100644 index 0000000..ecb8c9b --- /dev/null +++ b/Antidote/CoordinatorProtocol.swift @@ -0,0 +1,15 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +typealias CoordinatorOptions = [String: Any] + +protocol CoordinatorProtocol { + /** + This method will be called when coordinator should start working. + + - Parameters: + - options: Options to start with. Options are used for recovering state of coordinator on recreation. + */ + func startWithOptions(_ options: CoordinatorOptions?) +} diff --git a/Antidote/CopyLabel.swift b/Antidote/CopyLabel.swift new file mode 100644 index 0000000..d77596a --- /dev/null +++ b/Antidote/CopyLabel.swift @@ -0,0 +1,58 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit + +class CopyLabel: UILabel { + var copyable = true { + didSet { + recognizer.isEnabled = copyable + } + } + + fileprivate var recognizer: UITapGestureRecognizer! + + override init(frame: CGRect) { + super.init(frame: frame) + + isUserInteractionEnabled = true + + recognizer = UITapGestureRecognizer(target: self, action: #selector(CopyLabel.tapGesture)) + addGestureRecognizer(recognizer) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +// MARK: Actions +extension CopyLabel { + @objc func tapGesture() { + // This fixes issue with calling UIMenuController after UIActionSheet was presented. + let appDelegate = UIApplication.shared.delegate as! AppDelegate + appDelegate.window?.makeKey() + + becomeFirstResponder() + + let menu = UIMenuController.shared + menu.setTargetRect(frame, in: superview!) + menu.setMenuVisible(true, animated: true) + } +} + +// MARK: Copying +extension CopyLabel { + override func copy(_ sender: Any?) { + UIPasteboard.general.string = text + } + + override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool { + return action == #selector(copy(_:)) + } + + override var canBecomeFirstResponder : Bool { + return true + } +} diff --git a/Antidote/EnterPinController.swift b/Antidote/EnterPinController.swift new file mode 100644 index 0000000..19ab64e --- /dev/null +++ b/Antidote/EnterPinController.swift @@ -0,0 +1,148 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation +import SnapKit + +private struct Constants { + static let PinLength = 4 +} + +protocol EnterPinControllerDelegate: class { + func enterPinController(_ controller: EnterPinController, successWithPin pin: String) + + // This method may be called only for ValidatePin state. + func enterPinControllerFailure(_ controller: EnterPinController) +} + +class EnterPinController: UIViewController { + enum State { + case validatePin(validPin: String) + case setPin + } + + weak var delegate: EnterPinControllerDelegate? + + let state: State + + var topText: String { + get { + return pinInputView.topText + } + set { + customLoadView() + pinInputView.topText = newValue + } + } + + var descriptionText: String? { + get { + return pinInputView.descriptionText + } + set { + customLoadView() + pinInputView.descriptionText = newValue + } + } + + fileprivate let theme: Theme + + fileprivate var pinInputView: PinInputView! + + fileprivate var enteredString: String = "" + + init(theme: Theme, state: State) { + self.theme = theme + self.state = state + + super.init(nibName: nil, bundle: nil) + } + + required convenience init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func loadView() { + loadViewWithBackgroundColor(theme.colorForType(.NormalBackground)) + + createViews() + installConstraints() + + pinInputView.applyColors() + } + + override var shouldAutorotate : Bool { + return false + } + + override var supportedInterfaceOrientations : UIInterfaceOrientationMask { + return UIInterfaceOrientationMask.portrait + } + + func resetEnteredPin() { + enteredString = "" + pinInputView.enteredNumbersCount = enteredString.count + } +} + +extension EnterPinController: PinInputViewDelegate { + func pinInputView(_ view: PinInputView, numericButtonPressed i: Int) { + guard enteredString.count < Constants.PinLength else { + return + } + + enteredString += "\(i)" + pinInputView.enteredNumbersCount = enteredString.count + + if enteredString.count == Constants.PinLength { + switch state { + case .validatePin(let validPin): + if enteredString == validPin { + delegate?.enterPinController(self, successWithPin: enteredString) + } + else { + delegate?.enterPinControllerFailure(self) + } + case .setPin: + delegate?.enterPinController(self, successWithPin: enteredString) + } + } + } + + func pinInputViewDeleteButtonPressed(_ view: PinInputView) { + guard enteredString.count > 0 else { + return + } + + enteredString = String(enteredString.dropLast()) + view.enteredNumbersCount = enteredString.count + } +} + +private extension EnterPinController { + func createViews() { + pinInputView = PinInputView(pinLength: Constants.PinLength, + topColor: theme.colorForType(.LockGradientTop), + bottomColor: theme.colorForType(.LockGradientBottom)) + pinInputView.delegate = self + view.addSubview(pinInputView) + } + + func installConstraints() { + pinInputView.snp.makeConstraints { + $0.center.equalTo(view) + } + } + + func customLoadView() { + if #available(iOS 9.0, *) { + loadViewIfNeeded() + } else { + if !isViewLoaded { + // creating view + view.setNeedsDisplay() + } + } + } +} diff --git a/Antidote/ErrorHandling.swift b/Antidote/ErrorHandling.swift new file mode 100644 index 0000000..f4b199e --- /dev/null +++ b/Antidote/ErrorHandling.swift @@ -0,0 +1,337 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit + +enum ErrorHandlerType { + case cannotLoadHTML + case createOCTManager + case toxSetInfoCodeName + case toxSetInfoCodeStatusMessage + case toxAddFriend + case removeFriend + case callToChat + case exportProfile + case deleteProfile + case passwordIsEmpty + case wrongOldPassword + case passwordsDoNotMatch + case answerCall + case routeAudioToSpeaker + case enableVideoSending + case callSwitchCamera + case convertImageToPNG + case changeAvatar + case sendFileToFriend + case acceptIncomingFile + case cancelFileTransfer + case pauseFileTransfer + case pinLogOut +} + + +/** + Show alert for given error. + + - Parameters: + - type: Type of error to handle. + - error: Optional erro to get code from. + - retryBlock: If set user will be asked to retry request once again. + */ +func handleErrorWithType(_ type: ErrorHandlerType, error: NSError? = nil, retryBlock: (() -> Void)? = nil) { + switch type { + case .cannotLoadHTML: + UIAlertController.showErrorWithMessage(String(localized: "error_internal_message"), retryBlock: retryBlock) + case .createOCTManager: + let (title, message) = OCTManagerInitError(rawValue: error!.code)!.strings() + UIAlertController.showWithTitle(title, message: message, retryBlock: retryBlock) + case .toxSetInfoCodeName: + let (title, message) = OCTToxErrorSetInfoCode(rawValue: error!.code)!.nameStrings() + UIAlertController.showWithTitle(title, message: message, retryBlock: retryBlock) + case .toxSetInfoCodeStatusMessage: + let (title, message) = OCTToxErrorSetInfoCode(rawValue: error!.code)!.statusMessageStrings() + UIAlertController.showWithTitle(title, message: message, retryBlock: retryBlock) + case .toxAddFriend: + let (title, message) = OCTToxErrorFriendAdd(rawValue: error!.code)!.strings() + UIAlertController.showWithTitle(title, message: message, retryBlock: retryBlock) + case .removeFriend: + let (title, message) = OCTToxErrorFriendDelete(rawValue: error!.code)!.strings() + UIAlertController.showWithTitle(title, message: message, retryBlock: retryBlock) + case .callToChat: + let (title, message) = OCTToxAVErrorCall(rawValue: error!.code)!.strings() + UIAlertController.showWithTitle(title, message: message, retryBlock: retryBlock) + case .exportProfile: + UIAlertController.showWithTitle(String(localized: "error_title"), message: error!.localizedDescription, retryBlock: retryBlock) + case .deleteProfile: + UIAlertController.showWithTitle(String(localized: "error_title"), message: error!.localizedDescription, retryBlock: retryBlock) + case .passwordIsEmpty: + UIAlertController.showWithTitle(String(localized: "password_is_empty_error"), retryBlock: retryBlock) + case .wrongOldPassword: + UIAlertController.showWithTitle(String(localized: "wrong_old_password"), retryBlock: retryBlock) + case .passwordsDoNotMatch: + UIAlertController.showWithTitle(String(localized: "passwords_do_not_match"), retryBlock: retryBlock) + case .answerCall: + let (title, message) = OCTToxAVErrorAnswer(rawValue: error!.code)!.strings() + UIAlertController.showWithTitle(title, message: message, retryBlock: retryBlock) + case .routeAudioToSpeaker: + UIAlertController.showWithTitle(String(localized: "error_title"), message: String(localized: "error_internal_message"), retryBlock: retryBlock) + case .enableVideoSending: + UIAlertController.showWithTitle(String(localized: "error_title"), message: String(localized: "error_internal_message"), retryBlock: retryBlock) + case .callSwitchCamera: + UIAlertController.showWithTitle(String(localized: "error_title"), message: String(localized: "error_internal_message"), retryBlock: retryBlock) + case .convertImageToPNG: + UIAlertController.showWithTitle(String(localized: "error_title"), message: String(localized: "change_avatar_error_convert_image"), retryBlock: retryBlock) + case .changeAvatar: + let (title, message) = OCTSetUserAvatarError(rawValue: error!.code)!.strings() + UIAlertController.showWithTitle(title, message: message, retryBlock: retryBlock) + case .sendFileToFriend: + let (title, message) = OCTSendFileError(rawValue: error!.code)!.strings() + UIAlertController.showWithTitle(title, message: message, retryBlock: retryBlock) + case .acceptIncomingFile: + let (title, message) = OCTAcceptFileError(rawValue: error!.code)!.strings() + UIAlertController.showWithTitle(title, message: message, retryBlock: retryBlock) + case .cancelFileTransfer: + let (title, message) = OCTFileTransferError(rawValue: error!.code)!.strings() + UIAlertController.showWithTitle(title, message: message, retryBlock: retryBlock) + case .pauseFileTransfer: + let (title, message) = OCTFileTransferError(rawValue: error!.code)!.strings() + UIAlertController.showWithTitle(title, message: message, retryBlock: retryBlock) + case .pinLogOut: + UIAlertController.showWithTitle(String(localized: "error_title"), message: String(localized: "pin_logout_message"), retryBlock: retryBlock) + } +} + +extension OCTManagerInitError { + func strings() -> (title: String, message: String) { + switch self { + case .passphraseFailed: + return (String(localized: "error_wrong_password_title"), + String(localized: "error_wrong_password_message")) + case .cannotImportToxSave: + return (String(localized: "error_import_not_exist_title"), + String(localized: "error_import_not_exist_message")) + case .databaseKeyCannotCreateKey: + fallthrough + case .databaseKeyCannotReadKey: + fallthrough + case .databaseKeyMigrationToEncryptedFailed: + return (String(localized: "error_title"), + String(localized: "error_internal_message")) + case .toxFileDecryptNull: + fallthrough + case .databaseKeyDecryptNull: + return (String(localized: "error_decrypt_title"), + String(localized: "error_decrypt_empty_data_message")) + case .toxFileDecryptBadFormat: + fallthrough + case .databaseKeyDecryptBadFormat: + return (String(localized: "error_decrypt_title"), + String(localized: "error_decrypt_bad_format_message")) + case .toxFileDecryptFailed: + fallthrough + case .databaseKeyDecryptFailed: + return (String(localized: "error_decrypt_title"), + String(localized: "error_decrypt_wrong_password_message")) + case .createToxUnknown: + return (String(localized: "error_title"), + String(localized: "error_general_unknown_message")) + case .createToxMemoryError: + return (String(localized: "error_title"), + String(localized: "error_general_no_memory_message")) + case .createToxPortAlloc: + return (String(localized: "error_title"), + String(localized: "error_general_bind_port_message")) + case .createToxProxyBadType: + return (String(localized: "error_proxy_title"), + String(localized: "error_internal_message")) + case .createToxProxyBadHost: + return (String(localized: "error_proxy_title"), + String(localized: "error_proxy_invalid_address_message")) + case .createToxProxyBadPort: + return (String(localized: "error_proxy_title"), + String(localized: "error_proxy_invalid_port_message")) + case .createToxProxyNotFound: + return (String(localized: "error_proxy_title"), + String(localized: "error_proxy_host_not_resolved_message")) + case .createToxEncrypted: + return (String(localized: "error_title"), + String(localized: "error_general_profile_encrypted_message")) + case .createToxBadFormat: + return (String(localized: "error_title"), + String(localized: "error_general_bad_format_message")) + } + } +} + +extension OCTToxErrorSetInfoCode { + func nameStrings() -> (title: String, message: String) { + switch self { + case .unknow: + return (String(localized: "error_title"), + String(localized: "error_internal_message")) + case .tooLong: + return (String(localized: "error_title"), + String(localized: "error_name_too_long")) + } + } + + func statusMessageStrings() -> (title: String, message: String) { + switch self { + case .unknow: + return (String(localized: "error_title"), + String(localized: "error_internal_message")) + case .tooLong: + return (String(localized: "error_title"), + String(localized: "error_status_message_too_long")) + } + } +} + +extension OCTToxErrorFriendAdd { + func strings() -> (title: String, message: String) { + switch self { + case .tooLong: + return (String(localized: "error_title"), + String(localized: "error_contact_request_too_long")) + case .noMessage: + return (String(localized: "error_title"), + String(localized: "error_contact_request_no_message")) + case .ownKey: + return (String(localized: "error_title"), + String(localized: "error_contact_request_own_key")) + case .alreadySent: + return (String(localized: "error_title"), + String(localized: "error_contact_request_already_sent")) + case .badChecksum: + return (String(localized: "error_title"), + String(localized: "error_contact_request_bad_checksum")) + case .setNewNospam: + return (String(localized: "error_title"), + String(localized: "error_contact_request_new_nospam")) + case .malloc: + fallthrough + case .unknown: + return (String(localized: "error_title"), + String(localized: "error_internal_message")) + } + } +} + +extension OCTToxErrorFriendDelete { + func strings() -> (title: String, message: String) { + switch self { + case .notFound: + return (String(localized: "error_title"), + String(localized: "error_internal_message")) + } + } +} + +extension OCTToxAVErrorCall { + func strings() -> (title: String, message: String) { + switch self { + case .alreadyInCall: + return (String(localized: "error_title"), + String(localized: "call_error_already_in_call")) + case .friendNotConnected: + return (String(localized: "error_title"), + String(localized: "call_error_contact_is_offline")) + case .friendNotFound: + fallthrough + case .invalidBitRate: + fallthrough + case .malloc: + fallthrough + case .sync: + fallthrough + case .unknown: + return (String(localized: "error_title"), + String(localized: "error_internal_message")) + } + } +} + +extension OCTToxAVErrorAnswer { + func strings() -> (title: String, message: String) { + switch self { + case .friendNotCalling: + return (String(localized: "error_title"), + String(localized: "call_error_no_active_call")) + case .codecInitialization: + fallthrough + case .sync: + fallthrough + case .invalidBitRate: + fallthrough + case .unknown: + fallthrough + case .friendNotFound: + return (String(localized: "error_title"), + String(localized: "error_internal_message")) + } + } +} + +extension OCTSetUserAvatarError { + func strings() -> (title: String, message: String) { + switch self { + case .tooBig: + return (String(localized: "error_title"), + String(localized: "error_internal_message")) + } + } +} + +extension OCTSendFileError { + func strings() -> (title: String, message: String) { + switch self { + case .internalError: + fallthrough + case .cannotReadFile: + fallthrough + case .cannotSaveFileToUploads: + fallthrough + case .nameTooLong: + fallthrough + case .friendNotFound: + return (String(localized: "error_title"), + String(localized: "error_internal_message")) + case .friendNotConnected: + return (String(localized: "error_title"), + String(localized: "error_contact_not_connected")) + case .tooMany: + return (String(localized: "error_title"), + String(localized: "error_too_many_files")) + } + } +} + +extension OCTAcceptFileError { + func strings() -> (title: String, message: String) { + switch self { + case .internalError: + fallthrough + case .cannotWriteToFile: + fallthrough + case .friendNotFound: + fallthrough + case .wrongMessage: + return (String(localized: "error_title"), + String(localized: "error_internal_message")) + case .friendNotConnected: + return (String(localized: "error_title"), + String(localized: "error_contact_not_connected")) + } + } +} + +extension OCTFileTransferError { + func strings() -> (title: String, message: String) { + switch self { + case .wrongMessage: + return (String(localized: "error_title"), + String(localized: "error_internal_message")) + } + } +} diff --git a/Antidote/ExceptionHandling.h b/Antidote/ExceptionHandling.h new file mode 100644 index 0000000..721d2f9 --- /dev/null +++ b/Antidote/ExceptionHandling.h @@ -0,0 +1,11 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#import + +@interface ExceptionHandling : NSObject + ++ (void)tryWithBlock:(nonnull void (^)(void))tryBlock catch:(nonnull void (^)(NSException *__nonnull exception))catchBlock; + +@end diff --git a/Antidote/ExceptionHandling.m b/Antidote/ExceptionHandling.m new file mode 100644 index 0000000..3782afd --- /dev/null +++ b/Antidote/ExceptionHandling.m @@ -0,0 +1,19 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#import "ExceptionHandling.h" + +@implementation ExceptionHandling + ++ (void)tryWithBlock:(nonnull void (^)(void))tryBlock catch:(nonnull void (^)(NSException *exception))catchBlock +{ + @try { + tryBlock(); + } + @catch (NSException *exception) { + catchBlock(exception); + } +} + +@end diff --git a/Antidote/ExtendedTextField.swift b/Antidote/ExtendedTextField.swift new file mode 100644 index 0000000..e4841b5 --- /dev/null +++ b/Antidote/ExtendedTextField.swift @@ -0,0 +1,224 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit +import SnapKit + +private struct Constants { + static let TextFieldHeight = 40.0 + static let VerticalOffset = 5.0 +} + +protocol ExtendedTextFieldDelegate: class { + func loginExtendedTextFieldReturnKeyPressed(_ field: ExtendedTextField) +} + +class ExtendedTextField: UIView { + enum FieldType { + case login + case normal + } + + weak var delegate: ExtendedTextFieldDelegate? + + var maxTextUTF8Length: Int = Int.max + + var title: String? { + get { + return titleLabel.text + } + set { + titleLabel.text = newValue + } + } + + var placeholder: String? { + get { + return textField.placeholder + } + set { + textField.placeholder = newValue + } + } + + var text: String? { + get { + return textField.text + } + set { + textField.text = newValue + } + } + + var hint: String? { + get { + return hintLabel.text + } + set { + hintLabel.text = newValue + } + } + + var secureTextEntry: Bool { + get { + return textField.isSecureTextEntry + } + set { + textField.isSecureTextEntry = newValue + } + } + + var returnKeyType: UIReturnKeyType { + get { + return textField.returnKeyType + } + set { + textField.returnKeyType = newValue + } + } + + fileprivate var titleLabel: UILabel! + fileprivate var textField: UITextField! + fileprivate var hintLabel: UILabel! + + init(theme: Theme, type: FieldType) { + super.init(frame: CGRect.zero) + + createViews(theme: theme, type: type) + installConstraints() + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + override func becomeFirstResponder() -> Bool { + return textField.becomeFirstResponder() + } +} + +extension ExtendedTextField: UITextFieldDelegate { + func textFieldShouldReturn(_ textField: UITextField) -> Bool { + delegate?.loginExtendedTextFieldReturnKeyPressed(self) + return false + } + + func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { + let resultText = (textField.text! as NSString).replacingCharacters(in: range, with: string) + + if resultText.lengthOfBytes(using: String.Encoding.utf8) <= maxTextUTF8Length { + return true + } + + textField.text = resultText.substringToByteLength(maxTextUTF8Length, encoding: String.Encoding.utf8) + return false + } +} + +// Accessibility +extension ExtendedTextField { + override var isAccessibilityElement: Bool { + get { + return true + } + set {} + } + + override var accessibilityLabel: String? { + get { + return placeholder ?? title + } + set {} + } + + override var accessibilityHint: String? { + get { + var result: String? + + if placeholder != nil { + // If there is a placeholder also read title as part of the hint. + result = title + } + + switch (result, hint) { + case (.none, _): + return hint + case (.some, .none): + return result + case (.some(let r), .some(let s)): + return "\(r), \(s)" + } + } + set {} + } + + override var accessibilityValue: String? { + get { + return text + } + set {} + } + + override var accessibilityTraits: UIAccessibilityTraits { + get { + return textField.accessibilityTraits + } + set {} + } +} + +private extension ExtendedTextField { + func createViews(theme: Theme, type: FieldType) { + textField = UITextField() + textField.delegate = self + textField.borderStyle = .roundedRect + textField.autocapitalizationType = .sentences + textField.enablesReturnKeyAutomatically = true + addSubview(textField) + + let textColor: UIColor + + switch type { + case .login: + textColor = theme.colorForType(.NormalText) + + textField.layer.borderColor = theme.colorForType(.LoginButtonBackground).cgColor + textField.layer.borderWidth = 0.5 + textField.layer.masksToBounds = true + textField.layer.cornerRadius = 6.0 + case .normal: + textColor = theme.colorForType(.NormalText) + } + + titleLabel = UILabel() + titleLabel.textColor = textColor + titleLabel.font = UIFont.systemFont(ofSize: 18.0) + titleLabel.backgroundColor = .clear + addSubview(titleLabel) + + hintLabel = UILabel() + hintLabel.textColor = textColor + hintLabel.font = UIFont.antidoteFontWithSize(14.0, weight: .light) + hintLabel.numberOfLines = 0 + hintLabel.backgroundColor = .clear + addSubview(hintLabel) + } + + func installConstraints() { + titleLabel.snp.makeConstraints { + $0.top.leading.trailing.equalTo(self) + } + + textField.snp.makeConstraints { + $0.top.equalTo(titleLabel.snp.bottom).offset(Constants.VerticalOffset) + $0.leading.trailing.equalTo(self) + $0.height.equalTo(Constants.TextFieldHeight) + } + + hintLabel.snp.makeConstraints { + $0.top.equalTo(textField.snp.bottom).offset(Constants.VerticalOffset) + $0.leading.trailing.equalTo(self) + $0.bottom.equalTo(self) + } + } +} diff --git a/Antidote/FAQController.swift b/Antidote/FAQController.swift new file mode 100644 index 0000000..a4f2840 --- /dev/null +++ b/Antidote/FAQController.swift @@ -0,0 +1,79 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation +import WebKit +import SnapKit + +private struct Constants { + static let FAQURL = "https://github.com/Zoxcore/Antidote/blob/develop/FAQ/en.md" +} + +class FAQController: UIViewController { + fileprivate let theme: Theme + + fileprivate var webView: WKWebView! + fileprivate var spinner: UIActivityIndicatorView! + + init(theme: Theme) { + self.theme = theme + + super.init(nibName: nil, bundle: nil) + + hidesBottomBarWhenPushed = true + title = String(localized: "settings_faq") + } + + required convenience init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func loadView() { + loadViewWithBackgroundColor(theme.colorForType(.NormalBackground)) + + createViews() + installConstraints() + } + + override func viewDidLoad() { + super.viewDidLoad() + + let request = URLRequest(url: URL(string: Constants.FAQURL)!) + webView.load(request) + } +} + +extension FAQController: WKNavigationDelegate { + func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) { + spinner.startAnimating() + } + + func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { + spinner.stopAnimating() + } +} + +private extension FAQController { + func createViews() { + let configuration = WKWebViewConfiguration() + + webView = WKWebView(frame: CGRect.zero, configuration: configuration) + webView.navigationDelegate = self + view.addSubview(webView) + + spinner = UIActivityIndicatorView(activityIndicatorStyle: .gray) + spinner.hidesWhenStopped = true + view.addSubview(spinner) + } + + func installConstraints() { + webView.snp.makeConstraints { + $0.edges.equalTo(view) + } + + spinner.snp.makeConstraints { + $0.center.equalTo(view) + } + } +} diff --git a/Antidote/FilePreviewControllerDataSource.swift b/Antidote/FilePreviewControllerDataSource.swift new file mode 100644 index 0000000..2836d9e --- /dev/null +++ b/Antidote/FilePreviewControllerDataSource.swift @@ -0,0 +1,71 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation +import QuickLook + +private class FilePreviewItem: NSObject, QLPreviewItem { + @objc var previewItemURL: URL? + @objc var previewItemTitle: String? + + init(url: URL, title: String?) { + self.previewItemURL = url + self.previewItemTitle = title + } +} + +class FilePreviewControllerDataSource: NSObject , QuickLookPreviewControllerDataSource { + weak var previewController: QuickLookPreviewController? + + let messages: Results + var messagesToken: RLMNotificationToken? + + init(chat: OCTChat, submanagerObjects: OCTSubmanagerObjects) { + let predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [ + NSPredicate(format: "chatUniqueIdentifier == %@ AND messageFile != nil", chat.uniqueIdentifier), + + NSCompoundPredicate(orPredicateWithSubpredicates: [ + NSPredicate(format: "messageFile.fileType == \(OCTMessageFileType.ready.rawValue)"), + NSPredicate(format: "senderUniqueIdentifier == nil AND messageFile.fileType == \(OCTMessageFileType.canceled.rawValue)"), + ]), + ]) + + self.messages = submanagerObjects.messages(predicate: predicate).sortedResultsUsingProperty("dateInterval", ascending: true) + + super.init() + + messagesToken = messages.addNotificationBlock { [unowned self] change in + switch change { + case .initial: + break + case .update: + self.previewController?.reloadData() + case .error(let error): + fatalError("\(error)") + } + } + } + + deinit { + messagesToken?.invalidate() + } + + func indexOfMessage(_ message: OCTMessageAbstract) -> Int? { + return messages.indexOfObject(message) + } +} + +extension FilePreviewControllerDataSource: QLPreviewControllerDataSource { + func numberOfPreviewItems(in controller: QLPreviewController) -> Int { + return messages.count + } + + func previewController(_ controller: QLPreviewController, previewItemAt index: Int) -> QLPreviewItem { + let message = messages[index] + + let url = URL(fileURLWithPath: message.messageFile!.filePath()!) + + return FilePreviewItem(url: url, title: message.messageFile!.fileName) + } +} diff --git a/Antidote/FriendCardController.swift b/Antidote/FriendCardController.swift new file mode 100644 index 0000000..203e06f --- /dev/null +++ b/Antidote/FriendCardController.swift @@ -0,0 +1,186 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit + +protocol FriendCardControllerDelegate: class { + func friendCardControllerChangeNickname(_ controller: FriendCardController, forFriend friend: OCTFriend) + func friendCardControllerOpenChat(_ controller: FriendCardController, forFriend friend: OCTFriend) + func friendCardControllerCall(_ controller: FriendCardController, toFriend friend: OCTFriend) + func friendCardControllerVideoCall(_ controller: FriendCardController, toFriend friend: OCTFriend) +} + +class FriendCardController: StaticTableController { + weak var delegate: FriendCardControllerDelegate? + + fileprivate weak var submanagerObjects: OCTSubmanagerObjects! + + fileprivate let friend: OCTFriend + + fileprivate let avatarManager: AvatarManager + fileprivate var friendToken: RLMNotificationToken? + + fileprivate let avatarModel: StaticTableAvatarCellModel + fileprivate let chatButtonsModel: StaticTableChatButtonsCellModel + fileprivate let nicknameModel: StaticTableDefaultCellModel + fileprivate let nameModel: StaticTableDefaultCellModel + fileprivate let statusMessageModel: StaticTableDefaultCellModel + fileprivate let publicKeyModel: StaticTableDefaultCellModel + fileprivate let capabilitiesModel: StaticTableDefaultCellModel + fileprivate let pushurlModel: StaticTableDefaultCellModel + + init(theme: Theme, friend: OCTFriend, submanagerObjects: OCTSubmanagerObjects) { + self.submanagerObjects = submanagerObjects + self.friend = friend + + self.avatarManager = AvatarManager(theme: theme) + + avatarModel = StaticTableAvatarCellModel() + chatButtonsModel = StaticTableChatButtonsCellModel() + nicknameModel = StaticTableDefaultCellModel() + nameModel = StaticTableDefaultCellModel() + statusMessageModel = StaticTableDefaultCellModel() + publicKeyModel = StaticTableDefaultCellModel() + capabilitiesModel = StaticTableDefaultCellModel() + pushurlModel = StaticTableDefaultCellModel() + + super.init(theme: theme, style: .plain, model: [ + [ + avatarModel, + chatButtonsModel, + ], + [ + nicknameModel, + nameModel, + statusMessageModel, + ], + [ + publicKeyModel, + ], + [ + capabilitiesModel, + ], + [ + pushurlModel, + ], + ]) + + updateModels() + } + + deinit { + friendToken?.invalidate() + } + + required convenience init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { + super.viewDidLoad() + + let predicate = NSPredicate(format: "uniqueIdentifier == %@", friend.uniqueIdentifier) + let results = submanagerObjects.friends(predicate: predicate) + friendToken = results.addNotificationBlock { [unowned self] change in + switch change { + case .initial: + break + case .update: + self.updateModels() + self.reloadTableView() + case .error(let error): + fatalError("\(error)") + } + } + } +} + +private extension FriendCardController { + func updateModels() { + title = friend.nickname + + if let data = friend.avatarData { + avatarModel.avatar = UIImage(data: data) + } + else { + avatarModel.avatar = avatarManager.avatarFromString( + friend.nickname, + diameter: StaticTableAvatarCellModel.Constants.AvatarImageSize) + } + avatarModel.userInteractionEnabled = false + + chatButtonsModel.chatButtonHandler = { [unowned self] in + self.delegate?.friendCardControllerOpenChat(self, forFriend: self.friend) + } + chatButtonsModel.callButtonHandler = { [unowned self] in + self.delegate?.friendCardControllerCall(self, toFriend: self.friend) + } + chatButtonsModel.videoButtonHandler = { [unowned self] in + self.delegate?.friendCardControllerVideoCall(self, toFriend: self.friend) + } + chatButtonsModel.chatButtonEnabled = true + chatButtonsModel.callButtonEnabled = friend.isConnected + chatButtonsModel.videoButtonEnabled = friend.isConnected + + nicknameModel.title = String(localized: "nickname") + nicknameModel.value = friend.nickname + nicknameModel.rightImageType = .arrow + nicknameModel.didSelectHandler = { [unowned self] _ -> Void in + self.delegate?.friendCardControllerChangeNickname(self, forFriend: self.friend) + } + + nameModel.title = String(localized: "name") + nameModel.value = friend.name + nameModel.userInteractionEnabled = false + + statusMessageModel.title = String(localized: "status_message") + statusMessageModel.value = friend.statusMessage + statusMessageModel.userInteractionEnabled = false + + publicKeyModel.title = String(localized: "public_key") + publicKeyModel.value = friend.publicKey + publicKeyModel.userInteractionEnabled = false + publicKeyModel.canCopyValue = true + + capabilitiesModel.title = "Tox Capabilities" + let capabilities = friend.capabilities2 ?? "" + if (capabilities.count > 0) { + let caps = NSNumber(value: UInt64(capabilities) ?? 0) + capabilitiesModel.value = capabilitiesToString(caps) + } else { + capabilitiesModel.value = "BASIC" + } + capabilitiesModel.userInteractionEnabled = false + + pushurlModel.title = "Push URL" + let pushtoken = friend.pushToken ?? "" + if (pushtoken.count > 0) { + pushurlModel.value = pushtoken + } else { + pushurlModel.value = "" + } + pushurlModel.userInteractionEnabled = false + } + + func capabilitiesToString(_ cap: NSNumber) -> String { + var ret: String = "BASIC" + if ((UInt(cap) & 1) > 0) { + ret = ret + " CAPABILITIES" + } + if ((UInt(cap) & 2) > 0) { + ret = ret + " MSGV2" + } + if ((UInt(cap) & 4) > 0) { + ret = ret + " H264" + } + if ((UInt(cap) & 8) > 0) { + ret = ret + " MSGV3" + } + if ((UInt(cap) & 16) > 0) { + ret = ret + " FTV2" + } + return ret; + } + +} diff --git a/Antidote/FriendListCell.swift b/Antidote/FriendListCell.swift new file mode 100644 index 0000000..d8ff9c9 --- /dev/null +++ b/Antidote/FriendListCell.swift @@ -0,0 +1,121 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit +import SnapKit + +class FriendListCell: BaseCell { + struct Constants { + static let AvatarSize = 30.0 + static let AvatarLeftOffset = 10.0 + static let AvatarRightOffset = 16.0 + + static let TopLabelHeight = 22.0 + static let MinimumBottomLabelHeight = 15.0 + + static let VerticalOffset = 3.0 + } + + fileprivate var avatarView: ImageViewWithStatus! + fileprivate var topLabel: UILabel! + fileprivate var bottomLabel: UILabel! + fileprivate var arrowImageView: UIImageView! + + override func setupWithTheme(_ theme: Theme, model: BaseCellModel) { + super.setupWithTheme(theme, model: model) + + guard let friendModel = model as? FriendListCellModel else { + assert(false, "Wrong model \(model) passed to cell \(self)") + return + } + + separatorInset.left = CGFloat(Constants.AvatarLeftOffset + Constants.AvatarSize + Constants.AvatarRightOffset) + + avatarView.imageView.image = friendModel.avatar + avatarView.userStatusView.theme = theme + avatarView.userStatusView.userStatus = friendModel.status + avatarView.userStatusView.connectionStatus = friendModel.connectionstatus + avatarView.userStatusView.isHidden = friendModel.hideStatus + + topLabel.text = friendModel.topText + topLabel.textColor = theme.colorForType(.NormalText) + + bottomLabel.text = friendModel.bottomText + bottomLabel.textColor = theme.colorForType(.FriendCellStatus) + bottomLabel.numberOfLines = friendModel.multilineBottomtext ? 0 : 1 + + accessibilityLabel = friendModel.accessibilityLabel + accessibilityValue = friendModel.accessibilityValue + } + + override func createViews() { + super.createViews() + + avatarView = ImageViewWithStatus() + contentView.addSubview(avatarView) + + topLabel = UILabel() + topLabel.font = UIFont.systemFont(ofSize: 18.0) + contentView.addSubview(topLabel) + + bottomLabel = UILabel() + bottomLabel.font = UIFont.antidoteFontWithSize(12.0, weight: .light) + contentView.addSubview(bottomLabel) + + let image = UIImage(named: "right-arrow")!.flippedToCorrectLayout() + arrowImageView = UIImageView(image: image) + arrowImageView.setContentCompressionResistancePriority(UILayoutPriority.required, for: .horizontal) + contentView.addSubview(arrowImageView) + } + + override func installConstraints() { + super.installConstraints() + + avatarView.snp.makeConstraints { + $0.leading.equalTo(contentView).offset(Constants.AvatarLeftOffset) + $0.centerY.equalTo(contentView) + $0.size.equalTo(Constants.AvatarSize) + } + + topLabel.snp.makeConstraints { + $0.leading.equalTo(avatarView.snp.trailing).offset(Constants.AvatarRightOffset) + $0.top.equalTo(contentView).offset(Constants.VerticalOffset) + $0.height.equalTo(Constants.TopLabelHeight) + } + + bottomLabel.snp.makeConstraints { + $0.leading.trailing.equalTo(topLabel) + $0.top.equalTo(topLabel.snp.bottom) + $0.bottom.equalTo(contentView).offset(-Constants.VerticalOffset) + $0.height.greaterThanOrEqualTo(Constants.MinimumBottomLabelHeight) + } + + arrowImageView.snp.makeConstraints { + $0.centerY.equalTo(contentView) + $0.leading.greaterThanOrEqualTo(topLabel.snp.trailing) + $0.trailing.equalTo(contentView) + } + } +} + +// Accessibility +extension FriendListCell { + override var isAccessibilityElement: Bool { + get { + return true + } + set {} + } + + // Label and value are set in setupWithTheme:model: method + // var accessibilityLabel: String? + // var accessibilityValue: String? + + override var accessibilityTraits: UIAccessibilityTraits { + get { + return UIAccessibilityTraitButton + } + set {} + } +} diff --git a/Antidote/FriendListCellModel.swift b/Antidote/FriendListCellModel.swift new file mode 100644 index 0000000..faf40d9 --- /dev/null +++ b/Antidote/FriendListCellModel.swift @@ -0,0 +1,20 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +class FriendListCellModel: BaseCellModel { + var avatar: UIImage? + + var topText: String = "" + var bottomText: String = "" + var multilineBottomtext: Bool = false + + var accessibilityLabel = "" + var accessibilityValue = "" + + var status: UserStatus = .offline + var connectionstatus: ConnectionStatus = .none + var hideStatus: Bool = false +} diff --git a/Antidote/FriendListController.swift b/Antidote/FriendListController.swift new file mode 100644 index 0000000..cdfb26c --- /dev/null +++ b/Antidote/FriendListController.swift @@ -0,0 +1,315 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit +import SnapKit + +protocol FriendListControllerDelegate: class { + func friendListController(_ controller: FriendListController, didSelectFriend friend: OCTFriend) + func friendListController(_ controller: FriendListController, didSelectRequest request: OCTFriendRequest) + func friendListControllerAddFriend(_ controller: FriendListController) + func friendListController(_ controller: FriendListController, showQRCodeWithText text: String) +} + +class FriendListController: UIViewController { + weak var delegate: FriendListControllerDelegate? + + fileprivate let theme: Theme + + fileprivate var dataSource: FriendListDataSource! + + fileprivate weak var submanagerObjects: OCTSubmanagerObjects! + fileprivate weak var submanagerFriends: OCTSubmanagerFriends! + fileprivate weak var submanagerChats: OCTSubmanagerChats! + fileprivate weak var submanagerUser: OCTSubmanagerUser! + + fileprivate var placeholderView: UITextView! + fileprivate var tableView: UITableView! + + init(theme: Theme, submanagerObjects: OCTSubmanagerObjects, submanagerFriends: OCTSubmanagerFriends, submanagerChats: OCTSubmanagerChats, submanagerUser: OCTSubmanagerUser) { + self.theme = theme + + self.submanagerObjects = submanagerObjects + self.submanagerFriends = submanagerFriends + self.submanagerChats = submanagerChats + self.submanagerUser = submanagerUser + + super.init(nibName: nil, bundle: nil) + + addNavigationButtons() + + edgesForExtendedLayout = UIRectEdge() + title = String(localized: "contacts_title") + } + + required convenience init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func loadView() { + loadViewWithBackgroundColor(theme.colorForType(.NormalBackground)) + + createTableView() + createPlaceholderView() + installConstraints() + } + + override func viewDidLoad() { + super.viewDidLoad() + + let friends = submanagerObjects.friends() + let requests = submanagerObjects.friendRequests() + dataSource = FriendListDataSource(theme: theme, friends: friends, requests: requests) + dataSource.delegate = self + + // removing separators on empty lines + tableView.tableFooterView = UIView() + + updateViewsVisibility() + + let message = "Antidote is Tox" + let echobotid = "76518406F6A9F2217E8DC487CC783C25CC16A15EB36FF32E335A235342C48A39218F515C39A6" + + print("EchobotAdded=\(UserDefaultsManager().EchobotAdded)") + + if (UserDefaultsManager().EchobotAdded == false) { + do { + try self.submanagerFriends.sendFriendRequest(toAddress: echobotid, message: message) + UserDefaultsManager().EchobotAdded = true + } + catch let error as NSError { + return + } + } + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + updateViewsVisibility() + } + + override func setEditing(_ editing: Bool, animated: Bool) { + super.setEditing(editing, animated: animated) + + tableView.setEditing(editing, animated: animated) + } +} + +extension FriendListController { + @objc func addFriendButtonPressed() { + delegate?.friendListControllerAddFriend(self) + } +} + +extension FriendListController: FriendListDataSourceDelegate { + func friendListDataSourceBeginUpdates() { + tableView.beginUpdates() + } + + func friendListDataSourceEndUpdates() { + tableView.endUpdates() + updateViewsVisibility() + } + + func friendListDataSourceInsertRowsAtIndexPaths(_ indexPaths: [IndexPath]) { + tableView.insertRows(at: indexPaths, with: .automatic) + } + + func friendListDataSourceDeleteRowsAtIndexPaths(_ indexPaths: [IndexPath]) { + tableView.deleteRows(at: indexPaths, with: .automatic) + } + + func friendListDataSourceReloadRowsAtIndexPaths(_ indexPaths: [IndexPath]) { + tableView.reloadRows(at: indexPaths, with: .automatic) + } + + func friendListDataSourceInsertSections(_ sections: IndexSet) { + tableView.insertSections(sections, with: .automatic) + } + + func friendListDataSourceDeleteSections(_ sections: IndexSet) { + tableView.deleteSections(sections, with: .automatic) + } + + func friendListDataSourceReloadSections(_ sections: IndexSet) { + tableView.reloadSections(sections, with: .automatic) + } + + func friendListDataSourceReloadTable() { + tableView.reloadData() + } +} + +extension FriendListController: UITableViewDataSource { + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: FriendListCell.staticReuseIdentifier) as! FriendListCell + let model = dataSource.modelAtIndexPath(indexPath) + + cell.setupWithTheme(theme, model: model) + + return cell + } + + func numberOfSections(in tableView: UITableView) -> Int { + return dataSource.numberOfSections() + } + + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return dataSource.numberOfRowsInSection(section) + } + + func sectionIndexTitles(for tableView: UITableView) -> [String]? { + return dataSource.sectionIndexTitles() + } + + func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { + return dataSource.titleForHeaderInSection(section) + } + + func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) { + if editingStyle == .delete { + let title: String + + switch dataSource.objectAtIndexPath(indexPath) { + case .request: + title = String(localized:"delete_contact_request_title") + case .friend: + title = String(localized:"delete_contact_title") + } + + let alert = UIAlertController(title: title, message: nil, preferredStyle: .alert) + + alert.addAction(UIAlertAction(title: String(localized: "alert_cancel"), style: .default, handler: nil)) + alert.addAction(UIAlertAction(title: String(localized: "alert_delete"), style: .destructive) { [unowned self] _ -> Void in + switch self.dataSource.objectAtIndexPath(indexPath) { + case .request(let request): + self.submanagerFriends.remove(request) + case .friend(let friend): + do { + let chat = self.submanagerChats.getOrCreateChat(with: friend) + + try self.submanagerFriends.remove(friend) + + self.submanagerChats.removeAllMessages(in: chat, removeChat: true) + } + catch let error as NSError { + handleErrorWithType(.removeFriend, error: error) + } + } + }) + + present(alert, animated: true, completion: nil) + } + } +} + +extension FriendListController: UITableViewDelegate { + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + tableView.deselectRow(at: indexPath, animated: true) + + switch dataSource.objectAtIndexPath(indexPath) { + case .request(let request): + didSelectFriendRequest(request) + case .friend(let friend): + delegate?.friendListController(self, didSelectFriend: friend) + } + } +} + +extension FriendListController : UITextViewDelegate { + func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange) -> Bool { + if textView === placeholderView { + let toxId = submanagerUser.userAddress + let alert = UIAlertController(title: String(localized: "my_tox_id"), message: toxId, preferredStyle: .alert) + + alert.addAction(UIAlertAction(title: String(localized: "copy"), style: .default) { _ -> Void in + UIPasteboard.general.string = toxId + }) + + alert.addAction(UIAlertAction(title: String(localized: "show_qr_code"), style: .default) { [weak self] _ -> Void in + self?.delegate?.friendListController(self!, showQRCodeWithText: toxId) + }) + + alert.addAction(UIAlertAction(title: String(localized: "alert_cancel"), style: .cancel, handler: nil)) + + present(alert, animated: true, completion: nil) + } + + return false + } +} + +private extension FriendListController { + func addNavigationButtons() { + navigationItem.rightBarButtonItem = UIBarButtonItem( + barButtonSystemItem: .add, + target: self, + action: #selector(FriendListController.addFriendButtonPressed)) + } + + func updateViewsVisibility() { + var isEmpty = true + + for section in 0.. 0 { + isEmpty = false + break + } + } + + navigationItem.leftBarButtonItem = isEmpty ? nil : editButtonItem + placeholderView.isHidden = !isEmpty + } + + func createTableView() { + tableView = UITableView() + tableView.estimatedRowHeight = 44.0 + tableView.dataSource = self + tableView.delegate = self + tableView.backgroundColor = theme.colorForType(.NormalBackground) + tableView.sectionIndexColor = theme.colorForType(.LinkText) + + view.addSubview(tableView) + + tableView.register(FriendListCell.self, forCellReuseIdentifier: FriendListCell.staticReuseIdentifier) + } + + func createPlaceholderView() { + let top = String(localized: "contact_no_contacts_add_contact") + let bottom = String(localized: "contact_no_contacts_share_tox_id") + + let text = NSMutableAttributedString(string: "\(top)\(bottom)") + let linkRange = NSRange(location: top.count, length: bottom.count) + let fullRange = NSRange(location: 0, length: text.length) + + text.addAttribute(NSAttributedStringKey.foregroundColor, value: theme.colorForType(.EmptyScreenPlaceholderText), range: fullRange) + text.addAttribute(NSAttributedStringKey.font, value: UIFont.antidoteFontWithSize(26.0, weight: .light), range: fullRange) + text.addAttribute(NSAttributedStringKey.link, value: "", range: linkRange) + + placeholderView = UITextView() + placeholderView.delegate = self + placeholderView.attributedText = text + placeholderView.isEditable = false + placeholderView.isScrollEnabled = false + placeholderView.textAlignment = .center + placeholderView.linkTextAttributes = [NSAttributedStringKey.foregroundColor.rawValue : theme.colorForType(.LinkText)] + view.addSubview(placeholderView) + } + + func installConstraints() { + tableView.snp.makeConstraints { + $0.edges.equalTo(view) + } + + placeholderView.snp.makeConstraints { + $0.center.equalTo(view) + $0.size.equalTo(placeholderView.sizeThatFits(CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude))) + } + } + + func didSelectFriendRequest(_ request: OCTFriendRequest) { + delegate?.friendListController(self, didSelectRequest: request) + } +} diff --git a/Antidote/FriendListDataSource.swift b/Antidote/FriendListDataSource.swift new file mode 100644 index 0000000..4796ce6 --- /dev/null +++ b/Antidote/FriendListDataSource.swift @@ -0,0 +1,230 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +private struct Constants { + static let FriendRequestsSection = 0 +} + +protocol FriendListDataSourceDelegate: class { + func friendListDataSourceBeginUpdates() + func friendListDataSourceEndUpdates() + + func friendListDataSourceInsertRowsAtIndexPaths(_ indexPaths: [IndexPath]) + func friendListDataSourceDeleteRowsAtIndexPaths(_ indexPaths: [IndexPath]) + func friendListDataSourceReloadRowsAtIndexPaths(_ indexPaths: [IndexPath]) + + func friendListDataSourceInsertSections(_ sections: IndexSet) + func friendListDataSourceDeleteSections(_ sections: IndexSet) + func friendListDataSourceReloadSections(_ sections: IndexSet) + + func friendListDataSourceReloadTable() +} + +enum FriendListObject { + case request(OCTFriendRequest) + case friend(OCTFriend) +} + +class FriendListDataSource: NSObject { + weak var delegate: FriendListDataSourceDelegate? + + fileprivate let avatarManager: AvatarManager + fileprivate let dateFormatter: DateFormatter + + fileprivate let requests: Results? + fileprivate let friends: Results + + fileprivate var requestsToken: RLMNotificationToken? + fileprivate var friendsToken: RLMNotificationToken? + + /// In case if requests is nil friend requests won't be shown. + init(theme: Theme, friends: Results, requests: Results? = nil) { + self.avatarManager = AvatarManager(theme: theme) + self.dateFormatter = DateFormatter(type: .relativeDateAndTime) + + self.requests = requests + self.friends = friends + + super.init() + + addNotificationBlocks() + } + + deinit { + requestsToken?.invalidate() + friendsToken?.invalidate() + } + + func numberOfSections() -> Int { + if isRequestsSectionVisible() { + return 2 + } + + // friends only + return 1 + } + + func numberOfRowsInSection(_ section: Int) -> Int { + if section == Constants.FriendRequestsSection && isRequestsSectionVisible() { + return requests!.count + } + else { + return friends.count + } + } + + func modelAtIndexPath(_ indexPath: IndexPath) -> FriendListCellModel { + let model = FriendListCellModel() + + switch objectAtIndexPath(indexPath) { + case .request(let request): + model.avatar = avatarManager.avatarFromString("", diameter: CGFloat(FriendListCell.Constants.AvatarSize)) + model.topText = request.publicKey + model.bottomText = request.message ?? "" + model.multilineBottomtext = true + model.hideStatus = true + + model.accessibilityLabel = String(localized: "contact_request") + model.accessibilityValue = "" + + if let message = request.message { + model.accessibilityValue += String(localized: "add_contact_default_message_title") + ": " + message + ", " + } + model.accessibilityValue += String(localized: "public_key") + ": " + request.publicKey + + case .friend(let friend): + if let data = friend.avatarData { + model.avatar = UIImage(data: data) + } + else { + model.avatar = avatarManager.avatarFromString(friend.nickname, diameter: CGFloat(FriendListCell.Constants.AvatarSize)) + } + model.topText = friend.nickname + + model.status = UserStatus(connectionStatus: friend.connectionStatus, userStatus: friend.status) + model.connectionstatus = ConnectionStatus(connectionStatus: friend.connectionStatus) + + model.accessibilityLabel = friend.nickname + model.accessibilityValue = model.status.toString() + + if friend.isConnected { + model.bottomText = friend.statusMessage ?? "" + model.accessibilityValue += ", Status: \(model.bottomText)" + } + else if let date = friend.lastSeenOnline() { + model.bottomText = String(localized: "contact_last_seen", dateFormatter.string(from: date)) + model.accessibilityValue += ", " + model.bottomText + } + } + + return model + } + + func objectAtIndexPath(_ indexPath: IndexPath) -> FriendListObject { + if indexPath.section == Constants.FriendRequestsSection && isRequestsSectionVisible() { + return .request(requests![indexPath.row]) + } + else { + return .friend(friends[indexPath.row]) + } + } + + func sectionIndexTitles() -> [String] { + // TODO fix when Realm will support sections + let array = [String]() + return array + } + + func titleForHeaderInSection(_ section: Int) -> String? { + if !isRequestsSectionVisible() { + return nil + } + + if section == Constants.FriendRequestsSection { + return String(localized: "contact_requests_section") + } + else { + return String(localized: "contacts_title") + } + } +} + +private extension FriendListDataSource { + func addNotificationBlocks() { + requestsToken = requests?.addNotificationBlock { [unowned self] change in + switch change { + case .initial: + break + case .update(let requests, let deletions, let insertions, let modifications): + guard let requests = requests else { + return + } + + if deletions.count > 0 { + // reloading data on request removal/friend insertion to synchronize requests/friends + self.delegate?.friendListDataSourceReloadTable() + return + } + + self.delegate?.friendListDataSourceBeginUpdates() + + let countAfter = requests.count + let countBefore = countAfter - insertions.count + deletions.count + + if countBefore == 0 && countAfter > 0 { + self.delegate?.friendListDataSourceInsertSections(IndexSet(integer: 0)) + } + else if countBefore > 0 && countAfter == 0 { + self.delegate?.friendListDataSourceDeleteSections(IndexSet(integer: 0)) + } + else { + self.delegate?.friendListDataSourceDeleteRowsAtIndexPaths(deletions.map { IndexPath(row: $0, section: 0)} ) + self.delegate?.friendListDataSourceInsertRowsAtIndexPaths(insertions.map { IndexPath(row: $0, section: 0)} ) + self.delegate?.friendListDataSourceReloadRowsAtIndexPaths(modifications.map { IndexPath(row: $0, section: 0)} ) + } + + self.delegate?.friendListDataSourceEndUpdates() + case .error(let error): + fatalError("\(error)") + } + } + + friendsToken = friends.addNotificationBlock { [unowned self] change in + switch change { + case .initial: + break + case .update(_, let deletions, let insertions, let modifications): + if insertions.count > 0 { + // reloading data on request removal/friend insertion to synchronize requests/friends + self.delegate?.friendListDataSourceReloadTable() + return + } + + let section = self.isRequestsSectionVisible() ? 1 : 0 + + let deletions = deletions.map { IndexPath(row: $0, section: section) } + let insertions = insertions.map { IndexPath(row: $0, section: section) } + let modifications = modifications.map { IndexPath(row: $0, section: section) } + + self.delegate?.friendListDataSourceBeginUpdates() + self.delegate?.friendListDataSourceDeleteRowsAtIndexPaths(deletions) + self.delegate?.friendListDataSourceInsertRowsAtIndexPaths(insertions) + self.delegate?.friendListDataSourceReloadRowsAtIndexPaths(modifications) + self.delegate?.friendListDataSourceEndUpdates() + case .error(let error): + fatalError("\(error)") + } + } + } + + func isRequestsSectionVisible() -> Bool { + guard let requests = requests else { + return false + } + + return requests.count > 0 + } +} diff --git a/Antidote/FriendRequestController.swift b/Antidote/FriendRequestController.swift new file mode 100644 index 0000000..1053904 --- /dev/null +++ b/Antidote/FriendRequestController.swift @@ -0,0 +1,90 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit + +protocol FriendRequestControllerDelegate: class { + func friendRequestControllerDidFinish(_ controller: FriendRequestController) +} + +class FriendRequestController: StaticTableController { + weak var delegate: FriendRequestControllerDelegate? + + fileprivate let request: OCTFriendRequest + + fileprivate weak var submanagerFriends: OCTSubmanagerFriends! + + fileprivate let publicKeyModel: StaticTableDefaultCellModel + fileprivate let messageModel: StaticTableDefaultCellModel + fileprivate let buttonsModel: StaticTableMultiChoiceButtonCellModel + + init(theme: Theme, request: OCTFriendRequest, submanagerFriends: OCTSubmanagerFriends) { + self.request = request + + self.submanagerFriends = submanagerFriends + + publicKeyModel = StaticTableDefaultCellModel() + messageModel = StaticTableDefaultCellModel() + buttonsModel = StaticTableMultiChoiceButtonCellModel() + + super.init(theme: theme, style: .plain, model: [ + [ + publicKeyModel, + messageModel, + ], + [ + buttonsModel, + ], + ]) + + updateModels() + } + + required convenience init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +private extension FriendRequestController { + func updateModels() { + title = String(localized: "contact_request") + + publicKeyModel.title = String(localized: "public_key") + publicKeyModel.value = request.publicKey + publicKeyModel.userInteractionEnabled = false + + messageModel.title = String(localized: "status_message") + messageModel.value = request.message + messageModel.userInteractionEnabled = false + + buttonsModel.buttons = [ + StaticTableMultiChoiceButtonCellModel.ButtonModel(title: String(localized: "contact_request_decline"), style: .negative, target: self, action: #selector(FriendRequestController.declineButtonPressed)), + StaticTableMultiChoiceButtonCellModel.ButtonModel(title: String(localized: "contact_request_accept"), style: .positive, target: self, action: #selector(FriendRequestController.acceptButtonPressed)), + ] + } +} + +extension FriendRequestController { + @objc func declineButtonPressed() { + let alert = UIAlertController(title: String(localized: "contact_request_delete_title"), message: nil, preferredStyle: .alert) + + alert.addAction(UIAlertAction(title: String(localized: "alert_cancel"), style: .default, handler: nil)) + alert.addAction(UIAlertAction(title: String(localized: "alert_delete"), style: .destructive) { [unowned self] _ -> Void in + self.submanagerFriends.remove(self.request) + self.delegate?.friendRequestControllerDidFinish(self) + }) + + present(alert, animated: true, completion: nil) + } + + @objc func acceptButtonPressed() { + do { + try submanagerFriends.approve(request) + delegate?.friendRequestControllerDidFinish(self) + } + catch let error as NSError { + handleErrorWithType(.toxAddFriend, error: error) + } + } +} diff --git a/Antidote/FriendSelectController.swift b/Antidote/FriendSelectController.swift new file mode 100644 index 0000000..273bf8f --- /dev/null +++ b/Antidote/FriendSelectController.swift @@ -0,0 +1,197 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit +import SnapKit + +protocol FriendSelectControllerDelegate: class { + func friendSelectController(_ controller: FriendSelectController, didSelectFriend friend: OCTFriend) + func friendSelectControllerCancel(_ controller: FriendSelectController) +} + +class FriendSelectController: UIViewController { + weak var delegate: FriendSelectControllerDelegate? + + var userInfo: AnyObject? + + fileprivate let theme: Theme + + fileprivate let dataSource: FriendListDataSource + + fileprivate var placeholderView: UITextView! + fileprivate var tableView: UITableView! + + init(theme: Theme, submanagerObjects: OCTSubmanagerObjects, userInfo: AnyObject? = nil) { + self.theme = theme + self.userInfo = userInfo + + let friends = submanagerObjects.friends() + self.dataSource = FriendListDataSource(theme: theme, friends: friends) + + super.init(nibName: nil, bundle: nil) + + dataSource.delegate = self + + addNavigationButtons() + + edgesForExtendedLayout = UIRectEdge() + } + + required convenience init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func loadView() { + loadViewWithBackgroundColor(theme.colorForType(.NormalBackground)) + + createTableView() + createPlaceholderView() + installConstraints() + + updateViewsVisibility() + } +} + +extension FriendSelectController { + @objc func cancelButtonPressed() { + delegate?.friendSelectControllerCancel(self) + } +} + +extension FriendSelectController: FriendListDataSourceDelegate { + func friendListDataSourceBeginUpdates() { + tableView.beginUpdates() + } + + func friendListDataSourceEndUpdates() { + self.tableView.endUpdates() + updateViewsVisibility() + } + + func friendListDataSourceInsertRowsAtIndexPaths(_ indexPaths: [IndexPath]) { + tableView.insertRows(at: indexPaths, with: .automatic) + } + + func friendListDataSourceDeleteRowsAtIndexPaths(_ indexPaths: [IndexPath]) { + tableView.deleteRows(at: indexPaths, with: .automatic) + } + + func friendListDataSourceReloadRowsAtIndexPaths(_ indexPaths: [IndexPath]) { + tableView.reloadRows(at: indexPaths, with: .automatic) + } + + func friendListDataSourceInsertSections(_ sections: IndexSet) { + tableView.insertSections(sections, with: .automatic) + } + + func friendListDataSourceDeleteSections(_ sections: IndexSet) { + tableView.deleteSections(sections, with: .automatic) + } + + func friendListDataSourceReloadSections(_ sections: IndexSet) { + tableView.reloadSections(sections, with: .automatic) + } + + func friendListDataSourceReloadTable() { + tableView.reloadData() + } +} + +extension FriendSelectController: UITableViewDataSource { + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: FriendListCell.staticReuseIdentifier) as! FriendListCell + let model = dataSource.modelAtIndexPath(indexPath) + + cell.setupWithTheme(theme, model: model) + + return cell + } + + func numberOfSections(in tableView: UITableView) -> Int { + return dataSource.numberOfSections() + } + + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return dataSource.numberOfRowsInSection(section) + } + + func sectionIndexTitles(for tableView: UITableView) -> [String]? { + return dataSource.sectionIndexTitles() + } + + func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { + return dataSource.titleForHeaderInSection(section) + } +} + +extension FriendSelectController: UITableViewDelegate { + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + tableView.deselectRow(at: indexPath, animated: true) + + switch dataSource.objectAtIndexPath(indexPath) { + case .request: + // nop + break + case .friend(let friend): + delegate?.friendSelectController(self, didSelectFriend: friend) + } + } +} + +private extension FriendSelectController { + func addNavigationButtons() { + navigationItem.leftBarButtonItem = UIBarButtonItem( + barButtonSystemItem: .cancel, + target: self, + action: #selector(FriendSelectController.cancelButtonPressed)) + } + + func updateViewsVisibility() { + var isEmpty = true + + for section in 0.. 0 { + isEmpty = false + break + } + } + + placeholderView.isHidden = !isEmpty + } + + func createTableView() { + tableView = UITableView() + tableView.estimatedRowHeight = 44.0 + tableView.dataSource = self + tableView.delegate = self + tableView.backgroundColor = theme.colorForType(.NormalBackground) + tableView.sectionIndexColor = theme.colorForType(.LinkText) + // removing separators on empty lines + tableView.tableFooterView = UIView() + + view.addSubview(tableView) + + tableView.register(FriendListCell.self, forCellReuseIdentifier: FriendListCell.staticReuseIdentifier) + } + + func createPlaceholderView() { + placeholderView = UITextView() + placeholderView.text = String(localized: "contact_no_contacts") + placeholderView.isEditable = false + placeholderView.isScrollEnabled = false + placeholderView.textAlignment = .center + view.addSubview(placeholderView) + } + + func installConstraints() { + tableView.snp.makeConstraints { + $0.edges.equalTo(view) + } + + placeholderView.snp.makeConstraints { + $0.center.equalTo(view) + $0.size.equalTo(placeholderView.sizeThatFits(CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude))) + } + } +} diff --git a/Antidote/FriendsTabCoordinator.swift b/Antidote/FriendsTabCoordinator.swift new file mode 100644 index 0000000..7e7cae8 --- /dev/null +++ b/Antidote/FriendsTabCoordinator.swift @@ -0,0 +1,152 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +protocol FriendsTabCoordinatorDelegate: class { + func friendsTabCoordinatorOpenChat(_ coordinator: FriendsTabCoordinator, forFriend friend: OCTFriend) + func friendsTabCoordinatorCall(_ coordinator: FriendsTabCoordinator, toFriend friend: OCTFriend) + func friendsTabCoordinatorVideoCall(_ coordinator: FriendsTabCoordinator, toFriend friend: OCTFriend) +} + +class FriendsTabCoordinator: ActiveSessionNavigationCoordinator { + weak var delegate: FriendsTabCoordinatorDelegate? + + fileprivate weak var toxManager: OCTManager! + + init(theme: Theme, toxManager: OCTManager) { + self.toxManager = toxManager + + super.init(theme: theme) + } + + override func startWithOptions(_ options: CoordinatorOptions?) { + let controller = FriendListController(theme: theme, submanagerObjects: toxManager.objects, submanagerFriends: toxManager.friends, submanagerChats: toxManager.chats, submanagerUser: toxManager.user) + controller.delegate = self + + navigationController.pushViewController(controller, animated: false) + } + + func showRequest(_ request: OCTFriendRequest, animated: Bool) { + navigationController.popToRootViewController(animated: false) + + let controller = FriendRequestController(theme: theme, request: request, submanagerFriends: toxManager.friends) + controller.delegate = self + + navigationController.pushViewController(controller, animated: animated) + } +} + +extension FriendsTabCoordinator: FriendListControllerDelegate { + func friendListController(_ controller: FriendListController, didSelectFriend friend: OCTFriend) { + let controller = FriendCardController(theme: theme, friend: friend, submanagerObjects: toxManager.objects) + controller.delegate = self + + navigationController.pushViewController(controller, animated: true) + } + + func friendListController(_ controller: FriendListController, didSelectRequest request: OCTFriendRequest) { + showRequest(request, animated: true) + } + + func friendListControllerAddFriend(_ controller: FriendListController) { + let controller = AddFriendController(theme: theme, submanagerFriends: toxManager.friends) + controller.delegate = self + + navigationController.pushViewController(controller, animated: true) + } + + func friendListController(_ controller: FriendListController, showQRCodeWithText text: String) { + let controller = QRViewerController(theme: theme, text: text) + controller.delegate = self + + let toPresent = UINavigationController(rootViewController: controller) + + navigationController.present(toPresent, animated: true, completion: nil) + } +} + +extension FriendsTabCoordinator: QRViewerControllerDelegate { + func qrViewerControllerDidFinishPresenting() { + navigationController.dismiss(animated: true, completion: nil) + } +} + +extension FriendsTabCoordinator: FriendCardControllerDelegate { + func friendCardControllerChangeNickname(_ controller: FriendCardController, forFriend friend: OCTFriend) { + let title = String(localized: "nickname") + let defaultValue = friend.nickname + + let textController = TextEditController(theme: theme, title: title, defaultValue: defaultValue, changeTextHandler: { + [unowned self] newValue -> Void in + self.toxManager.objects.change(friend, nickname: newValue) + + }, userFinishedEditing: { [unowned self] in + self.navigationController.popViewController(animated: true) + }) + + navigationController.pushViewController(textController, animated: true) + } + + func friendCardControllerOpenChat(_ controller: FriendCardController, forFriend friend: OCTFriend) { + delegate?.friendsTabCoordinatorOpenChat(self, forFriend: friend) + } + + func friendCardControllerCall(_ controller: FriendCardController, toFriend friend: OCTFriend) { + delegate?.friendsTabCoordinatorCall(self, toFriend: friend) + } + + func friendCardControllerVideoCall(_ controller: FriendCardController, toFriend friend: OCTFriend) { + delegate?.friendsTabCoordinatorVideoCall(self, toFriend: friend) + } +} + +extension FriendsTabCoordinator: FriendRequestControllerDelegate { + func friendRequestControllerDidFinish(_ controller: FriendRequestController) { + navigationController.popViewController(animated: true) + } +} + +extension FriendsTabCoordinator: AddFriendControllerDelegate { + func addFriendControllerScanQRCode(_ controller: AddFriendController, + validateCodeHandler: @escaping (String) -> Bool, + didScanHander: @escaping (String) -> Void) { + let scanner = QRScannerController(theme: theme) + + scanner.didScanStringsBlock = { [unowned self, scanner] in + let qrCode = $0.filter { validateCodeHandler($0) }.first + + if let code = qrCode { + didScanHander(code) + self.navigationController.dismiss(animated: true, completion: nil) + } + else { + scanner.pauseScanning = true + + let title = String(localized:"error_title") + let message = String(localized:"add_contact_wrong_qr") + let button = String(localized:"error_ok_button") + + let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) + + alert.addAction(UIAlertAction(title: button, style: .default) { [unowned scanner ] _ -> Void in + scanner.pauseScanning = false + }) + + scanner.present(alert, animated: true, completion: nil) + } + } + + scanner.cancelBlock = { [unowned self] in + self.navigationController.dismiss(animated: true, completion: nil) + } + + let scannerNavCon = UINavigationController(rootViewController: scanner) + navigationController.present(scannerNavCon, animated: true, completion: nil) + } + + func addFriendControllerDidFinish(_ controller: AddFriendController) { + navigationController.popViewController(animated: true) + } +} diff --git a/Antidote/FullscreenPicker.swift b/Antidote/FullscreenPicker.swift new file mode 100644 index 0000000..508ea70 --- /dev/null +++ b/Antidote/FullscreenPicker.swift @@ -0,0 +1,158 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit +import SnapKit + +private struct Constants { + static let AnimationDuration = 0.3 + static let ToolbarHeight: CGFloat = 44.0 +} + +protocol FullscreenPickerDelegate: class { + func fullscreenPicker(_ picker: FullscreenPicker, willDismissWithSelectedIndex index: Int) +} + +class FullscreenPicker: UIView { + weak var delegate: FullscreenPickerDelegate? + + fileprivate var theme: Theme + + fileprivate var blackoutButton: UIButton! + fileprivate var toolbar: UIToolbar! + fileprivate var picker: UIPickerView! + + fileprivate var pickerBottomConstraint: Constraint! + + fileprivate let stringsArray: [String] + + init(theme: Theme, strings: [String], selectedIndex: Int) { + self.theme = theme + self.stringsArray = strings + + super.init(frame: CGRect.zero) + + configureSelf() + createSubviews() + installConstraints() + + picker.selectRow(selectedIndex, inComponent: 0, animated: false) + } + + required convenience init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func showAnimatedInView(_ view: UIView) { + view.addSubview(self) + + snp.makeConstraints { + $0.edges.equalTo(view) + } + + show() + } +} + +// MARK: Actions +extension FullscreenPicker { + @objc func doneButtonPressed() { + delegate?.fullscreenPicker(self, willDismissWithSelectedIndex: picker.selectedRow(inComponent: 0)) + hide() + } +} + +extension FullscreenPicker: UIPickerViewDataSource { + func numberOfComponents(in pickerView: UIPickerView) -> Int { + return 1 + } + + func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { + return stringsArray.count + } +} + +extension FullscreenPicker: UIPickerViewDelegate { + func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? { + return stringsArray[row] + } + + func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { + picker.reloadAllComponents() + } +} + +private extension FullscreenPicker { + func configureSelf() { + backgroundColor = .clear + } + + func createSubviews() { + blackoutButton = UIButton() + blackoutButton.backgroundColor = theme.colorForType(.TranslucentBackground) + blackoutButton.addTarget(self, action: #selector(FullscreenPicker.doneButtonPressed), for:.touchUpInside) + blackoutButton.accessibilityElementsHidden = true + blackoutButton.isAccessibilityElement = false + addSubview(blackoutButton) + + toolbar = UIToolbar() + toolbar.tintColor = theme.colorForType(.LoginButtonText) + toolbar.barTintColor = theme.loginNavigationBarColor + toolbar.items = [ + UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: self, action: nil), + UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(FullscreenPicker.doneButtonPressed)) + ] + addSubview(toolbar) + + picker = UIPickerView() + // Picker is always white, despite choosen theme + picker.backgroundColor = .white + picker.delegate = self + picker.dataSource = self + addSubview(picker) + } + + func installConstraints() { + blackoutButton.snp.makeConstraints { + $0.edges.equalTo(self) + } + + toolbar.snp.makeConstraints { + $0.bottom.equalTo(self.picker.snp.top) + $0.height.equalTo(Constants.ToolbarHeight) + $0.width.equalTo(self) + } + + picker.snp.makeConstraints { + $0.width.equalTo(self) + pickerBottomConstraint = $0.bottom.equalTo(self).constraint + } + } + + func show() { + blackoutButton.alpha = 0.0 + pickerBottomConstraint.update(offset: picker.frame.size.height + Constants.ToolbarHeight) + + layoutIfNeeded() + + UIView.animate(withDuration: Constants.AnimationDuration, animations: { + self.blackoutButton.alpha = 1.0 + self.pickerBottomConstraint.update(offset: 0.0) + + self.layoutIfNeeded() + UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, self.picker); + }) + } + + func hide() { + UIView.animate(withDuration: Constants.AnimationDuration, animations: { + self.blackoutButton.alpha = 0.0 + self.pickerBottomConstraint.update(offset: self.picker.frame.size.height + Constants.ToolbarHeight) + + self.layoutIfNeeded() + }, completion: { finished in + self.removeFromSuperview() + }) + } +} diff --git a/Antidote/HelperFunctions.swift b/Antidote/HelperFunctions.swift new file mode 100644 index 0000000..fc9d1c6 --- /dev/null +++ b/Antidote/HelperFunctions.swift @@ -0,0 +1,19 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +func isAddressString(_ string: String) -> Bool { + let nsstring = string as NSString + + if nsstring.length != Int(kOCTToxAddressLength) { + return false + } + + let validChars = CharacterSet(charactersIn: "1234567890abcdefABCDEF") + let components = nsstring.components(separatedBy: validChars) + let leftChars = components.joined(separator: "") + + return leftChars.isEmpty +} diff --git a/Antidote/ImageViewWithStatus.swift b/Antidote/ImageViewWithStatus.swift new file mode 100644 index 0000000..5fc96a3 --- /dev/null +++ b/Antidote/ImageViewWithStatus.swift @@ -0,0 +1,61 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit +import SnapKit + +private struct Constants { + static let Sqrt2: CGFloat = 1.4142135623731 +} + +class ImageViewWithStatus: UIView { + var imageView: UIImageView! + var userStatusView: UserStatusView! + + fileprivate var userStatusViewCenterConstrant: Constraint! + + init() { + super.init(frame: CGRect.zero) + + createViews() + installConstraints() + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func layoutSubviews() { + super.layoutSubviews() + + imageView.layer.cornerRadius = frame.size.width / 2 + + let offset = bounds.size.width / (2 * Constants.Sqrt2) + userStatusViewCenterConstrant.update(offset: offset) + } +} + +private extension ImageViewWithStatus { + func createViews() { + imageView = UIImageView() + imageView.backgroundColor = UIColor.clear + imageView.layer.masksToBounds = true + // imageView.contentMode = .ScaleAspectFit + addSubview(imageView) + + userStatusView = UserStatusView() + addSubview(userStatusView) + } + + func installConstraints() { + imageView.snp.makeConstraints { + $0.edges.equalTo(self) + } + + userStatusView.snp.makeConstraints { + userStatusViewCenterConstrant = $0.center.equalTo(self).constraint + $0.size.equalTo(UserStatusView.Constants.DefaultSize) + } + } +} diff --git a/Antidote/Images.xcassets/AppIcon.appiconset/Contents.json b/Antidote/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..1e2d708 --- /dev/null +++ b/Antidote/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "filename" : "Icon-App-20x20@2x.png", + "idiom" : "iphone", + "scale" : "2x", + "size" : "20x20" + }, + { + "filename" : "Icon-App-20x20@3x.png", + "idiom" : "iphone", + "scale" : "3x", + "size" : "20x20" + }, + { + "filename" : "Icon-App-29x29@1x.png", + "idiom" : "iphone", + "scale" : "1x", + "size" : "29x29" + }, + { + "filename" : "Icon-App-29x29@2x.png", + "idiom" : "iphone", + "scale" : "2x", + "size" : "29x29" + }, + { + "filename" : "Icon-App-29x29@3x.png", + "idiom" : "iphone", + "scale" : "3x", + "size" : "29x29" + }, + { + "filename" : "Icon-App-40x40@2x.png", + "idiom" : "iphone", + "scale" : "2x", + "size" : "40x40" + }, + { + "filename" : "Icon-App-40x40@3x.png", + "idiom" : "iphone", + "scale" : "3x", + "size" : "40x40" + }, + { + "filename" : "Icon-App-60x60@2x.png", + "idiom" : "iphone", + "scale" : "2x", + "size" : "60x60" + }, + { + "filename" : "Icon-App-60x60@3x.png", + "idiom" : "iphone", + "scale" : "3x", + "size" : "60x60" + }, + { + "filename" : "Icon-App-20x20@1x.png", + "idiom" : "ipad", + "scale" : "1x", + "size" : "20x20" + }, + { + "filename" : "Icon-App-20x20@2x.png", + "idiom" : "ipad", + "scale" : "2x", + "size" : "20x20" + }, + { + "filename" : "Icon-App-29x29@1x.png", + "idiom" : "ipad", + "scale" : "1x", + "size" : "29x29" + }, + { + "filename" : "Icon-App-29x29@2x.png", + "idiom" : "ipad", + "scale" : "2x", + "size" : "29x29" + }, + { + "filename" : "Icon-App-40x40@1x.png", + "idiom" : "ipad", + "scale" : "1x", + "size" : "40x40" + }, + { + "filename" : "Icon-App-40x40@2x.png", + "idiom" : "ipad", + "scale" : "2x", + "size" : "40x40" + }, + { + "filename" : "Icon-App-76x76@1x.png", + "idiom" : "ipad", + "scale" : "1x", + "size" : "76x76" + }, + { + "filename" : "Icon-App-76x76@2x.png", + "idiom" : "ipad", + "scale" : "2x", + "size" : "76x76" + }, + { + "filename" : "Icon-App-83.5x83.5@2x.png", + "idiom" : "ipad", + "scale" : "2x", + "size" : "83.5x83.5" + }, + { + "filename" : "ItunesArtwork@2x.png", + "idiom" : "ios-marketing", + "scale" : "1x", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Antidote/Images.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/Antidote/Images.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..e020aab7be2725300a9c5cf734420af04258b68d GIT binary patch literal 618 zcmV-w0+s!VP)TltD}DP!NT`Nz$ZPYb;VBn~I2`D^W`Q2`&Btf2>g4 zi71us>Y}Sc5usphz!F2|Egrd~?S1X$&1$%pIdkURGgs0yRaHeq_#fc_hzP2>b!j`> z7haKUGE`NvEMq>OGn>r-h@yy-lM{U3-w#*@5)slg<>lpt;c#f0sVdjk*WBLTQmt04 zb)M}o&vV}2-+6j^qSNUR$1x(pWHRCT`I&mX&ehcwuIrlGqN!KtBqB!3pPwJz-ri`p z+r)9qU@#yE0(!k3Ns=%cjfmrzTCKLl(kY`C`D(Rdu~=|+c19S6wA*biFE2SbIH1*P z@%{bHYPH(ZPeky_VC9kXJf~8raCmq~x7#)BUDq}DHoI*-3V`dnhzOsbpER3IQlgRzOwd_xG2@ zV!?8`1mN}cmFaZK{rx?sr>9gZ6{A~u^tBenp@`u7K1WAKJU%{BtyUS2$MpMsqA0>~ zoHgBdYFJ)FRpsmJ3(xaNl7v>PWx#Cfs;c%)*^D3va2&^2Wz%NmI>WsTw3#PKf~r!l z*SDH&0z0a@<)?D)x-P!&BO>O3c7Zy@%Gtv6JkHP0nM@|sYPB_n|N7eO?kutEcDsaO z$no(pjYh+Om9<-&uJGZ$Pu8}gJ6CVtk8QKaCQA|F4|0wkqg0BsIRF3v07*qoM6N<$ Ef@qB`r~m)} literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/Antidote/Images.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a19b88bd6749bb8fd05ea9e3ee2700ae40eb7139 GIT binary patch literal 1581 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 literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/Antidote/Images.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..7cf5f9d7c86f45c0290932887a68400802d498fe GIT binary patch literal 1027 zcmV+e1pNDnP){B1nRwZe5~4PyP%2 zWkHv2L3ZdEU6O(hAq1A`r6d)!u+4FIzSC~A>#W)LfVeaB&ig#?J2USLp_DSl7=8mG z#M5@>IQ@(VTZ*Xw~&3RP7RiA135IwVO76zuqS#3>?$B2Y?Euh(&RcZW))0@F01>pE6f zSFyRdiA*MgP$)E!FESVmm?&BvrfK5#_7-PnX8?fp^>sv}QS^E}JUl$WvMdw|1#E9` zBODHo_~P4yke`hdL}=SKo}ZslDwVLXuz>yjePl8j$g&K}vaq$ah0DuJTwGirkw{=| zZ4I(4dv>iu=0N%_75#o6<#HLeZ6lx0Bb7?w@$nJ&_xGsPYFJuYLO!2|EXydD%joy} zZV;kl#u)pZwB2r_TCHMZV*`tei)gi4I6XbZ@$oTAr4mfjL^_>DE|){CRzs)L@uZah zIT$&oygJ*q@%8nE!C-*d*;y!xf>bJnqoX5OmIYncVHgGoA()w&0i_hCX$pPukt@7` zUlAb$wrztk21QXo2tha;MmC%E2(@h+vMhr!2FtQs5)s_=22~IKe_W;E$s|b<67v2O z|A2pjs;VG_pwVcc*=$17v=N){?{C!Wbx4u~P16E}IZ*g0M3rcMejdBKyEs2T$JN!9 zTX`5`==b}el)^9!ghC+{3I!yS$q~Yls41l`Q&8#p`1run(-Yp`-`zA0heKRnU!&1z zpja#-o6RDd%_0(s2qSfT0)XPbqC|$#XcW0z4whx1+wHn3e|vj_s;b!A+e0Fe2=w6( z%2RuTinY`C`T2>HlM^g2FC!L<;pXNBhlhtS3}Y;bpFiby1amzNh1 zLa?*5165T6vm_GYZlrNWB4@E!43tuLjVHaW0Q{U&(Qyen;F2U^Zf*{yX`?OG$KCXkko@K7{R6(2I})=4A8!Bv002ovPDHLkV1gY$)uR9a literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/Antidote/Images.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..cfa18decad55296844cef2082abf733da551b8fc GIT binary patch literal 2700 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 literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/Antidote/Images.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..a19b88bd6749bb8fd05ea9e3ee2700ae40eb7139 GIT binary patch literal 1581 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 literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/Antidote/Images.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..be45a31e09b41144fb997f90f783f6a95ece16d5 GIT binary patch literal 7836 zcmX9@c|25KAD$m7OZKghYz@YmU5RX2$2zj_Bs+sFFLSwebiuw9^En)Ivn=hX9${SAk>R}xwMilBx4lLZAj zoAh?1K)&hc<fGed~go;`_#*W$y-JD}!ffhnwQ$NI?X2$RyYD3R38 zY&u>B1UKRy5WjMeQoyBj25BIuLq@n%6rUpr*=~v>Qgn;rTSU;s(M{MwvMt-QHR_IIW<;7-3^|7O2crfhjpNAqUQ(QJz}~?^~?%dEw@*lBwNEi#A|>~bZ4 z4Yk$p{@4oWJ&7xk;mWD{;FxRl+zYGUb8c{ObaW%x{eMr%h957+YlAa-U8I01fk7Z-?@^TX*Iw{B@dP(L=nCPFM7Wzd|Vk&&3z=SRim<=4c- z#L!qQpQn`>R#J=?6Tp&vLy=QVh@OqppOC|6IZI}W!*_-3ohSi6?|1mivgL5f^Tv%E zUnVAQyvfRPMUW)vI~^L`f;BXqA5_gU9FFFH-xnB%DJ-agp|B zW~>_<8`X}TS7l^m3d_o_qEIMMB$4O}tiPj&2X#h9#@p=duS-i#U!Al{jAi8Imuc*e z$?_4W?q2h4w-){0j^dw0LE$o55X04w%-CY{7=@Un%z-DhA*8(EoqqcZCVc8`{OBkP z9LE)jl59qthy9xPL~d(qyY}msMnHfxu)BO|lw?t$NLF&4QWFaci!Z&slotmdUo6fB z&v)UG zf{t4$;r#DW2@ZFYm6g@5ZLE(W^-hM)Oj`u!`T2Rs!I=5(Pix=MM=aE_J8LDWOE^+~ zXB7E024wdKT}Td;#&%Zhh55~N<6Ab6#5aQc#>_Oq!a3iUHpVJK)=RVePXDY&cmLkp z?A#wzNi{_5WuP&bT{&@${F-Y<%*%V8?(VA2&iqr;)4NMZiKU58&Tk6}w7?l(PxeX1 z#>P<=qH%L`bH#q&zeg!tz}3Qp8DXKgYMYwLVPn*z2A|muJ&D$r?ZDoI>@55TDr{=v zDEN0q+U=l`C@d-IRL3<*f(;bpCwD`*W@l$D+7S%Ntu- zCZ3*#1qKBPw_4a)7*`2dU-JmsEZ+O`h5p5H=Rad8WqG5R@n?Ys8UaXSV`D;zR_YQl z%f4r2MF7OZhFnD2pYgTr=WRRSQ*PPie;!WuByrPIkfE!p9sy`F!LZD|_!l86A;F(# z;0z24tnvgdKoBA#f@)06Rqw z1mJPqrK=-`mWINFuu>-?_H6)id6H5#%+~$Ow9^Te@@9{_hq!Ik|SJ$p=vbaUx7guJE<; z6$7&rn4i7O=js}wX_3*{Hz?nDJ|Et{8rYVGc?9R}@SXo6QBtnJP8`pWl;cB`s$@EV zg@i$3HTV|K#Uvy${>^q5_3#kTX!IB7)CX}}TRt!t3RB?>>Aq{`XhXC%X z;?mMPXMgAa9UewIf4X61ZEb9Bj^9|}wg)QrT~3bw=1(!-9Aiy0Gqb1O-rc}TSQ;|m z8B_7Y06qb#I5`P*skNMG^e5NT(?eHQifyPXCT(!Z%AMR`Wfh9Jr4PN!Zsp~-n|n3X4*o($ zngALuzY`o$4>UARIj@HbT;TuWw1L(((Htz%)ZE-UWvLnU5H$R>&Y@F7v&e{Y^Jk?x z6q-Da@bRI$#L_M%q=FCaeo?mC0&>ZYGh!}9%YhfC{JFjj41}?>gtwtu7ekcnjGO}= zQd(G2uru~AFSW$&QTliRgCul2anA?dO9s}*l@gU&LC_fsW{zh`3=h;KrhyskHL+*Q z-1b&hdo2J)c{!5#Sg2XodG?Jod34PcXV!;W^?*9Tm3dgFjmtpp6w2&=Or2tvH zuUblH3t^~Ex;m_|m?7Fs3&I`;JIQpcSjF-9XQtm?nQ_sBsVEjC()(r=7l@`# z57#UTE8|!8PwLqJLiM1WQi-`!M=sey>QM|wjdT{qGz`g)XvFgcnWzLZbSg9#0!eHm zES0PKq1$piSu-?jFqM%OOfkI2_OKb^EtUp(u(E$}Z~$mQvTCVD3v-O5k^dCLm9FK=GLIs9lhHtL(DHu8OX)A#_sLaB8W1c>J`cO{~ z8BFCH9?n&6kk`@Mo6unB-9+U$@>nZd|Ej#t%omJlc}vcYdJ)6a)KvAe-&SJw;!VaR z^B6At$zX{{8Rgq)ri^KSCH-eepwx!P$K&@&gUbN5zRk(${N#*hpo`xfH8pgcuJ?Yl zJ+kmDIFQK2{zk&S?bT&BUg^u2o8<$#W%nhePfb}Z@Alh0I&a_|3yIE+_tz-8hizG+ z=+7|d3-mR95OFGFP@tUbC5PPI^*=joXup(n&$j210Tr;^e51b5Z z$ku#2J>DOfz%ZboA3Q(gVM?sF6L};;$6Dd>EW?@QB)p>;0+p8$qJgDV*_F0TZ67%U z(>(5xZ;P64@O>U^ZUBWYUY!3`2;Q>!y03j(R&jukeB9^qqdA!}vfLSdmw4c+eTm*{^?!^mlWB>)rHsfSO3Zf3^ARgYklhG$IkpBQ_ zZXdxK6B9E>>r?S*C}o)^t3Nc@86 znm09hT1T4KgZ5Qt-C4g|*_>-w8<(bSgjDu*fdBmfKV#F5xYgi0FCMa7uN85;?aY=5%j6CgZU)>S(Ga; zIJBF>E87U1p(>UA2kwZo1A#78dqdlS*!vN8iWpU;la-8PVDFLvZA|6`$ev5+Z+(IF z)!aQcflHfz?^UAC-ywmruCt))bAwIh&B#%yi7a&SjMT9$S%pUACXBL0K|w)RNFoqO zHQ)ifCaR;v$b;g%H?GgLY@C|zHJ<6SrHg+c!O@iG#Ah})dG=S^0#4CwIq5c4Z$qx% zG0%T$X7xHbi<$(9zzpVIC-f!dL#6uM?yXgssGa%1zdaBaPobVzM~`A7t-L~qVRNno z`-az<&c^!-dn3xqkT5UBuA3=@oJMCzr}Tf4Wy_2wlPg+B&1VJD+RWEWlF(QLg23-W zY>e6{Y}Z*66Pz*093)NlBS&3&iEk8c!&hFP^!8|c&+&ML#f{#Cu>KYzr^hPcM>`aj z_#%~V-ZPX%fL=7@^b@k&uLqzn~ud0R@ zfNvh2oJ^GU{8{ZR)t9vw668YG0gEsTuw41dbw=t)g^VYX%!0Va4728m0YFW?ef##( zzXJxU2amriEp58O3Vah#l*cE7FH)EV4R~_CcaW@ceG6Zr$N`s~)zF}?dB+Tm;x8O% z#)KCA$o4pEGUCoey}oa{_*ls;2@ynscC=TuhKOeMr+NF#G)4hFVgZ2noci?G*w{q- z3zht^4dF{XZ+9>eCwSmFio&t&!l6R%m>}YX1U+FH!Fop3H#)b|f-&UGcwQ4=HLZPH zW98>UI-egHySm;{K3_Lno^&hd2ILu_oRS$Ep_KJhoy0h=wCFumROvbaY@FaFz;gRj zrD%U3NRAD$J@)``lFPvRbKS9kjavr9lQQ6@kaj!81aFv5*Sg2McQ#TeN2$Z&WIARS z&uBJ`CX5&|(5p*zBxPuR0fZ8O4_~t7ex<<|vV|j612!?bKZfO*Ul0j$-G{MJrW|Y0 zD0dH}wU}F6P%o{TIJ1OxXw$DRj7l%j3svD4#eq5fs>yfL$-cdVdb=a zdBKEMe!R)U;+d@e-!nFen~MqqFYE+AY@n?JQ9JMsnud_Qg`l*qQlK?#U%NkJvNnSY zIR5U7hygl4jm#3;HyBu+F2m1PdV9wI_eWhnD?9TMmI1taZ6E-8 z&DH9!Ns$~=qQlYF>_mg_ZKqE+B2g7afZ(>Uvid=gO>}BPfSs$MG&Q0P-m2LG)F}3j zXS=TH4<2rHjy;3emHj3nzB(`fY%(7F zE2MGp?Vxl+#ejFV(0kex;F#UT_}iBb-cFnDY7Ai5RRx%Ym-@#(L2B+kP0lm;^UkQu-PtgFTPkkX2ZiSy@M!Iu^U=va&UCq{t%IXpZp?tdwD+cZLN%uLX{ zJL7)&>>9)1rY>KeUvLfd)IYTUsx85rIg#ShQl6cTxA&~A2?5zt$D-sV8B9-CMCeAH ziZ%?#`cG3A+CTvLp?`0uI|^*}oLS&oXeI61>&h2!IFq13?qy5^)O)z{Z9ruBtqt)4 z#*6K2u4uv##o>}$tQ%VTsM;j;KeFER*v)iY%H8oE@Tf7fCAEaZ6^-OquNF=ZHs`wI z03YF25W$wJa?yD7=s(?H*2dwRh29rsfkS<;-6!_z_PQ-u(`dD3@uTUGDhOX=7yx8_ zDAW;wn7iNLJuMeb6tNc$Yl_-??2{IREQipV)p-O}Q&F$NdB?QamAeq&xxqAdD5Rfx z+O^hl8(#=bkk(*!lf*FSyT1DqfZve6mCMCp#?9YQ(qfE4LicKQxY>i~W7U9IO*F)k z@O-;99uPfFK0X5$^#&5=+$2ygqLhH*&k>sTPjJgnc#nk?c@29j!jekwr!1cf3>^NR zZZ+o?6Bl1HZ$D)n$W@GiK}uIX-q*@AzgeWlj{D5@bKp<-_f+MQEOtTwDvOV zEuSJh7LI>1QsX&N22}`LW8e;5Vcfo^eCZgo>=8G&+y5cHMx&460gLImDwva{Vk2Qp z&ja!0D-W9{c<7BDzx5OmAy`&bysYdt;S?+788H%iIX7pgbpB`LQUCy+CBFZo4KBK< zs3`i#x3{Kyu#Cr);)#v@2-=N2x_keTZ&Lx}y!XXkL*|338 z#Y#PZA=WoA2s?7T5~JGXba%TUTYsq9LN(zxx~>xyi|y@o>55RF<0Mxa#N9=!_m)8yS z#R(pmH9D>@{HaPEZGY2gT8rn(kisvr{sk=8Q4yDLg`yhxNNSzEhbzzE zd*i|t91OwYOo@fHwalr?r$Rsuc9}8&Y0gNwp|gVnNO@lOyGR?|T^8!1k00rQd|e|V z;z6HvzJs+=$AN4f^9XgEl}f>&d3b*cRe+g+nJ|A`@fewj_{llKw|oPri?!`-{NA3_ zkM+7EKL0cz_62x8hE(u^`_`>nJ-$_A$*JVVa?YfkRAE*Pqa$cAnED;xL(7D3onV%n zHNMLZ4tR$YF2!g-P&ha_kzrsScWkc2SkykD?4 z&u5V5nG*bCcS)kQV*@T&ZNiA~E4~LNpg>7@#s;AKd<(e!p?p$uau-1w<1@X$Ph7Qd@d-?ekDsT321A z(i4xndKe>(R%owx#Vnf0W^(4^%vHu*`UC&7qkqyx=*r}DZ}AU)`A2!u#w%HsQ2CQG z*Tmkz_b#tP;s2m3Q$~uEs1dD$Sr_`qB}YAR33y586V<@?IV=WjN9`;TU5O)65@T@` zS~GEUL37EJnFdQICdDZt=9br{(}jf-3{f2{#|Jh%6-+X T#_j?fH-mIE4K%9M9HRdRJ^y+# literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/Antidote/Images.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..be45a31e09b41144fb997f90f783f6a95ece16d5 GIT binary patch literal 7836 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 T#_j?fH-mIE4K%9M9HRdRJ^y+# literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/Antidote/Images.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..206019e5d366f9be54d79721eb478d19f9ae7893 GIT binary patch literal 11575 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 literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/Antidote/Images.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..bae0c8730720cf7cf07e3cad43f86ed8a38397c2 GIT binary patch literal 4010 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 literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/Antidote/Images.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..1b50349ca17de1df802898b1002c5f350a8db223 GIT binary patch literal 11185 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 literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/Antidote/Images.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..321f9d62fe1044f93e5017477c14147d0dc02795 GIT binary patch literal 10722 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 literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png b/Antidote/Images.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..e419b2f2584ed7f6aff408fb8cc1451d9e0a71bb GIT binary patch literal 44373 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 V1#N3i&D2|b`n>&SqIclD{{!`$7C`_2 literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Contents.json b/Antidote/Images.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/Antidote/Images.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Antidote/Images.xcassets/Controllers/Call/Contents.json b/Antidote/Images.xcassets/Controllers/Call/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/Antidote/Images.xcassets/Controllers/Call/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Antidote/Images.xcassets/Controllers/Call/end-call.imageset/Contents.json b/Antidote/Images.xcassets/Controllers/Call/end-call.imageset/Contents.json new file mode 100644 index 0000000..c78909a --- /dev/null +++ b/Antidote/Images.xcassets/Controllers/Call/end-call.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "end-call.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "end-call@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Antidote/Images.xcassets/Controllers/Call/end-call.imageset/end-call.png b/Antidote/Images.xcassets/Controllers/Call/end-call.imageset/end-call.png new file mode 100644 index 0000000000000000000000000000000000000000..4e1eebaf732c56fa18428da31dac6ab9a2515780 GIT binary patch literal 645 zcmeAS@N?(olHy`uVBq!ia0vp^av;pX0wgC|rfC8xmUKs7M+SzC{oH>NS%G|oWRDf38wRuoNLcAMGZr2ju#-+J6O*$w0 z*JLi#d^~q`@bfkAj`tgXKQoiN>SF(FQ$LLleq8gHF|9eX(Q}&CqM7C_Usg=k@UPjL zpln=G<;Yz(Da0y4`La*x;^vlg-2kqIq&d%e(;YEus&++~+n|lw>#xtU+ER{+(&fc0b z<%N1-%-QthmW~GpS1sd93Ywku#$b_Qb3-q0meAd_i2f)JZ{@)B@aawS(^vWyx|Ob+ zytr@S{3}bv7G1h-_u%T%2Wr|^ZOv|bCV$y@)i6-i>Hk`7ff(a;&TDnHrmc{*YpSw1 z(eQAcZ~0=bF6HUTas1PHwjApEbwcv-l?LHo(NCX-Evo#pOGM#7Y^v@$WbGBwmTFtjo-__pwp4T^@`{FKbJO1K6?(-0#gD-%mABdCU}A9z6;7(8A5 KT-G@yGywqY)cRZi literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Call/end-call.imageset/end-call@2x.png b/Antidote/Images.xcassets/Controllers/Call/end-call.imageset/end-call@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..aa73e487cc0f4a95d7412398c132c339d392272c GIT binary patch literal 3459 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 l?3JSTz;|=b?b3?*I{ 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 S+ZBxf0000 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 literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Call/location-call-medium.imageset/Contents.json b/Antidote/Images.xcassets/Controllers/Call/location-call-medium.imageset/Contents.json new file mode 100644 index 0000000..9d5ade5 --- /dev/null +++ b/Antidote/Images.xcassets/Controllers/Call/location-call-medium.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "location-call-medium.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "location-call-medium@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/Antidote/Images.xcassets/Controllers/Call/location-call-medium.imageset/location-call-medium.png b/Antidote/Images.xcassets/Controllers/Call/location-call-medium.imageset/location-call-medium.png new file mode 100644 index 0000000000000000000000000000000000000000..056bbd4709567504e43614819fb63bf9a7374482 GIT binary patch literal 244 zcmVE7LY_XA%tp`QU7 zItGLo=xE*tmpHV0j`CG_jYq5)DsJ4UFsukqeV*MTdh*Dd(wuBIu%3tV5>>pCAZO`a; za$Q#5v{WHjxzh0 zVJ>z^tVH3I6A0vx4edg7n~lT=<(zYo^iIi$?-G|{M^$9<;u5p}jv|(3DA*USv|f7c z2lyO0bLNQ8;72a*mUi<6LIGQ9y)}Z=ZcYfOX_%$>6Xwx(1A#r*4Q1FVSKy=|8*e1=@+C5!WNS7xzR`>y6~+%c3&*wb3&;4CY2nhhP_`H^ wyeyQC7K&dB<-3&!h=nKA=NbEM0`K^J0WY$a$Eu!Ux&QzG07*qoM6N<$f|GmBcK`qY literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Call/mute-selected.imageset/Contents.json b/Antidote/Images.xcassets/Controllers/Call/mute-selected.imageset/Contents.json new file mode 100644 index 0000000..06eb2ff --- /dev/null +++ b/Antidote/Images.xcassets/Controllers/Call/mute-selected.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "filename" : "mute-selected.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "mute-selected@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Antidote/Images.xcassets/Controllers/Call/mute-selected.imageset/mute-selected.png b/Antidote/Images.xcassets/Controllers/Call/mute-selected.imageset/mute-selected.png new file mode 100644 index 0000000000000000000000000000000000000000..27ff96440dd24d88b00d6a04cab4c8fa73c927db GIT binary patch literal 1565 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 literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Call/mute.imageset/Contents.json b/Antidote/Images.xcassets/Controllers/Call/mute.imageset/Contents.json new file mode 100644 index 0000000..46ba9a2 --- /dev/null +++ b/Antidote/Images.xcassets/Controllers/Call/mute.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "mute.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "mute@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Antidote/Images.xcassets/Controllers/Call/mute.imageset/mute.png b/Antidote/Images.xcassets/Controllers/Call/mute.imageset/mute.png new file mode 100644 index 0000000000000000000000000000000000000000..5331e14effc0a622b27a8654244cdf1ff72129a2 GIT binary patch literal 1491 zcmV;^1uXiBP) zaB^>EX>4U6ba`-PAZ2)IW&i+q+U=KJlI$i7h2L34mVhLL#Bwk{RoOw7p96M#x@RWI zy>;(Xs!bWNkcE6cpl8DP>(3efz(plQrgc*lnYR6cZ0N zw9JiV+gywbH(8w0Dm2-oNEZjg#v=e-625bxJ#X3bHFC_{39d{CMjQV>l<;qZKU2b- zZAnDYZ>^9Qua%257P(c!3qWXI+;j{4C>Q?tw0^KuK~T5Mjt{KyI71vtA8SiCXMvxh zJ$D5K>sJ6sgt-;TkbpqUBubg0F&hzdbO5TzoUu0!5Fl0VNRpEX&Ld;zH86#eAwYfIcmf5X{l+;&6>B;YUeH; z$3)NFy7$uSpfGS!j5KuQVZ%ombz-eenQ7|G)27cd>rL&V`lb8?HM*$rCbj(RrUq*; zdxW5MoakZ(Vw?!XZ4tnN=EW>JrNoQeVipTyQz#=zU2H<9MGOejAl6AYyAN_d#4V`* z5I6oWa$%wS9pnPgedYEIwZ4Am+9r1H!lh{x>^_VSuYtX;AGP|c?K{vr&^ypO&^ypO z&^yroAkf4g5BMiG{0-dIo#}ZKhR*;10VHWdLr_UWLm+T+Z)Rz1WdHyuk)4pSO2beT zhQG$5B8r2epbi;a3odqYsS2T>5NidaQ+m^4F^M5bDZYVkq7TzS5PSq5K*8DnMh6G8 zc;WDW9M1XwdoMU{Y?7k62T5AyUau2e23PLF8xBoY*=92|Mb`2C6Kc=rD-EkJE$dZ3 z_ve|9hJ}&NRH@1G5*i2M_O#3_t60D7_m0F5VmC_CNc<$;jgrW+-R&ju#Qb>L+bj>$ zi*wso?cmYn6d#uX6UM}pw4|vz$F$j(dgO%MQ(&YqL-nSbDY+39a`HG7^+mc(P2N_O z=PP9(kFmUL!X1e`Z65Z2zt=v_s?Em6EDQ6nYR##f(FoojVI_dIXIQ$f$y)sVwwjrC zHS^CmegU|cP)!w7Ycc=;00Lr5M??Tr#*4P!00009a7bBm000XU000XU0RWnu7ytkO z2XskIMF-{r1P>-TZtU6_0003xNkl{Rxg1SO0)+;#%m^T`;IWqtKR;I!8*Y(7q0a*qVD|f{J>wT+Vx*L@5cHrXQd}^hw8u%QL7DWmDO_5#ElGvBFC+GFCVo`U=ed{PG{$ z_F}NwWe+%K2)u;qo&i|q1i0b;qg+LZtYtj+0mvdmHN5Q>06PHO@i_Bhmxn2}Wg1Bj z(KKGk13%kDc%)3{zd%eVgnkBFex|?#acMShjRB%Z#;9iKAqK45ygx*UF8Pp>r;89r zQLQ^gh%t4F{@GF#sWV21v(Gwzj2Bqdp%bj1-dhwE8(d9!{pR;IoAD=ag$fQrI8<0o tKDsr8sQvPl{C;>LLYt$_Ee>s4!7Kmhf>86u1v3Bu002ovPDHLkV1haTwHyEd literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Call/mute.imageset/mute@2x.png b/Antidote/Images.xcassets/Controllers/Call/mute.imageset/mute@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..0044b8df33f896f7265ed6a460419028b5e4747e GIT binary patch literal 1704 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 literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Call/start-call-30.imageset/start-call-30@2x.png b/Antidote/Images.xcassets/Controllers/Call/start-call-30.imageset/start-call-30@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..55f10aae3479dafdec0f057593f5f6d6a9b9b0d9 GIT binary patch literal 3480 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 Zh99;m!-?gOT@U~O002ovPDHLkV1f;*on`<4 literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Call/start-call-medium.imageset/start-call-medium@2x.png b/Antidote/Images.xcassets/Controllers/Call/start-call-medium.imageset/start-call-medium@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..5e9b1fea5ae7ddc25e9cdada77c6c0c081d1486b GIT binary patch literal 738 zcmV<80v-K{P)Xms*SBfv%<1#) z%=3M|=Q%Xy2!`E3$ujs}dRA$r^_7<2ch{YIGD-qWi78DgODH|}VzC>I%iVB#7 zjTqNlBK{ZKS4_;ttQIZkBoc9rVtxTx>(Y%8VG?m&FCcGSE=VU)!6bI(A9;2@NiR}C z89lkDo`v696RF^8?x|;?taXt|?8rO#Ode@nq=Hi3!K>-Qt2W(h3zoO(Ua45GJx^o` zeK}{Zp`>+@q1;nf(KY?^ejDy}xefPdnML?1{nL1!f8_dHk-qhAEg)}Qmg0|ak=sRt zZN`8wi3zMIBxw`o;)5`mfkKidV88JFqhk*x?g^9mCVEZoIQoPSlVvO`B5X6Zb6$hvK1Y=V%r({nCvyt<*>sB1E%UJ5Dc?*7vMLh^FQTIf)EsDMIu< zb5{0E;BeL=G5wN#zfV)Q@{)+@#oaapudWxOv$#Uoh4&4@C9P2`$v1i}-J;LpY4@DZ zSeJY11}wov(RiO!VjP=_2%Ch3ID@wuOO&vxpp3z+6;0F+@lkY6FeZ9ssJpQL0e1r| UOicd!SpWb407*qoM6N<$f?qgP1poj5 literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Call/start-call-small.imageset/Contents.json b/Antidote/Images.xcassets/Controllers/Call/start-call-small.imageset/Contents.json new file mode 100644 index 0000000..4b572d6 --- /dev/null +++ b/Antidote/Images.xcassets/Controllers/Call/start-call-small.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "start-call-small.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "start-call-small@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Antidote/Images.xcassets/Controllers/Call/start-call-small.imageset/start-call-small.png b/Antidote/Images.xcassets/Controllers/Call/start-call-small.imageset/start-call-small.png new file mode 100644 index 0000000000000000000000000000000000000000..a1b8e6cdf71b282ee20916a5ef8f1166c3b75d95 GIT binary patch literal 466 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YDR+ueoXe|!I#{Xiaj ziKnkC`$I;4F+zS+S>zEaSexTg!zviA*s7h8xUto>i&as<@Y$_3g@)H>raky`W{&ZNiC($CmhWO~ zS}ELXF@dvbL4g2!o2tN_h}qM{@1A=WdRC&~nJkO=Cy9cmQayWT9Enw#$Lg4-&!=M% z!qF7+DSS<%`kPhRx4&tGZ(o=Bg}bKm!i0!R+mhET&yRn&_0_7UH#`JtW=vUcy*1Ew z`CXU=&Cb+O$`pI-`CcG~>fO`qrDyC;7F`ck#T zHKHUXu_VKYk_7#docnpzo~Y8x0@85l7B`VfkuAvZrIGp!P? h!O%3s$jHjX(#psXqT%WXUQj?Yc)I$ztaD0e0sy~}s?Pub literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Call/start-call-small.imageset/start-call-small@2x.png b/Antidote/Images.xcassets/Controllers/Call/start-call-small.imageset/start-call-small@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..0fc6e39e25d593e3a73c962bae436b3b569a5e29 GIT binary patch literal 466 zcmV;@0WJQCP)og91dT5s zN(lC*NgdY0BGySD`2rioMk^(RfPMg9BG+Ofk#*gf-FwFar<#H1f9K3R=Ui^b6!!54 zGac5mMGea+ZsaA#?nC?`KDUWq=N<-fir3M+L;O0|asn(x#0y+tG#9{00ziRXp;VQ} z??iwCD>(qZ_W*E?$5o2g@wJEj4=_|E0E|dKfkVMBDv#7MOy>}XmkHu6G;#sJw+O&g zPH}jO(=Grz7|ab3bHz>Jg! zoiAn$&sESn))OF_c=T_71Fvx8e*;@lqLtV1F#+PIU{NznbH2p8x;=07*qo IM6N<$f^LY$aR2}S literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Call/start-call.imageset/Contents.json b/Antidote/Images.xcassets/Controllers/Call/start-call.imageset/Contents.json new file mode 100644 index 0000000..f9487b6 --- /dev/null +++ b/Antidote/Images.xcassets/Controllers/Call/start-call.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "start-call.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "start-call@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Antidote/Images.xcassets/Controllers/Call/start-call.imageset/start-call.png b/Antidote/Images.xcassets/Controllers/Call/start-call.imageset/start-call.png new file mode 100644 index 0000000000000000000000000000000000000000..5e9b1fea5ae7ddc25e9cdada77c6c0c081d1486b GIT binary patch literal 738 zcmV<80v-K{P)Xms*SBfv%<1#) z%=3M|=Q%Xy2!`E3$ujs}dRA$r^_7<2ch{YIGD-qWi78DgODH|}VzC>I%iVB#7 zjTqNlBK{ZKS4_;ttQIZkBoc9rVtxTx>(Y%8VG?m&FCcGSE=VU)!6bI(A9;2@NiR}C z89lkDo`v696RF^8?x|;?taXt|?8rO#Ode@nq=Hi3!K>-Qt2W(h3zoO(Ua45GJx^o` zeK}{Zp`>+@q1;nf(KY?^ejDy}xefPdnML?1{nL1!f8_dHk-qhAEg)}Qmg0|ak=sRt zZN`8wi3zMIBxw`o;)5`mfkKidV88JFqhk*x?g^9mCVEZoIQoPSlVvO`B5X6Zb6$hvK1Y=V%r({nCvyt<*>sB1E%UJ5Dc?*7vMLh^FQTIf)EsDMIu< zb5{0E;BeL=G5wN#zfV)Q@{)+@#oaapudWxOv$#Uoh4&4@C9P2`$v1i}-J;LpY4@DZ zSeJY11}wov(RiO!VjP=_2%Ch3ID@wuOO&vxpp3z+6;0F+@lkY6FeZ9ssJpQL0e1r| UOicd!SpWb407*qoM6N<$f?qgP1poj5 literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Call/start-call.imageset/start-call@2x.png b/Antidote/Images.xcassets/Controllers/Call/start-call.imageset/start-call@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..cbcc46e1866f496d376503bb4326e7a81dffb2ec GIT binary patch literal 1476 zcmV;#1v~nQP)J|)IsyNpnw8X0+ql2ywMB39pMcqlLe4V19{pahft_ zv}2((vKz3T=ae<1g{!lxtcaz`8}b)siBdcaxpP z&S7;L2jvvquMFX5X(vg)v1923O3?oCe7WUKjSyEOQ}C5oGge~v2ywM?fmlOsiIG(=!}wH;8H=%PjI6qe z8gZQ;C8!C!D6biRN{2`XbjS>8qA#Z@_k^iw2zSfhZOsl-(*UO8OL+}hj)S8FHGz}l zU*`P^J4Fd<0*}hybT2PJC_(*3x81`J>;InE>qIu- zM0_Ki*d4GLhVZidPss>Q3DQ(O)3HQ;Q-P|I^ke2k~ zIHAuYcETh)EzXo54Mty^Wh=ZU&XnH`ULH5gG^yxilqpMbbcnKw*&W}DGvyDQ9HOjZ z4iQ^RWd!H;Si_dmp5tTJ>#2SL?RcybXUaNUKhB(|;7q*YzXhZh<5HCuH<*LJ#hKE= zeY*cPPr~Us+tl$Y_UZET`-*d;+;`4H`hP0#+*oH^tw#6ONx4aksVt#*~N(daI-oxYeB|?$uQo{TlD9@ZOYp$~Roj7{Q$?yF2A#@uRQk_&{ZwH7?M6 zQ`V^LX*t{Y?z*ZaK2*_}{JBzL<#BHKPS76}wP000>X1^@s6#OZ}&00006VoOIv0RI60 z0RN!9r;`8x0cuG^K~zYI?bN|eQ$ZBQ@n1{plGIuxrU5s0!%G+t6BaIf0%F|o00bWa zBRqjy61Ie$3pKoe3*&;2u#!NOq8lQMmXx}fAt9Ic-YJ9~Uox4=%sJ;jGiT0luMt!# zSZ`nv)f}61Y~asLAY<6U5q{>_Jw+3<=naEB!|NFIs%9{a7r4lQl<^e@*v+iPtJj98R+?_bC zWo#g7q;2pjV0JZR;z?Z~g zT#x;CA<2gk@EofN{z}40ioSe8oh;x9ehZJHo#2;rUAI-gjIL18ccD5u72(c*;lUk1 fxwjixw?f z{D&C93uF!33!GVI?F%@7A4>?V(thILvO2&9%tQgV67b!QTr-h-*>E=op2FG$d}||D zhC5A2ZemWgsqhW^>TCZC`y*!+4Rg4THDagge4fFngeJN;C7-fY+BNbgakvM#-4gFdQCk*25>oY+>6Ht z;<>V@ZKP=8YhnDf@@9_6i_hbQ{x*5hc%&p(EhC%dCZ_Q*_Ma7wZ7#vH36JDYGm|IH zES}p`Qd2D>!~VScpX2}Sa)ZMqxdw%N(~bX2o`VKUa?oIE9g^Sm?#9FJcjUvqG|`it%N8wKwCEjv10&>|zI#}b`Tzg` M07*qoM6N<$f-(?Vi~s-t literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Call/video-call-30.imageset/Contents.json b/Antidote/Images.xcassets/Controllers/Call/video-call-30.imageset/Contents.json new file mode 100644 index 0000000..eaed03b --- /dev/null +++ b/Antidote/Images.xcassets/Controllers/Call/video-call-30.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "video-call-30.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "video-call-30@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Antidote/Images.xcassets/Controllers/Call/video-call-30.imageset/video-call-30.png b/Antidote/Images.xcassets/Controllers/Call/video-call-30.imageset/video-call-30.png new file mode 100644 index 0000000000000000000000000000000000000000..2e9f952e4403306916c943d61fcf45074a669dc2 GIT binary patch literal 478 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 literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Call/video-call-medium.imageset/Contents.json b/Antidote/Images.xcassets/Controllers/Call/video-call-medium.imageset/Contents.json new file mode 100644 index 0000000..7bbb6e9 --- /dev/null +++ b/Antidote/Images.xcassets/Controllers/Call/video-call-medium.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "video-call-medium.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "video-call-medium@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Antidote/Images.xcassets/Controllers/Call/video-call-medium.imageset/video-call-medium.png b/Antidote/Images.xcassets/Controllers/Call/video-call-medium.imageset/video-call-medium.png new file mode 100644 index 0000000000000000000000000000000000000000..2b54444c0be00ff5a526dfaf0d84a05af0b3c14c GIT binary patch literal 265 zcmeAS@N?(olHy`uVBq!ia0vp^k|4~%1|*NXY)uAIY)RhkE)4%caKYZ?lYt`pJY5_^ zJUZWA-Pq^oDAN8>UR$c`?Vg783lnQacy9*2X7<6Skau$2X(dJ}i-Y*Fm` ztvXpV?bH7vwVA~yD$I*M-gDrUFHc!xaMgm zhfcqEC?BY}_K3B{qRzw^))Va0z8G4H+c-~}As$t<+j8rtbhg3xrfBC1!f2;04%b%|t10AT-hOxdy7f1C~X+yFL6;kU{9JV#YZ-p5JcR~mugb=_UUiX%H^{2wS00000 LNkvXXu0mjfdAFD$ literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Call/video-call.imageset/Contents.json b/Antidote/Images.xcassets/Controllers/Call/video-call.imageset/Contents.json new file mode 100644 index 0000000..2c0b182 --- /dev/null +++ b/Antidote/Images.xcassets/Controllers/Call/video-call.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "video-call.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "video-call@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Antidote/Images.xcassets/Controllers/Call/video-call.imageset/video-call.png b/Antidote/Images.xcassets/Controllers/Call/video-call.imageset/video-call.png new file mode 100644 index 0000000000000000000000000000000000000000..28c9a53ce3a5d28bba92a8ad1369fc92a0c32e4b GIT binary patch literal 365 zcmV-z0h0cSP)rtbhg3xrfBC1!f2;04%b%|t10AT-hOxdy7f1C~X+yFL6;kU{9JV#YZ-p5JcR~mugb=_UUiX%H^{2wS00000 LNkvXXu0mjfdAFD$ literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Call/video-call.imageset/video-call@2x.png b/Antidote/Images.xcassets/Controllers/Call/video-call.imageset/video-call@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..49cf9ef5feb29def1d613918318c2bb5027d5d85 GIT binary patch literal 744 zcmeAS@N?(olHy`uVBq!ia0vp^DImizD-d^Od$6Y4RNh(luIeXdp_urYt z8;cKUCdgS>teiY+L;eA)4?-1OHf(iiwu|+=4@i9|_j+x+A)=~FbOx*3gnEU*SO2d0 zY}&c~u%~aet&ZtMp=oY52Q$~S3Kjbrxfk9&v-iV_uZ@pf&$(=A@IJ87(==y6<%2&h zRa>J)^m9!k?iyP$-C>Gj+@ttERk2D}y|;3Q^8w!nueZhJutgMnx#c18O`*E+^?~KG zRjKhg!K=7*9~gZo3z&b0JJ)M!>9j|WXD+NQ(%+&v^%c*DoH=$o#cxfKy3YAP@I(3? z2`#1)xSH<4*DyzphExS&Q)M_ueP;6+IysGYHivt zli>C5^24V$mdX0^q?p`oykfLHOqM;=ikb76LzCfz1RfO$a+#jngN{4$s@(N_!1iI| zE9U3_)_+e;gO zm|Me9xApqTe04J#XP;lg0t}xj+ixe_FK@OD=B@|~-hB5-rSI{(EP2ewx7Yn++Tr$Z z|A7~!s);u=Zw2Hu?Tq@|G%MzPLv7|~-|Z2fmXsIA>Ka}Ty5q5P`@1Q#GCVg+ocgxQ zd*gi1GH##m$4;$I+2ixII_9WML1WVXTbD)VC%k)hJao;+|AnId9N%_uA*Gr}@(U*= VD878;)d5Vp44$rjF6*2UngHCnO&$OM literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Chat/Contents.json b/Antidote/Images.xcassets/Controllers/Chat/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/Antidote/Images.xcassets/Controllers/Chat/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-camera.imageset/Contents.json b/Antidote/Images.xcassets/Controllers/Chat/chat-camera.imageset/Contents.json new file mode 100644 index 0000000..dd672cc --- /dev/null +++ b/Antidote/Images.xcassets/Controllers/Chat/chat-camera.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "chat-camera.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "chat-camera@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-camera.imageset/chat-camera.png b/Antidote/Images.xcassets/Controllers/Chat/chat-camera.imageset/chat-camera.png new file mode 100644 index 0000000000000000000000000000000000000000..38f64f27dc96c1515d21ce0495e4fcffc5df8081 GIT binary patch literal 523 zcmV+m0`&cfP)P000>X1^@s6#OZ}&00006VoOIv0RI60 z0RN!9r;`8x0l-N_K~zYI?bNwzRY4TT@z0A(WdgVj;#cg3)MOgcE2g#c0B=3JUqOt-=-IkB5caFTw5z zIf<8<{Y67*;Sna#9p{_liTklJevb=xwE=^8fK3^QGUQk83*lG$aV(yG6bG>khwvO@ z=*0jQKQ|3ASMf#}huixPuNno(ZHTq@aeDgii~; zpwaKuIRz=-NnMnKyudo4;<^()J$Q)qLLnrTO4m7D$5!c!AB*EHoXN#cK^ldg)q?~0 zh}*an$13(?FJ4QRa27&%WFOEcbmSxP#E0YjG~NpjHKpQj+R92?#u}lmRIwC$@D!(n z{x>Vgbl46w3r%xGzGqEA;A`Ai4>e zkY6yv3#rB}0YXd;Z^Zq+w3UUwi#@q|>3!+$O?y<kbA6CP_~h$B>G+CsS&@ZwE*mJ)e8a#O&gh%(b5JmqNN{^V~oG{Xa*O z!@)i!$wjAFyqEWE$tx3do_yyW)1&$G1P=W?`0!cfC!2%Mr%m`Hp6K}`)9_TY)4g|l zPjE))R|jzK{%vD%X7OR>cki86E>4~|=hTNUEyvv>71-=g@4fO*%=yHxZ7Y^MJHAHK zY}0bL#~iDT*xZiQ9#<Rd|**x*i2lt9Y z#`E%niiB@VxSgsM>`?eH!Ihsg#Py%rb*&(`D?x5soF>tV;%WKB|y|LVPQ+q zwv!us7cT6XQSoK*g{znRSME%FVt?q*g9A^j%_PgRir?0)-VmxK;`Q-y-0bUChdHk- zKaghHa4%s|Ti*gN=~Ej+*3Gc`)aQEcbll>nYxiH<^e!@HGviUE<+H-__UoNpJ0rC%f3xHHI2jlcH9F*G?6kb|L}^Vulh+zfR)hPB6~EqH>rYy&p(er9e6!_4#D$8^ hIbTAXo}Qe%kNMlaX}2!!vib;0WuC5nF6*2UngDD;L0bR- literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-delivered-checkmark.imageset/Contents.json b/Antidote/Images.xcassets/Controllers/Chat/chat-delivered-checkmark.imageset/Contents.json new file mode 100644 index 0000000..5f301cc --- /dev/null +++ b/Antidote/Images.xcassets/Controllers/Chat/chat-delivered-checkmark.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "chat-delivered-checkmark.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "chat-delivered-checkmark@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-delivered-checkmark.imageset/chat-delivered-checkmark.png b/Antidote/Images.xcassets/Controllers/Chat/chat-delivered-checkmark.imageset/chat-delivered-checkmark.png new file mode 100644 index 0000000000000000000000000000000000000000..731de1be96f76f2670444fc99a71b9828d043261 GIT binary patch literal 436 zcmeAS@N?(olHy`uVBq!ia0vp@Ak4u6ByT*@`3|I5(j9#r85lP9bN@+X1@aY=J%W50 z7^>757#dm_7=8hT8eT9klo~KFyh>nTu$sZZAYL$MSD+10f+@+{-G$+Qd;gjJKptm- zM`SSr1KS%AW|S+nFa-*-mw5WRvOi?x7c&$+{v;h_T$87ZV~E7%xfg7?9ScR+9~^(J zWTcUrWRS2!zVWDR>X*n!o*KrbCE}A$B)PINZ(sL^-STmz-}2Aae}Y>Rwy%FSiQmEb z%_;MzN6q*YyF%8+8$U4$FgGdpUYWe)%d(9}?Cze4yd5IR?0fpn$8u}iiIY29AE&Qt zcR79LnwH4s6{|lzUOexSmT3OU8TmlRFsPQeMwFx^mZVxG7o`Fz1|tJQb6o>NT_eK~ zLnA8#11l2)Z39Cfqj>XOWfTp$`6-!cm2eG)rXfZ~RwkBKMurd#S3mHALP-*2LvVgt pNqJ&XDnogBxn5>oc5!lIL8@MUQTpt6Hc}vWc)I$ztaD0e0swfxkIeu8 literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-delivered-checkmark.imageset/chat-delivered-checkmark@2x.png b/Antidote/Images.xcassets/Controllers/Chat/chat-delivered-checkmark.imageset/chat-delivered-checkmark@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a5ef6fa36e5583501a55b29e63dc03db454c977b GIT binary patch literal 418 zcmeAS@N?(olHy`uVBq!ia0vp^k|4~%1|*NXY)uAIEX7WqAsj$Z!;#Vf4nJ zu)P6cM!8Z8Q;?1l*NBqf{Irtt#G+J&^73-M%)IR4Y>&#%=X)O^oy}!j6@QRbF5tN2x?^%* z=S(i?2`>qd7oSw+X*4zH){%6VEyc174yU*^7w!Lfod1$}k*~l9qtm}FfZ@sD>FVdQ I&MBb@0FUjTaR2}S literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-cancel.imageset/Contents.json b/Antidote/Images.xcassets/Controllers/Chat/chat-file-cancel.imageset/Contents.json new file mode 100644 index 0000000..7168d6c --- /dev/null +++ b/Antidote/Images.xcassets/Controllers/Chat/chat-file-cancel.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "chat-file-cancel.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "chat-file-cancel@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-cancel.imageset/chat-file-cancel.png b/Antidote/Images.xcassets/Controllers/Chat/chat-file-cancel.imageset/chat-file-cancel.png new file mode 100644 index 0000000000000000000000000000000000000000..5029a46a949d18234a4bffad620b2f9d5bcd4617 GIT binary patch literal 535 zcmV+y0_gpTP)P000>X1^@s6#OZ}&00006VoOIv0RI60 z0RN!9r;`8x0nAB6K~zYIz1GW46+sXN;LqEbfZ--9b#WA*!Ne$da!gE&Z{UTU-~+hO zCosm#T73mIgbg7s*mzm^0)mQ>pbIY``UEbzhfF5ZrzaBmHgr(^u&1SN z7-w-5qxgldc!l3N<9(U+E*{|lj$knICvYM1U94lR<%YL0hIxFz6$~VF1GtKhm=m&W zg_C%XyExF&rocU{U?L|TivecZ?x==YEMugfXkN%*C%BL2sl~2PgX$;Ri%!Pr@tRG6 zRZKOB7je19P2dN5i2%L0Ua!M7EY!ur*wWlZllX@74gB{8Ui7o2R+~#gCMlFV?j_!v z@B$aB#0(zyF{nDe)gk~q!F57m;V?EbMoU8H+=}Ly#-?z&b#MxAgemYc<)rQ3$`H=rSPZa;K3>LZ2T=D#Oea}0!nD=uH z)l^=`Wt_C~zSLbdXJYF2^72_f&23*E5WRZk<;@RIQYy+;WeLi#MBCo#OP*5q&*NU* z!v;4QBlFuQe;)nxsi?AW-j>;C67L)cU-Ifh=yvtB>3iRamQQI3uRl;_(w1y<$>zo3 z$5F)wjn`EYYTvSK59Uk%aY^UN%eTuPH9qH-*)ZdC^Ie~xANknt+J3rntNFR#LzCil zZ!TYd$W*_Tqg0;t1mpRF7D;{;t}bR7)r3%<-oAMcG=%SJzVkbyER%V}P$8hcevwhc zT23*q@Tm`9?&Vu>GkrnjJre9y_qfUeA={-m&P01xuL@-aZiCu)yGns*K8y zfAd%mZhW$^;vl!ou_sZ_j~&=(ulM1+3%9OCN6EZwC5vyzk801eb)A)K7Wpc3-bbx+ zgMEi2ME|6}vgW=v~1T5RZg^78Y>uRXtYYCP@i m?rZzsS@}RA@!OppMTbPgKTZ=nAh*m0q{Y+K&t;ucLK6V`TPrRA literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-download-big.imageset/Contents.json b/Antidote/Images.xcassets/Controllers/Chat/chat-file-download-big.imageset/Contents.json new file mode 100644 index 0000000..51aee17 --- /dev/null +++ b/Antidote/Images.xcassets/Controllers/Chat/chat-file-download-big.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "chat-file-download-big.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "chat-file-download-big@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-download-big.imageset/chat-file-download-big.png b/Antidote/Images.xcassets/Controllers/Chat/chat-file-download-big.imageset/chat-file-download-big.png new file mode 100644 index 0000000000000000000000000000000000000000..717aa6aa74935da63502fe95ba872758e5160752 GIT binary patch literal 1181 zcmV;O1Y-M%P)+@LzX#Bg$^8(%Py`;}ES#xG3d9Diws(Aue3e z#wlD=QSMX-aVKc_59)B`f=Ha2Hj+|RJ)uHNm9{9gX-iw5i}j9~z4IMs=G)toO!hbP zuC?Ch$;@7}-t`Xs$2xpG4)avPAWrRI(@00BIFoB()FY+i34(ipWyU1KHUg;r(m~V2pX(PwiV99`oe@;a62Y-@askhT#Jnb`;AyomTW6L zfIrg&-{Phoe7hBr;bwf7eEz`wJ@~f8ssfo;F|$YiUWLGPyj<{orbqu#7{E&@(BD{5 zGENyG8ScXIKSWNfFoE|k_gp=z%4kMVm#lg^L=s=ODd3{x)4|@7jt*FPFLVq za=ND?0qPL~%Tt_VSlr3@6nvE&o~vPU>JtJlq*%KI*OquJ8E(atnkKJP$P{c(@m94m zItL@kXlYFoQ?C%XCdC`UoMr}DmU^YeNvU55yskwSI}L~N4=$>C(tZfJIK}+Um?HDu zG_bBj(9NRm8g4P(PRKAm6LnRu*q})|{xDs3#k3MKoO~Miw8XqClJAD> z!gQPv`MJ{~sTqc`Q)@BJgcL>WY~s@mrs6NbeF$z$0oRuZmSHxwr8r+2olV9HIZK{G zztAG{bcyUqx*ncPCr?)hNNX`gA!9|HU2)E5Q>@kSW;(gGVo*jC%^tH%Nbzyno@}e) zwiNFz*pyB#t06FPXNqDPV}5VfevRJ?E|>qG*_}?#ttmL8AG6}IO?@JW<#z+Wke4Ox z8VF@DOVn(|J5nY)wZk-dMf~3itga%lh)m4Z^t*0Mk*{F=noiE>!$gFDeuyCY2Mrt= z5Dhls#n=!0l#YI2M*4erK(u$@{60%f`f1=|pXn|MAEo&2L-oBx^b9! zs3Df-U2piz6kEm(kxJaznTBYlQA`5NCdm@pHR3-2);YVAiFS(k=00000NkvXXu0mjfJ=i*M literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-download-big.imageset/chat-file-download-big@2x.png b/Antidote/Images.xcassets/Controllers/Chat/chat-file-download-big.imageset/chat-file-download-big@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..065c39fdaef5e429108485c66c4be7513d445029 GIT binary patch literal 2394 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 M07*qoM6N<$f=aq+bN~PV literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-download.imageset/Contents.json b/Antidote/Images.xcassets/Controllers/Chat/chat-file-download.imageset/Contents.json new file mode 100644 index 0000000..c00be9f --- /dev/null +++ b/Antidote/Images.xcassets/Controllers/Chat/chat-file-download.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "chat-file-download.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "chat-file-download@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-download.imageset/chat-file-download.png b/Antidote/Images.xcassets/Controllers/Chat/chat-file-download.imageset/chat-file-download.png new file mode 100644 index 0000000000000000000000000000000000000000..d30055080e5af4a9bb916f78fb85218834ae80de GIT binary patch literal 526 zcmV+p0`dKcP)P000>X1^@s6#OZ}&00006VoOIv0RI60 z0RN!9r;`8x0mDf|K~zYIwbosWO;H#J@ZXtXh${-yk(VotxRZnnGbfaik_#cBd;mI^ zUh*B}3&;%#x8g=#l1YjZQC^yiIm)FPH^;?#&N!XU-g})f{_|AB`%L|Wq+B|GOlF(%b}u7*wAUf_^>IM@AQ zDc(z`;X>df-eE~^$7X4IyZ$j?cleAI5%vY)=sW|CN%h@ZMcj&yxQ-2(<{NPXAFw5N zM9Zbqt%aM?O=O+F=l)`>muh$`co#!AFjnF;?n>wXEPh5ig*(!nU`3h9AE&@t8g<4! Q;{X5v07*qoM6N<$g7JIs6#xJL literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-download.imageset/chat-file-download@2x.png b/Antidote/Images.xcassets/Controllers/Chat/chat-file-download.imageset/chat-file-download@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..4b58f3c6aedb8266f3291977b6e8803fd4774265 GIT binary patch literal 1246 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*_=3?wxlRx~p(Fg67Egt-3y{~sta3I-|!dZJ!` z2HIU;666=mAaVWk&wpHu{NGlwAARVz{IA-FVudb4spfMsfxA7Jo^PM( z#r#*dvQ<8ICZ?=EJmmym40CMw^sC2p?E?;)K9J^7KY#zMrZ7bDlobeS_DQ#cR#&+9p@4uR1PwwyZnysekRvS?+rKCdV=`F!g!5IEGZj z^;|sY740a|_OM*-ctwz@lAxcNZf2nC;;zoEN?jeZ%{V;nygW5K!`u58<4e;D%U%4T zvDpWrUwA1r2tHwHKdf@bc=pXbpZ^>1eEw_RXg6Wfhr^Ff>Cfbnw71uNDw(!?i_+fH zem@o0PAU5kWk2m)cZzV=^GhGCxf_R{5DKR0zg z4lvdEZu9VjX-^_U@;)gU|2xT#Up$j?Uw*eLyC-w&|A#yFbte7GkQYC8N@@aIxcKiX z|48W{QYXVVEG!Z+Zsz{ACHig2>N1o^nUe2 z>VxQ&om<-U_AUE+MfK0823MpbCH+w_8x zNM*^>z5+Q)=F=R4)mf|qg@0Ey-8|UIDYE?iev_#8S{%%dA`Vk`tnzSBj_hFLws%=` z#A`#afz%n{PiimUuU|1gJv&v=BSg`E^1DrMBHJP*(z;_~Hy!>atMRh;b!TD!1^-*l ztK3!I?0KLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z0002ONklAm93YHpUE>~+zd7&>DJh2($WBBFyI%xY3>>k4`3 zA^`#f2oNBD$uo1fl+uDnH{09bew9=s1#GvJ#CCW|a&Wbs`z=}{^Df&rZLKbA_gy6| ziTiI!efzzpUo+cUKiVeJS}jxmHmwB&2oNAZfB*pk1PBlyK!5-Na%!gMT7&UvO_r#M z5$t&o9T}#5vnV&vqqRm^gXgy7{^1ng)ZfZyh))PHGvmKH>EKpnn^roq^#)?(de~&ksMl?XUd$Z^GmG z?Z$o+Bpj3KxXtc=f&h+7<5>k6pGz< eIo03f$i*PAm_z1~)x1!kISihzelF{r5}E)$e=Gz5 literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-pause.imageset/chat-file-pause@2x.png b/Antidote/Images.xcassets/Controllers/Chat/chat-file-pause.imageset/chat-file-pause@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..60c149bfe90229b165d1caa8c1cc913c426aec4c GIT binary patch literal 2967 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 B?2-Tg literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-play-big.imageset/chat-file-play-big@2x.png b/Antidote/Images.xcassets/Controllers/Chat/chat-file-play-big.imageset/chat-file-play-big@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..afa50eae3f74df00c4924aa9e0c18c130f9dc00c GIT binary patch literal 815 zcmV+~1JL}5P)fQP{8h;wbiP$1?i@WQj5jkmzfC^K!uxNDHVp*a z>F+-9!}D`$`+zfZ+n-=cAOH*C0q(5J7s@Z-F|ZS2 zvMrbzh&hkzC&!+Bs_l;uDiCuWctP4afJF=lb)Up%lFSJ^AV*Lfz3tbW$T70$aL{17qF9l0LEju%6 t*_lzx&Wu`iX7u`Q5fKp)5fKro#6MbSOm0{bf1m&W002ovPDHLkV1g73Xnp_y literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-play.imageset/Contents.json b/Antidote/Images.xcassets/Controllers/Chat/chat-file-play.imageset/Contents.json new file mode 100644 index 0000000..35d6ca4 --- /dev/null +++ b/Antidote/Images.xcassets/Controllers/Chat/chat-file-play.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "chat-file-play.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "chat-file-play@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-play.imageset/chat-file-play.png b/Antidote/Images.xcassets/Controllers/Chat/chat-file-play.imageset/chat-file-play.png new file mode 100644 index 0000000000000000000000000000000000000000..71ea45a3d971b05aa5a7b18e2c4c0c095ed37281 GIT binary patch literal 276 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 B?2-Tg literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-retry.imageset/Contents.json b/Antidote/Images.xcassets/Controllers/Chat/chat-file-retry.imageset/Contents.json new file mode 100644 index 0000000..0c4890f --- /dev/null +++ b/Antidote/Images.xcassets/Controllers/Chat/chat-file-retry.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "chat-file-retry.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "chat-file-retry@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-retry.imageset/chat-file-retry.png b/Antidote/Images.xcassets/Controllers/Chat/chat-file-retry.imageset/chat-file-retry.png new file mode 100644 index 0000000000000000000000000000000000000000..18b07b3e0637ef6b5eadb6ca77ddc4996e82f446 GIT binary patch literal 477 zcmV<30V4j1P)P000>X1^@s6#OZ}&00006VoOIv0RI60 z0RN!9r;`8x0g_2XK~zYI#nwG*R6!KR@!uw(jbuSg;YvP3x{x9XVpa&Oz5MPQjySXfGcJF2|4-9u^m^uG5Gk4Az{(~w5 z%=w5>e8xH&c#Gc|{W6S;n81C!#}4YpOyaDG7iB+)RKc-5{579k=jv00{iTZQM{eqoKlg8F%qxKtN0TxQE9r`z^?1 zs;{Q@msAGTs@S$Ejt=M!w#5G~)wfOnA@0&RUbi|n#AwPd%gL!8YF zIg{+R5B?j@XNHX8YZ21KSZ2tW2%>GsI<97hT*I4U$Bc-kxl|D;VY;((TSU_wS`bcm z#zu7!u18J?sA3OSx(!&u3w`8-E*i!wJnc28A@V}CB%qoA4SgoAWqiVXAI2*pJ?x1U zl-h;5$lV|CK*XY&xXHEDeklH;ZOk6$MK3R>MaG-KC0r0Ux#{S&@=m-9PEUUU(>_e- Tg`~*M00000NkvXXu0mjfXfM)5 literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-retry.imageset/chat-file-retry@2x.png b/Antidote/Images.xcassets/Controllers/Chat/chat-file-retry.imageset/chat-file-retry@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..c033cf094a14c06b0c9580d9910704780ef1c278 GIT binary patch literal 781 zcmV+o1M>WdP)Vi|K~!jg?U~PO6G0TmKQ<&ajXzF_N3p#KqV*yk)Pp~we}dJkwieHd z{v{&zF8U{Us0ULl6j7wsTBD-%rg&+jp&qgx-Ww*Yaktr-*^2B3mVwOd_r13>JNxDZ z3JMAe3jR}Cz%Sqj@CtYc+yo|e(y1)8faovRbKoja+9?O(R~luY4x9j{ky+X3yZ;?< z(Xaa!pMeZw47dio@6(wBs!m=HL7hK?bfFB~0yb6a1<-KROr;JitHE{r1Y$Ufot-rT z1~UpQs-a~yf-JLpYTy(0Y55KW)o!cq1JBxA0D3?dnC$yKL?9r`%)B#A zU!o(x8x_49>kAbKz-`rD#nX3Y3cI8#vA&Rjl(9?fiVwkODmF8qFJvG9*HwSPRp=1% zZfpR12K2Y|3PnwA_tcln%py+k9FeKegTG$Cpg( z*S3>1C@qk$+B)swj*M%&o-`;ekhj_%cXlT`CP`gQ8k81@Ne#|AyOW)B+B#(r6WA1G z%+;d|)R1?>IYj{}*+fX8AaADelr)0Wog(BsUG^ckO)9_#wSC!#U8chLHy&PY> z;BJ~cd&iC`TwS6%U*ZEcnNHzrG6^V{)}*mz$BPV&ri5+Dca}I#wOA+JvuqV-vlidCKGvvJYBIggb{$@@^i`V4bz8N%^2iMl zdeUyE*A%+@v)q&M8P+widWYurZRQ%-;FcHF5m+?;HB-C)_1$#;uZ ztWG}~W*fHU@}5PTCgmp}Mys zfp@u#`Pz%zWkCm(y4-9xrev4pbbrnYGe|jN_&vr)%l}!C8<`)MX5lF!N|bST-U%**T^u$(8$Wb+{(yM+rZGuz~E!~kxUc~x%nxXX_asd dhNdA#Mph=4a1B>K@PZNxgQu&X%Q~loCIFL%5ZnL& literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-7zip.imageset/chat-file-type-7zip@2x.png b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-7zip.imageset/chat-file-type-7zip@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..2a82a52ab0f9853b8200f02656a05a67faf884b7 GIT binary patch literal 717 zcmeAS@N?(olHy`uVBq!ia0vp^-XP4u3?%s{blm__Hv)V@T>t<74`dEMaLnFV0q86D zk|4iehIvdAE@U_`2L7E|@Vn`_*6zd&lHd9I-}>igt>J!l-rZyNdv=Mh`#3(#xoH;W zsQhd7=BGkl2F6%V7srr_xHVTD`5F{>Tmlv5 z@t(`!Z(nz&e|Fc;lB=92PnWprp6~f&8JPa<&Z+*F;nACIzU}(xv+&@|P2y+GA{m#h zyI~d*{?z`&-{c6#jNZ^Ew3I$vRkc^o{eKUv1aDc5CD{mfv*P%HMT( zLa6r42W$EIlB9PP&6}_#YAv_d!ecqHW#@%I3+u%@eZMu+jG=9{n!WS2-g`0;I=lA@ zZwxcKY5GFnqjk*|Eyiqbx!sPZi^Z2b_0vkp{jx;)hK|JCRx_2G(;8Bi#agGnuBci4 zU^VmCE9-3ij^*d12u(P${Vt2enfrZrq#i#B%X?aX=I{TTKbYs;$x2fEx1I%*B0XLG KT-G@yGywp6I^+8Q literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-aac.imageset/Contents.json b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-aac.imageset/Contents.json new file mode 100644 index 0000000..3a7789d --- /dev/null +++ b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-aac.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "chat-file-type-aac.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "chat-file-type-aac@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-aac.imageset/chat-file-type-aac.png b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-aac.imageset/chat-file-type-aac.png new file mode 100644 index 0000000000000000000000000000000000000000..6b6cd605d8196ec504fa0c343802083367ef477a GIT binary patch literal 803 zcmeAS@N?(olHy`uVBq!ia0vp^Y9P$P0wkGC6jgx~OS+@4BLl<6e(pbstU$g(vPY0F z149*1VM7Z8!!Mvv!wUw6QUeBtR|yOZRx=nF#0%!^3bX-AFeQ1ryDH=O_J@r8Vuqr}pQHngWBlmp;uzv_{Oz^#-d7wYj(@zq z%ljXLXAoC(q@2@seXXPqkhYC+kA4nCQz#!-tZ-#l+{rQKL zE*;~2aiX7_y?INa_~*xm4zpB;bLj|#OZ99qtc~h<@+e7>LDG8e#8Z8Xo|Q;mOjfkX zi9Pf}f7*L9nc|wuyGkRDEm(NJDYwMAQZw<~^NqDr|5<97GFE==KhPw+!FhW5vIC6n zwg&wjX>+ID-70o$GhaB*3Z}d3Ua_g)x%7O=se*Z?zgM{Jot_kBdtGbQxdpDab`ku= zX@+mprgSGy-{Hxdr7Bx=Sv%V(G2ynVZ)B-Jbx6e$r^P#X^AD>p2wWR_I%>b=vTV{r&mK&_mIZ$;&c<(yzj4N-p*_CgJ`f@C@`s$PQ>wYFq zwK`Lk6SdW^FgVTE+e7kF+Mx}v*0#?qyUFxy&i7lY#yg&Ot0vFO{CaQuq2=Lg7CjHY z)b;OB;=ckpFCl;kLl$V$5W#(lUCnpx9>g5-u&wghk1ysb~ M>FVdQ&MBb@0QTKT00000 literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-aac.imageset/chat-file-type-aac@2x.png b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-aac.imageset/chat-file-type-aac@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..656cb3f8de8ec687c436e8f0d5f13e9254c7324a GIT binary patch literal 1211 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 B9wh(( literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-canceled.imageset/chat-file-type-canceled@2x.png b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-canceled.imageset/chat-file-type-canceled@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..5d9954e1d04ddd000933bba595223e63c91a9722 GIT binary patch literal 748 zcmV002t}1ONa4l1H*(0008BNklHGsA|WIQ7U~~jYoQQQDwqbUTz z!p6c_CxyL@iI`lxQ#a-?x3fD!nkin`ac^((PBGuV;KRcM&pS+}>X1tgo283hvSIf0 z>|{@S!vkhdhyaBf3ey(s7vx@$S@GA-v(_B(>y%R*JK&;2$URRCGyAk$bJet!3Y0M{ z{ciDxZ*AR$owuhwtUF%wz9NDpW@T!A9`J>_k`G|w9O-EL#`$gC9jjw?td2EjpIxRc*lTxltlTM=;(tK?@f)rih-2PaKYFJ* z)`O0E%t>$Rt72f;IVY?UqpUjP3C{&h^{4MWF1Lu&2C6Q*48$l)b{YAuIac9y^A=+m z6H%ovyb?6mz-b~_9qMz-)&oglF>1*=fz+@VMIbROMj?;@R)Zpt0yY^%APsC1ia-+B ziXuWKVX0t_>DhEVLM35Uu;7?dUZK*m7+BHsq8_;5q>Xkw0}GouzO8g_;ZtX;5{r zn3Y@bub%C7+n^p*4~tp*eQhYSoif)fyHba$hsCVm5!>%kPr6cvs)q$tBWvz6w*4~K z{ZxahhmEZURW}?lr<{rPx3%hH-?F(FRS(nGSbP1fH1es3{NMWCHB{QtSaUv9`o@B3 e+T$}LKl}$*7(|<&hs)~#0000H=O_J@r8Vuqr}pQHngWBldm;uzv_{OvVwk1K&9$3LDo z3AQtv>Th&v!V(Uq*smKFWCS{`7Kn1$k|C(#=q9<1YmsYY_aVg%J*Ui^c8g8wR_e-8 zWphka^hgx>rZ7imPT{Q=DJI6}>Z3%iyw7`Q`Tf)0=XZ+rV$!ZCSw4TU-A&9jX!C>} zddW_bWo;&r@Ao*z%?fs}*=BXR>O^k*p6koaE>Ej0ozuehLD>o+4P zar4*e$UNT_eK~LnA8#b1Nf5Z39Cq1A~v{M>0_~ zgqzn%T}+^y>MyU*EO z@8tOUWX|gRuI04{yaa#B{60{dB)@?(i}jnu^F`bDc5GPC-taerS3ppFk>b~or$HB9 zeRsE3?Y7#a)n#?4iz|D+)^TPvrBZVTt!U+c0<-g&FR5|cLTnur5l%-U=lf(~-=t|{5z#H6jdCg6YHa$pu<^a8!jEr zQrqyJDQt5?t@(yojA!-)-IBiYL_Z+v@9VBz$G;xQo*nXd$#)%X^U&Tet5;|*wOw>* zPMf0JmeMWDCZ+~7;YDBe^Uf{)+wk##!h=~ITS`}zAK*w3DTsD?_w0!zM-L+#^K_Rb zwi$;N?>&+?V7S3s^5N~H+e%Mo^4q)#`OlFNIPc#9u?KrU)iCk3#|88-asS}nagEa{ zRr;Z=chRf(MPWvb$(H+=QyWVoo?5VX+Fv1__HR-|N2L{zX zHfYUjJfQvlCr=J@T}P=@Tbrrl(QA968I>E^PyJ_+h&{Spte(_)P+nGP}Jlx)3zRzY!+xtyg{}WH-hxJrm(+j=#WX|us2Y38D;J>eCaa;aI zt@yL0rj7^Yc|HoCsXj2j?s{$l{|AO2{5SY|Sj!mFPgvP7M{x15+A#&YJn1UV(=|Bv z`_@SZU6x-=<_(=npDtc7i{9@P_aO97#)Ez57H|9C7;0I{v?jRn+_Q=}Mq#J>yo=XN z={ljCz_mesh0Zh1n;pNW=1h@gpZ9wg-vc3oXcx29A?Xd>4(;{-nJhfaD)-8*W1m^| z^l6+p^}bSA2xTlmtoQQA*vi oEz|#=zqG|BhRJ_t3* z{@TGBySrrK5rt-!*8#Fh9iNtLZ}L!jv1+-ERK&(59f}jfGMqe1MwmUoD zTI9WDAEdUpw{@s_3l?s#74W=l{HTS^e6C^MVT<&8>v+B^ zSLx3B8sNK2&r;f6RdT0W>5A)f`?#A0uP=_>n`d1o-|g|@VqScfo(vnO?YZU84kceY zuP3deJ6+c8P;Bn2lC{qlDK;DkQ$IR+Ys}%k7ndG|R^)h2eJ39krepo)Mbzu{$&Gy1 z>%Gc$TXSvl{G8ggjkWXr)Esez)IZ7*%UD-jOo-dB#GY%mAZlLS&sk?Gl{lJBUry0a zyQBL1Y*fh!M*pcVO3ptvFxD==xFzhpY1WmT1B-%=hiHUksl?3Mnzgl}_q@=y8Ji#N zWD4y%TP?_UTkRFE#I@(En6~>=r7t(Se6Q{Br>AT7J@U8G+5KiQyV{$uoFhT69A9ob z#-kN}db6HHVN8O@TrTIZLy3!*%?VoT(&?4@Nrh$J%D^<8vop42`t5w!71u0hnLF9$ zxaN$J5chZ}$_ZWJ29qCC5TAf<_aN~{{5^JpaYA&if|Jf`5tNsmt^6T%B3pY#l zEnKM-u+BhKtRw4OmeWc3ALg$;XT6@sGVv`iIjEMnMwFx^mZVxG7o`Fz1|tJQb6o>N zT_eK~LnA8#b1Nf5Z39Cq1A~v{M>0_~1QB*-tAVIC9X9~NeVe_x&D<(`VM{W6mHp!IR*1-=~9mFf>86f~x~Uk~x--qp;T zSDSxM=xxT&`rc2gTwfeHw(0!lbpL(I{2h;_TcR$tX`5N?P+E65G-dLNYR!T#6W`DL zmQ*}@`yrK=_h0*pf9~IZytS#vul$PFG{LjKvsD+}{d+U!stD&#_oFfl3``N8E{-7; zac{1j_YMhUIQsGZZ^QhYD^ltQlh~qdJv2lO%pF}k#YFuA95VwhH*J^bH4>?q(hQ|9o! z#__}5N5p7Lo>oNEj5`{K(z-UxRLhv-bNrN-&ut@>Wx1?Em$#~jCB00(bm{n#rTw1X z@{_08sp;1Gl-2r#)%uv#`iRx~ME#nv<%^;8RE}-z5~p6}Pq|UQCEz}XQp(nU$5ws4 z9e4%l#T*uGKBy?v8^>@%xc8do{kPxpuPc6RaN92J79F=Vy6r5(oyRs+%eNU$ z^7+necy8LR#xu{08XMCRu=Ya-hAoqdIXeZIW?nP97{;DZ z+R-e%OW=6J-A5n3t#>lN_54OOi^ZpTu?!oO{dux}M+W@q*POxlAkuoN9>cQ9I)_pV zMAw?WJHy=Ie*X1khBHN42aSAIMqcB7Rm-qK{_(XCDFxobYm%BPBeyaiF+a8ZP;#E1 z3G?I&2fe>7PLr$*Gdun2Hb0Nvk%XVh+pZqQ-i*p|K$DX=y{P2Bs#vQv^E^zH=O_J@r8Vuqr}pQHngWBlRi;uzv_{OvVw579sgh6njy z(mbYoY0)^NqIu|5R*=}*s4t6JyQgjKa8T?p@|s|_mRY>DJk&9R{FeEz3BaYj$nOUw0Uv(E}`Tp5;dr_{NL zN153@B&)z{yXE6G=grO**%zE&k@$UTiqs_I@6pSYu5*8VBs6n}hQ#ApS3A9Le0UzA zurzY+rUE@FHqEo=+KVq5&P<=qJ8j}=KINsJYjvfT7jNWnxTSTx$3J!FJnID)J#8;; zT+gMN_QmH%+WzLrdp{q)^eXmO?#82e5i`yj-EaBQ>+#oXldeO?ALWP&#-flL8CQ(= za!gruVeMgwX}6PChW-6~RBT7aYQ{O&mIXPTNfN)a>6++mmD2Xaho^atY*}ISW)72S zo6NOkQH@!J>LHafx#usj-3ipvd)K+d%=OgUtB)4?A6q1za6!mbtg^fOlW642t(`uH z(~lo=BP$b2xQ44ActL4X5@bVgep*R+Vo@qXd3m{BW?pu2a$-TMUVc&f T>~}U&Kt&9mu6{1-oD!MQ zi{QkFjvES&Ivk3Mf(ng{E(s4JzUW$Nt=+|6n(w>yx3AXsYdfERvHd=|xO&y<)yF$I z-aeU={a(c1`GA$+Pl@VBZf`ifFDPs{Y$&(-%z-Dds5C_VLU#JPH|57+wlvYY+3 ze8%)Si}&>Hs)o(??3j2~Yz)5lPe5Y%8+FkMou~HsKi#_O@}7O^v4Q`kx=vUp?6!Z) zD8_8@d>QlSy?=Lf>%7E&a@9$FICT5`;(2ikIei+YAGm+- z+5*myhTjhTpX^tEx+U_M%Z_c$?gI=Pgmy5etlw(ze1BZ;Tm~^_=TqBspYQj1&iZCy z^;ou7=Jg+WHsE+aJw;4 z{yUci&!0en%`6sNHtd^nYc!7RYOVvIoW;k~y189BJy)I-dFm9n zSVMdYchUB%D*PL_ReO1Ly-o5u>Gg0Dx0;LGCXrh$I{dw#HneZs%08#~U*4MyW#`T{ zb9bG8|Lphge|3B7=f8iy@c(?nx58;T-*pW;7oF4)D302$aQ4grF>Tq+(aU>oiMuo>o>{FDy1==a%lBo$&I28pfyPFS zer{6>tA#gyp3^wD{LFOCBIif;)<5MOy#6Y0=wvrIpVcaqr@1ZWNU{H!4aa2V*Is?U zGW40mm1nVOH@MDPeSICY^cMG1zRH&^vQ<~Amz~tK?WzfR>$}W|xj8GhBz$67wC$$g zn>#)-9e*2?=xSCiCS|CiHsQkiW=$^jE5Ylo|2~sybk_6ktD{qH<;)GMeQamE&`R}O z<&56V>+^Ok@z0oO8zt*$_s;Nc`Q50gH!Y+~9d|o~wCC$vHqvZ*j^)x`yAolpGsmPYozwcDxIwD*zS?g^6D zmbr=e+g#5QsVR<_Et&V)xc&@KxvDX|B_@u35cz z)5i?mp2t6y-;ON5ez*3fN%?oZ@AvLjmoL@nbQ4TuVp%1a)e`sp{*ona3PMW)T^-*C zs_s=>J0)PN*;|jGmmd7L4J*$v+&s=0fA09_$G`u~TmLLQC*fm_$ z#li)QtEZg)=gAx>XyMd;`*q6a*;n?h7rrg4bFS#yc8{g3H-6aU6&#!YK6^%l8tv1&vzd39szl&p0me&hukP_Tc#;7FdQy=zOpZDwxix9>W zN5gpZ3bpC}1coF{A#bnyeo;7D$9)7Fl;9z(-&w75qQe_FAPh4+h z=Po)BYk%qgQUy=_rpNEhzb#9RjSRmwwNz6@ux7Tg9b?YIRqNjvOi2JGdQVqBmvv4F FO#toMR}cUI literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-exe.imageset/Contents.json b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-exe.imageset/Contents.json new file mode 100644 index 0000000..63ff7e0 --- /dev/null +++ b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-exe.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "chat-file-type-exe.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "chat-file-type-exe@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-exe.imageset/chat-file-type-exe.png b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-exe.imageset/chat-file-type-exe.png new file mode 100644 index 0000000000000000000000000000000000000000..e2d33783e0434db8fde560dbbaf445283fb7c991 GIT binary patch literal 742 zcmeAS@N?(olHy`uVBq!ia0vp^Y9P$P0wkGC6jgx~OS+@4BLl<6e(pbstU$g(vPY0F z149*1VM7Z8!!Mvv!wUw6QUeBtR|yOZRx=nF#0%!^3bX-AFeQ1ryDf_~Q&6Cn|d?FW@y+XxPQ!0u@_S8Sc){rI66`$L_f8F-v?2CQj z_iqOT?BBfSdFA<^`}P;l`z#Y@c4hU3)as=DMqZ-xnJTZ>3c2*~lvw0ku+-08$!(Xd z^VzQ8wz&7Z+v27w8^4BkdCf9jaI!!|kFRG>;NMw1**|I{6iim#KX_?Jg#kzJEA8HH ze&M(4gd$Yd8A&XhT_tOv2WZ|27E<|V1+Pahqa zv}%`_L~cRQ6l_nOEV%gmc|A~XHxPTVY1f8Ht5GE&lg>**7U z`q`n1dOBAg^?3)$d3nq_v@1<=`qIa$4F?wWurAc{Txh~1-xGbK=GAs~?~1Q`8=`eR zGfnk3BpiwQG9@E)o|?Cmf9yKkN1CLWR1eo)k@AsZ@-o1WuI&H&V7X>Ffpi>xJHzuB$lLFB^RXvDF!10LvvjNLtP`o z5JMv?19K}QLu~^?D+7a%qhelF{r G5}E*GPA0Sf literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-exe.imageset/chat-file-type-exe@2x.png b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-exe.imageset/chat-file-type-exe@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..fa3b0f812a8208c90be09cc0e8e14e4fb44b355f GIT binary patch literal 919 zcmeAS@N?(olHy`uVBq!ia0vp^-XP4u3?%s{blqTJVB`+)332`Z|36S<6aYiu`expT zKq{gn$S;^-9+Sa_7YPy?H#q*@mvj|ke_X-B+`{_jxtzj5#%#sk@AzJdOntB^;D@ky zy;lDb`4uO2+!p244s}q|o3m$u3iqc=PvgJ2_?vCZ-Kv~6E!D}UQTJYtd#mr3vIq-c z&_DKcaSW-5dvkTS*Wm=2wvXzr8KR{D1p1xjIxMca( z<4dP}*)V0g-cOHv8*8`!|J1BLK_zK3+rgt3n|h|6*!XMHl*5}gtUaa{nXPd-KV(_H zqt2OaN{QRH3OtKC#5Aq{Cy!?UeO>s*Pe1EOmD%jkg)z2NZJXygv z{O$FN?#_u4$3Obte%TX{xT?hVCdVp`B|$y6jx_x{!4%vP!K|X$wMfC+RGYbHQdxb& zXC_Pg1E+sKJ$?T79{yjMvZdm-;rEWt{owau!MydR`&l-6wK^?4ad+{$pXLFQa=Oba z-=9vsHDhzCh{jY4zJe>xdIfxYV~qQ3<~6(*zIID9!kn2cr{~9vxE+66E;GJmIG(Xg zd}dVB2fvPU(TfVis$ajW505#+wz2Gy#l7;CH>Zckw{}*{aOII}6DND#JCzn?B&nU8y5`OPsvq{U{~1nfnkqS`m#Ytyw>(|_ KT-G@yGywqIc`o_@ literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-fb2.imageset/Contents.json b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-fb2.imageset/Contents.json new file mode 100644 index 0000000..21ad19d --- /dev/null +++ b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-fb2.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "chat-file-type-fb2.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "chat-file-type-fb2@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-fb2.imageset/chat-file-type-fb2.png b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-fb2.imageset/chat-file-type-fb2.png new file mode 100644 index 0000000000000000000000000000000000000000..34d0038a9ac94a8e3b624a28ceb5d456650c9a20 GIT binary patch literal 734 zcmeAS@N?(olHy`uVBq!ia0vp^Y9P$P0wkGC6jgx~OS+@4BLl<6e(pbstU$g(vPY0F z149*1VM7Z8!!Mvv!wUw6QUeBtR|yOZRx=nF#0%!^3bX-AFeQ1ryDD~6I zR|t0%ak;Q)g~UmpgSlG_4LD?){spLPJz*y3=~BINYInz`fX)Q7zoBm3X*IbeCbJ}K zFE3h9mtTBt=l9zCmUGH?Oqbls^}LqtiuS^adt528-{S&O(i7&p-JNuAMtFM9&6p(H z4+mQK--0POy;@v;FZSi5XwUd8o8a-E!~A5y$w`l@dy z_h*$#Zn>8GTtzlu?fJ^d7f+qZ+U~yJ^-|x?8x|zoW1GQoef7cB{!T+U)&n68JD&o$f@KGoPBkTFmM>qc==}3Vt?JkBe81{%$hV#SdtS(I`i?fSpp2a^iV+&` zDk3?brvG3!xz^_#E19bVOa!VWt`Q|Ei6yC4$wjF^iowXh&|KHRP}j&X#L&pfz}(8n yP}{)J%D~`b`H@T%4Y~O#nQ4`94Th#6Mn+a9mT(PMKk$MQ9fPN!Qtc3FhV&jqz& znQ`~|*h(Jm;gu@mj|>M!*+)+o$B>G+H`fkomjp^2|M-6Ivft;Hh`R(#SfX@r%G8FC z6K!3mP92d?HA~i5+LOS%G)O5`)l0>=RY6TzqV4RJ$!G8Qou737-OU=S{l!*ulPB^` z-l3MU^n`$Pvro-UwrO0yFBW$B%q&@**_@OrrL8gJ)+UzVXw8FLrX}c2lN0vt?_7HP z$fe|@mxdd^%s5l!<7TTiS#Gi;R9Nng^Rn-$N-N%L%(ypcMtO_o^lQKR_8E(fRv7*D3TU@Lal7(8IE1N!P=xu3hradsbNG nURe{k+3l=U?)qiC{`O1^+A|kU4y;x^14^Hsu6{1-oD!M>N+vt6U(g``E+dd~DcSFW9l-n9DY z_XD!0@9oZZ51H=rJMz`EFL!n*-qeVZkx;cvZcEAiUmLMNC*5b6rJfwmsUkhI<44;& z!>)7c2wj)#*)-dYcSg>UrAZ7OQ>)3@ ziF@A#U5i|uaL`d-#JZ6+)OX?EWigur}Aip|?Q#9Py^T(6T(a(I`&&%jH^B4Ya|C<=`*v{Mf`Xi}ZXPoX{I-9U?O0X>FDtV9ljI%Ym|Nht% z&ku}t)e_f;l9a@fRIB8oR3OD*WMF8nYhb8rWEf&-WMyD(Wn`#rU}$Av@Ui?zCW?mK k{FKbJO1K6?(-0#gD-%n&hN~ZVLCK84)78&qol`;+0OZ{y*8l(j literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-flv.imageset/chat-file-type-flv@2x.png b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-flv.imageset/chat-file-type-flv@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..f324aeda3a16cb584d18a4081db08c11363c7d69 GIT binary patch literal 805 zcmeAS@N?(olHy`uVBq!ia0vp^-XP4u3?%s{blm__9|C+rT>t<74`hxU@bt%|r$FEO zmjw9*Gt6Up5Mgj5!9!_A!G>S&Lw1NeoMPnZJE65LUXfX&-+8xW-Gq1N*<917DG2D) zEb@)`iaZBnd9g6dyfyu2TR-)5PF`&z`!`w)5S5QB5uu9 zN4^FH9+yCcdHm7U*8v*ar0$jhuB@!<+h- z533s!@4mfm=zZ8h;@HRfy>UT?99Oj%mHEV2U3K~1&2sE$o*&wxGjW&24lzd#4c3LB zx$L1?y^^a!G6Y0F>P^10d2hkbgPZr1J6dbW^4Ddqy?-&{{_%)oQBx21G;2R+^!E}^ za67ege^jAC5AWOuVil1bRo)FeObc&syq&z9GvuM;K`ZXV29my0`wxd3EZwj_N^{BL zmx6n|XQ*YqDtof?tkD$PTN%-FtNjwh;=by3<*a|;6nJ!%W#8tBy=FIT3TqZ8?cDc1 zJ|&r_NlZ9a^tDyjqOCb^?k5JO2EO#mRw?-PGACwT!MxM+1lEYJxL&kL&3xmloe{~k zEKIhi_4lUtuW;9Uz literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-gif.imageset/Contents.json b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-gif.imageset/Contents.json new file mode 100644 index 0000000..28bc957 --- /dev/null +++ b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-gif.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "chat-file-type-gif.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "chat-file-type-gif@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-gif.imageset/chat-file-type-gif.png b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-gif.imageset/chat-file-type-gif.png new file mode 100644 index 0000000000000000000000000000000000000000..8771231b69b6a75b0b97a670ed7f4ddab1b2c6a1 GIT binary patch literal 704 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 literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-jpg.imageset/chat-file-type-jpg@2x.png b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-jpg.imageset/chat-file-type-jpg@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..fc5c436b4c481b94e14be7af43468239f3f2060a GIT binary patch literal 1016 zcmeAS@N?(olHy`uVBq!ia0vp^-XP4u3?%s{blqTJV6+SH332`Z|36S<6p$AJHIEl% z0d;1U1o;IsFwNT$;m~04Plbd1_XBl7#!t-ex`bG~JtlH3;Nw|&;H0IZ@cJ+EA-Vz5 z*LC)V?tQ`bQ2)~5wbfxo5^`^km4$z8*`AQG>6w;&bG_{Hl=P3^T&j9RtV<;yEpmQ+tt!lW?*KJLgq-;>MXS z&a(n}tbf1V*u3>z%+#sDsiD`>*Ir|j`ucvp+V(}i+&_i=+0L)5cHuAUviRe|2eOOg z4wOAV^>#;#=Ha-<{2u>)Ge0;wb$|Gt85eglyw`m;`)ZZHUy&@c}j<$l(7~b2hKDNk7gR{BOPz%l1{9M`ZTV`uUEpXQn6})@JKE zEA+H8HG$QMjg`$!OksnX{hQnpNr`nai3!OJO6Mxr*xGJB+3h|3;jiA=@sbge4IPCi zW4m5$DP@~}&(NR&Xz;0mfSG$f6eT7ALB-C`vdlnWEHF{}n_NcUy>C5@t@C|0pIf-| zvAuEg5^l@1)|R%v2@z-7l794k=Si9vsHoCz%dYP%;rt-!N=@Z~-slFNa$wNw+-s1# zqCcblUs6KEC+mrg0w>O#ahaidZ058+TmF;>*IJF18O&`AVYp_xFIIRm7t{S>FVdQ&MBb@0CWO2yZ`_I literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-mov.imageset/Contents.json b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-mov.imageset/Contents.json new file mode 100644 index 0000000..cfea380 --- /dev/null +++ b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-mov.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "chat-file-type-mov.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "chat-file-type-mov@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-mov.imageset/chat-file-type-mov.png b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-mov.imageset/chat-file-type-mov.png new file mode 100644 index 0000000000000000000000000000000000000000..f640ac2509b56fcc279cf157fdd5ee2927fa08a0 GIT binary patch literal 852 zcmeAS@N?(olHy`uVBq!ia0vp^Y9P$P0wkGC6jgx~OS+@4BLl<6e(pbstU$g(vPY0F z149*1VM7Z8!!Mvv!wUw6QUeBtR|yOZRx=nF#0%!^3bX-AFeQ1ryDH=O_J@r8Vuqr}pQHngV^Z>TaSZV|{`Q);hiIb6fsgmU z-t&1o%j=d>kfD}}S57F$MWwe}GX!&ELM|-Q=tytc->iR67>AgLLxqU0HXFZ&M zT1jn-Wm4r1J!?syjADzJ>3e-Xy(yZgdiAMV@*!1r-Qu)Wded4J46cVg?hL%5{Ce)j zODWNJ=JjT zj{JEmu0Nk_m&&Bv=JRX8DeLuDx+<2d2j5)6#~bz{G+|r6{UgE2ze-mfHCCQkYOLqq zE|h)8RBK&)Oy`QCzx%2(I;w4o!>m6bYZGk z@(tTBKNp28KmG02!?oHkOjCT)mu)IL&b#BmD#hndq|3c_7ny&3(EFF^{Zf^?;a;P_ik>_LCp+5|PiCDgc&yg8-0@QB(^+0p~c{$AwQJ_JlaswJ)w zB`Jv|saDBFsX&Us$iUEC*T7KM$S}mv$jZRn%E(aLz|hLT;A8obOcV{d`6-!cm2eG) zrXfZ~RwkBk4Oc(#f>N<0$cEtjw370~qEv?R@^Zb*yzJuS#DY}4{G#;P?`))iiWody L{an^LB{Ts5N{C*_ literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-mov.imageset/chat-file-type-mov@2x.png b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-mov.imageset/chat-file-type-mov@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..3a6088dde34414dc7ed0c22b3bc166b8b45b91de GIT binary patch literal 1362 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 My85}Sb4q9e0O+M-WB>pF literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-mpg.imageset/chat-file-type-mpg@2x.png b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-mpg.imageset/chat-file-type-mpg@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..81eba6030de896554269f8a8438887a0e12ae29a GIT binary patch literal 1296 zcmeAS@N?(olHy`uVBq!ia0vp^-XP4u1|%)~s$KypmSQK*5Dp-y;YjHK@;M7UB8wRq zL=J;6qiBJz6HrjH#5JNMI6tkVJh3R1p}f3YFEcN@I61K(RWH9NefB#WDWE~Uo-U3d z6?5Ls@y(D86**q7eq>unl5aqV#;SnT4OdqLu9@!|!?{Rf0hiK6Ca$~^)dk*+t$DGT z+M+LxEp1w$va#uwLYC&FRY8H>H@cQ>+iIeFR@0z-*5vEvb1mPWo%>|(J$s(-ug{#> zYkzKMagngnDzBL?OYW?&%w^xU;+4~7eYuQZt)>}F72z&Y^Q-j_HKj6{z1Zs*s(Q@j z)Ri>t861CmTT|9og{^b5T@#*|YyS0F!^*6etQmEo8~Y1yS~4&n*fwon?g57@mS2?C zT*#A&IDaULFTs{~b!LJs|7y>KTE^9y3AN0tITLDGwaqr{YZeubh(FZDx+XvID8seu z8(y(p`@Z27OPS+=RopjNnOE~AyqkP!>VjGIjYfi}o_pVy?wEi7gpXhNxs63@S8ZAs zXR8@2_SHw?*oTbu+ttn&X&l6dR(zY!>-t3N!KMp$)~|BEb>mLTy}j;dFSd8AVRJiN z%JU;Ov_GuoyM_Uq3{zde)t`Ohm;6fQ_b|#!{0_g>!_UlpEbU0o-UFAKcmBD>Y*RC@ z+>Y_jwW9Ny3B_~Sy9^H%9J%s7+jt-626c|tK7SX9-M;fUkIhbOqHbA$3!7^S`v=8> z($jmJ58PWddEFw34Q;-E@0mURzGaKPZpFFF2cjMnZYp4@h;~`?_w<3y3+=>jJwDKU zz+rTqM;}`rb|3d7O$gugde(^4>xq4@JXlVV*jBR{JTTCUrcIWp_Y`wad%}ip;zP(HhSi%l};dvN|k6smO4HmPvW*rFYRk>%N-aR9Yyt#@*NU`wiZOHUXwv zUxbxDkG#gbk3nRIpNm`QSN%-_EH`*)dm@}(qvwMM|*4WC-RRA}tyc^Z4*Z3Dy4xM_#AxDJ~)?r!uB`8rYH7{iKJ zi4O`g;xd2D55Ah+$Q-+7VZcTk?f;j2+l%J#Na)n5esV)MShtLsC)Rvi5CFCb1? zY3A`!Idhx#^`KYQHRdy{&f)>`eyDs@4QoPhUvp8w?jO= zZokw`U}UK9b!oGz@k=#j%)WJHxzAqh^Fdel9;jYu$@WHQ;&PW1nTX3LjZcS^&zqY6 z!F7Y0@7~)6EEUZ<<-1#XZk*Gb7rN@jyrru)A4ortmvHOGGqcsslU`0+CCBoPA&$K+ z$uM<>^5;hp&yy{oFYxVVAzqqD_-z!}jA7L>i!IF6N#I89$@&D#6 ffvVuV^n#~4(f;Cv-f3pQ(u={<)z4*}Q$iB}l%QQj literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-ogg.imageset/Contents.json b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-ogg.imageset/Contents.json new file mode 100644 index 0000000..e539122 --- /dev/null +++ b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-ogg.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "chat-file-type-ogg.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "chat-file-type-ogg@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-ogg.imageset/chat-file-type-ogg.png b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-ogg.imageset/chat-file-type-ogg.png new file mode 100644 index 0000000000000000000000000000000000000000..ce0b6294d30248d85bba550fa346cef914622a43 GIT binary patch literal 843 zcmeAS@N?(olHy`uVBq!ia0vp^Y9P$P0wkGC6jgx~OS+@4BLl<6e(pbstU$g(vPY0F z149*1VM7Z8!!Mvv!wUw6QUeBtR|yOZRx=nF#0%!^3bX-AFeQ1ryDH=O_J@r8Vuqr}pQHngW0LfAaSZV|{`OjY#@RxN;~%fT zpK~_jh>28c>dgHsa~Ewr)GM_#rob_<$gwkNQ&iA8lP6AZpLC^&zq_+z_KBl^GM7Gy zKY7Dt%d;)p&YU@SvoP8C=iL2z8g~0k41Hlc=eC?%$>xTH#YfHl3NSxGnLd{A4F?fmQV^)7CL; zUSobe)|MkATKnm;IzjELl4Z9Y)@?{STjp7ny}o>#m9Eyh=>2#7BtD<}Y;c3$cW>tP z7hC~!GG=+?^N`isl3`Wc6#`)HJ6uP+W4M5ZE=$L-n07Y zqHMLFt~UIfCiUT-*wlBCYU}QsiRQI#oqFafkBX16-b%;SZkKzyZ#( zt-xo^ajB=~d~|VHf75HuRpnXMZ#EicU)B76z*)IWOZdUMpxaZIy zRdP`(kYX@0Ff`XSFw`|N3^6paGBCF?GSoIOv@$UGSbiiEMMG|WN@iLmT!W!$h>?+% zi6vaa)epR0E1Aviy+q&%@Gm7%=6TrV>(yEr+qAXP8FD1G)j8!4b722WQ%mvv4F FO#p9*Xj}jQ literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-ogg.imageset/chat-file-type-ogg@2x.png b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-ogg.imageset/chat-file-type-ogg@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..0f2c7c0014ead0b81ad6cd2953d11eda2f0cd529 GIT binary patch literal 1225 zcmeAS@N?(olHy`uVBq!ia0vp^-XP4u1|%)~s$KypmSQK*5Dp-y;YjHK@;M7UB8wRq zL=J;6qiBJz6HrjH#5JNMI6tkVJh3R1p}f3YFEcN@I61K(RWH9NefB#WDWE}ao-U3d z6?5Ls3CxfQ6=~bQ`RY+IN9};zT*YZ@IuRa$y8ASQL??9VD@|;Y(B$mEk+fDcZ!6^_yO`(abkzZl0T)vh90&qTjhc z>Cf)zf6q&Mrz04;)I%vKXO+KuL-VR#A>Ui0OXD{%`7*_Kdc4ieSJH`4PS{?_9TJ*k zvc$tuo^`Tf{Ou_@uTH#LbxrVENQApjjJ!dp?j44=d8vO4&2FQ@^d{7+gSHa#RK!rJKgyQSt|cW*d1>+x={Irm?$_nCS)=&JVtNrr^o9XF;g z7Q6TI!T%*S^DWu@%*wqny@7M`Y=eJ=llL>pFv+p* z>=CjQG&wm_m^j>{Mr&;vR{BIx4xWiUdv;WY&qQ`XkfO74h@2wXL z55{~he_*k}{P=&J55*F(cdzzLJ}}+zSLo^Qn_W^`&N+Xbv-p`@!b%_CAIh6}XIvH1 z-ni`C)%C|}X6m->`Rk>xgD(|hrtzZv`{L98Z{8BNbmG&1rl%KpCA6)D`E}pr1B)F7 MPgg&ebxsLQ0Aac{SpWb4 literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-otf.imageset/Contents.json b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-otf.imageset/Contents.json new file mode 100644 index 0000000..427bb19 --- /dev/null +++ b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-otf.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "chat-file-type-otf.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "chat-file-type-otf@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-otf.imageset/chat-file-type-otf.png b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-otf.imageset/chat-file-type-otf.png new file mode 100644 index 0000000000000000000000000000000000000000..1c9f669b891dc7de3c6a01088dc52a6fa60b2f68 GIT binary patch literal 736 zcmeAS@N?(olHy`uVBq!ia0vp^Y9P$P0wkGC6jgx~OS+@4BLl<6e(pbstU$g(vPY0F z149*1VM7Z8!!Mvv!wUw6QUeBtR|yOZRx=nF#0%!^3bX-AFeQ1ryD z_d=PxkA$)*zhB1p`-|w~O_~e~*ZQ4y-Q6?2??v&w-(NPk-u}9NlZcMxn-^WBZ#M+= zpWe^1`*g!9uR}G`$48O=mB#zHM9<9jp4|{78T=z-bMK+l?2PViy_*yH#B}^uI>ar^NMbcxG0k)O zSxMHdH`1=v2xf(?fA0C%;N)h(`CD$SJ~&~+i-!S?8gEPwsqt7m?Q`8etyYWA&e1cm zZJlJ;^Nr>b7xP%omrPr=;R#=-;<{an^LB{Ts5 D#yBnJ literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-otf.imageset/chat-file-type-otf@2x.png b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-otf.imageset/chat-file-type-otf@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..3970c388c020e578e9af9e268bc1cfe4168e9f1c GIT binary patch literal 875 zcmeAS@N?(olHy`uVBq!ia0vp^-XP4u3?%s{blm__-vWF>T>t<74`hxsu%WE@A<)l( zB|(0{4D*-_9^B{%m=Uyr^WQGsPEX=r17pYQ%+qkWjzA}<7H15$B>G+ zH&+$84+V&@J}|zj62W6;sOhaI@t1eg-%GqLi2^Q$+)W!)W*kvk>NN9nRl7E}A>ZofoOz80i@1;ImC9Y134J$+}6q zT+igZl+cx3yfk@BNzb%C!`Bjv`wU-7H1`!=H(X~G_M6S%uYTTw?@D0{TI2J+7_Yll z{dZ?*)Y4F6hP}U^@+55VP5ynMBi{S*tm{(uenphNvX(i%a;wXnyvcj^u2N^0P~4>a zcW>0Wq+Rn4-dil$R-AKa12@CL&3BFdk*@!gUsa=QeaQgS&9nM&hh zm}I(>w5HXiXV(6_(6Zh3-_+86&NYF1x^K)XJ-3U^d z)M%;b1xv!r@)|Cj3IB6YOLyw}Z<1|^x6g>XzMGd+y5Z!@&H56ve+E^tYaH16b^Cm+ zzFWH|nrb(w+JtB%oR#wHta>Uw@A28 pf&b<2W%fOd=zDr^^`rc6KbX&{bQS*URjvT#7f)9|mvv4FO#ob2Ctv^o literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-pdf.imageset/Contents.json b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-pdf.imageset/Contents.json new file mode 100644 index 0000000..55258d1 --- /dev/null +++ b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-pdf.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "chat-file-type-pdf.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "chat-file-type-pdf@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-pdf.imageset/chat-file-type-pdf.png b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-pdf.imageset/chat-file-type-pdf.png new file mode 100644 index 0000000000000000000000000000000000000000..77e2d231d9d589a7a0a3499ec758c9f468785f06 GIT binary patch literal 744 zcmeAS@N?(olHy`uVBq!ia0vp^Y9P$P0wkGC6jgx~OS+@4BLl<6e(pbstU$g(vPY0F z149*1VM7Z8!!Mvv!wUw6QUeBtR|yOZRx=nF#0%!^3bX-AFeQ1ryDp!0>pZC1>*+W^gtJ-U-Y%eZqy0kP<;rY5s$1|rKmX~dhHCVe!FS2aG zp}z-Km~tO`+aDbi{#RFZsn5&nX$E}LS=`Qb*yXal{aqWOknb|T`QnZggA>w)mQvGY z)a-UeC2ZVrE8z+6>#JD{WTyKuaJ;>w8a`{OP5GsUy!^?B_ub0=z`i`;E~o75ck2&3 z{muI~C1-Q>wri7~z2?Xd{r7vxH71u=@{LDD7o1F#ysRd=C41A8ncufrtO}f4u6D|N zpVXTv*>R_&j2=x}lj^VD^<y5aI zJXTNl3_E*ZP4TiPsoj2?&x>7|c|lv>M<_DkaLvjj&9!}%DXt139d4m{U(P!!aRtn@d^i|FarmNQFTWf5f_Rb+0nV#3MzJ1_nx)=Px_n|t;3 z$`8^~O9R4cMRcZ=?OWF1CHs;0_N3Vw)^{#n1||p964!{5l*E!$tK_0oAjM#0U}&yu zV5nnl$&bO) L)z4*}Q$iB}d9pN% literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-pdf.imageset/chat-file-type-pdf@2x.png b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-pdf.imageset/chat-file-type-pdf@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..bc0a1473183aabc9ce6f198b93bcadad595e41ea GIT binary patch literal 923 zcmeAS@N?(olHy`uVBq!ia0vp^-XP4u3?%s{blqTJU=$4S332`Z|36S<6u?73*gO9V zkP}rBRvb__^rMAm-IyrO*5H?Q`Fdbn2UFN z&USll*IB1+DeUj^`jvpsjVG}wAzoD-$CD!imOA#DFBaqe{I;O`%Dq1yPd74(KKk-; z7BC9#d%8G=RK&fxy0MQjQH1q@@nqjOc}dEVLgFj=HU{!0FBA1Fr zh(-w4#e@m=Ph5;YS)a1Jy7TPxYW10t?Axz=G?*u>prWS}WW7^tTFc$LH#k~f*#zI| zp1t?Pr;d};oPD-2C2ex`+1}9_ZRO^DJmaN=uI%Ea$#Y737WWliGUT&5wk~;%)weX} z5C0Ecv8mNh+I7^XI9d70tLg7WBYjd_uN}W1u2a8uX2~mgwVg9g_FvsCdtaP!&+gYJ zmx?u%8QHNJte04joceZ^!|o|ZPF;DH&v`>%T7i-}@DMQ4fbNHuiKV9TJ-1$r|8tpPZk}Lf5ILx(f2q1ojD!S zqMa>Uy>fHUwo2_@o|~%z6P~-q z`TDswU5)>{o2ClSZt``FU=9fl%{?)%c9PBHO?k;IUfc@PoA<6+%^Bq)E*_P=Rr^Y6 z?C}Gi6dq`~-k4>UsP_7j&qNL93rnjPtu2t={bbfEmV(1qyV7^rEL-QY2&e<=gCMyKAPu{}ihz$ae3{M`rf&UZ1o2hgm?W N%hT1*Wt~$(696UhDZBsx literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-png.imageset/Contents.json b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-png.imageset/Contents.json new file mode 100644 index 0000000..9500234 --- /dev/null +++ b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-png.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "chat-file-type-png.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "chat-file-type-png@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-png.imageset/chat-file-type-png.png b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-png.imageset/chat-file-type-png.png new file mode 100644 index 0000000000000000000000000000000000000000..136e37c59f878a6357049ac17a3eed5a96071d7a GIT binary patch literal 821 zcmeAS@N?(olHy`uVBq!ia0vp^Y9P$P0wkGC6jgx~OS+@4BLl<6e(pbstU$g(vPY0F z149*1VM7Z8!!Mvv!wUw6QUeBtR|yOZRx=nF#0%!^3bX-AFeQ1ryDH=O_J@r8Vuqr}pQHngV`BDnaSZV|{`T7K?DK^($3Gtb z{{6S^{?4{7GFc}R`2ufGSu#~7E2f}Py7RWHS}&y)@bQ=iIvwzwWHue}BIJ`SZX3R@T4zoEXCHT6x^p`$<638LlOz z75XPO8ErW0rT+G+`ubTln>3EsJlLbp7PCp=_N0h^vByNp{kx^!-YhtJz~l9`HEz3q z*7I?<>@r<_wnv+fZDC%!(c`Z6lk;LVH>}xlDWPST%$74NKkjf5Z17k*_fm3POh2#R z&BvJ^H%!rbyWhpF=4!&@j4cHbOI&Z~A3b+9(@8Vc?wr7Hoj)(9+-m6g<(@E8+Tf_x z)O$Np4{(XD^N3pPzJJEiS3Em&HU!)VO5Z!J`>Hfe0+*b(3T|By{;ucwJxRSkXF4MD7V^tQti5is zwe3hq_4~DF({{ZId^l6pWLD~aJ5KpK+u~Y`7S7n}w?co}nMC)TLQjkdn%SW zT`KfH(%tCFR`WY?`p&nlmQLoXxu%-8Z_nZt>)D)SXPq8#M^?7%wMq1<4{SC?2mZ=S zmT4Yl-Th_J+0v_QcP9k@jQesX>dE9~HL25<{NJ#j)9l}+Y1R`SOV9G0`0|wTK_$*! zRaKE*sr!sI_vdXrE@rh2m_k%bTq8@*|lj8glbfGSe#I8VpTCjEt;IEa4iie&7WqQ%R5w!TD(=<%vb94CUqJ hdYO6I#mR{Use1WE>9gP2NC6cwc)I$ztaD0e0sy@FS+@WH literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-png.imageset/chat-file-type-png@2x.png b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-png.imageset/chat-file-type-png@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..c85b021ac92e1819c31fb8d9cd4a61848878ace2 GIT binary patch literal 1141 zcmeAS@N?(olHy`uVBq!ia0vp^-XP4u1|%)~s$KypmSQK*5Dp-y;YjHK@;M7UB8wRq zL=J;6qiBJz6HrjH#5JNMI6tkVJh3R1p}f3YFEcN@I61K(RWH9NefB#WDFz1SPo6H0 zAr*7p&f#4m7Aes%-+b%#t!C0k-`(39yXNn~b-5cO$|A3&-8>Mbv^1L4(ba{)iD~7E zN&j3#MH-hlE%GQ@{i1)-Brli$+p7-GS?_oGXWhM7mgQ+y{K@Ce?72UueBQa4`R8V? z*Iwmi?y{shz{ZTZIP|OQn=bdG>ozd3HTEhA*?zY=)g&lncIy{o=u{)2mu?Tj3|@S5 ze?6%*H&S=ewhg;Z-Fh?iF=z1Ab=(WqE}j0vNX(u+L1csG_IzQ3RaazQX`Ie=7Y~b$ zR90MbZBr8W>b+}b9FkJhp0?rGi7v%8ftyZ=U9*Tx<;q^NW>br4SeWD?Dc#i>iM`W9 zmu%p73JW}BClTq&VSIi{SYuQC0-jx8->my;^>}Xco+n$ZE}v?>bh`9v>9P`+6~5*= zi(R9mv$G=ECh0JHPHR*-?Jy}-;iS=o6iJUwJSs5ZOUK%jK5>3vH4xmv920!iy>Z9- z2F?S;p|*3a%>-Yt$E|o3(7wx#t&Zs!)++TE?i{TIJ9D#}Pw`=m^){AzW_`T?c&=f379rSH(YDk%7p-HiG1oprniL>{Ckm~D7oE0pK$dH2Hm zDCT?r6!ZVLIILkZ-c{h;!nHkhZ}JZ_$Nk)WXJdEX+w!B^)tY_)$jhqcc0jD zC+Nr4qZNsTLO*x}7#`ScFcG-EeARK6CtL;$f1D$(HH7bbcWpnTbx~n8XZhoDHMi4J z{2U)xBDnutdd9i?{MzzeUwsa3%6oQ>_d~;)sdua2=U59kUz15N`ml1TGl3!WMlAKoKB<9Y6j zOis!V$-I`>6P{=L@V|J6_4BFeQ>XbhXr26Y-{L)M9^?Gy%^_bo3a;e(2~MBHOYz0&UxyJUF-(ZBS9^UcmFerEAOP%dXdX z)63?*4Ey`+)1LEtYMxito#*+yX+c@w+1E4YuF{C_V{$F;-o~fRa<{ekTc7kyzjn|YH^>%wh6Iz zI+vEFdv1=tv)Rad_WR_b%ZHA-USmA+O1@E*H=()q+K-$IQ_^lv-Sg>O;_TKUyI1Q? z_KD@}ZxX*&wdi!|*?UpXXF2!X&bXq?T)1J0+3Pbe3od*17R|GMxO#Kmj;uSWck7mY zUGrl0o=_#9*;{VyFkEOjd6CIH*CIZvgcBPan#HQWbg^{W&sjBfZNa%UX7ew+*mC<_ z%G|UBr`5~7ie7!m{;0ff>(fxNSpl>9)2B6iwdqy~>wMI_xOIscd#s67d}9C2qS*W` zl3v`>hDP$PY+9eVqmbgZgq$HN4S|t~y0x1R~14DCN14CUS!w^FwD+6;YBSUQiLn{M=kL5=) nQ8eV{r(~v8!ZjG0h8P)HnOMR#T>ZccN@fh6u6{1-oD!M<0rM`( literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-ppt.imageset/chat-file-type-ppt@2x.png b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-ppt.imageset/chat-file-type-ppt@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..4b46996c1b16393aa35efd6be97bd56cc6ce7cca GIT binary patch literal 745 zcmeAS@N?(olHy`uVBq!ia0vp^-XP4u3?%s{blm__mjZl3T>t<74`dD};C0LGGSEM+ zB|(0{4D*;?d=OZ1!QlW)z&BR@_rih}#~p90@Bo*vocTELAZ5D!X*qy{1VCS*HbjaxI%y>K^toB$Fe5rg{T6eFCBuO~-U`}V8NWQ*$mWx`xo6^fnAjY#O{KmV8huiXR z>t@_6v)$pU>#N7jz`t7OXlVYSB}u!K&+a>RD@q}lwPCJ`+QYRs@>rA@j(nf5ApEaP zhH+0gLto&O&x57!MOssN>)Q+d+&dWatY=p1O?Nd> tg_7PjTQv#O>?>;mH@n?lz3%Ykeum1RRxb0c-_L?ltEa1<%Q~loCIBn1@#p{m literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-psd.imageset/Contents.json b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-psd.imageset/Contents.json new file mode 100644 index 0000000..d0be5aa --- /dev/null +++ b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-psd.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "chat-file-type-psd.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "chat-file-type-psd@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-psd.imageset/chat-file-type-psd.png b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-psd.imageset/chat-file-type-psd.png new file mode 100644 index 0000000000000000000000000000000000000000..74362aa352d85cc22b043c3fd29991a5ef9c4253 GIT binary patch literal 747 zcmeAS@N?(olHy`uVBq!ia0vp^Y9P$P0wkGC6jgx~OS+@4BLl<6e(pbstU$g(vPY0F z149*1VM7Z8!!Mvv!wUw6QUeBtR|yOZRx=nF#0%!^3bX-AFeQ1ryD>UToOL=gNjp0`?`6sAzmoem~dY;RnJx1+QsZyLaL|y92iek^TyFWeI{btKtsYUN@PLh1Tc4Njp zw##Y3Hyxe%w0fFYuUWpDA^z*@&KFHij#)V|t`^hs&QA-;GI_8nQdZ35_X2yhBg`p%C1-(COr|4q#KS{$~< z@Nj-c1j{MW_Qb{=#+JGnKQBL#Ugj|Kcb#f1Con~*mbgZgq$HN4S|t~y0x1R~14DCN z14CUS!w^FwD+6;YBO`4CLn{M=1M}~FLD7(#pOTqY3D;m~8e(K*WnyV%WC+o4^#d;` P1u}TL`njxgN@xNA?+G)w literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-psd.imageset/chat-file-type-psd@2x.png b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-psd.imageset/chat-file-type-psd@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a627ef16b9260a526f55f580fae0f5ff636fcd8b GIT binary patch literal 1137 zcmeAS@N?(olHy`uVBq!ia0vp^-XP4u3?%s{blqTJV9X2f332`Z|36S<6woIGBpRoAm8#8j zHTg8YNv)IZigqcIUogwM`QF{cFxEG_mwMU=MqRwm68L3C=boFNomzGsSX^-VW&fko z$B(`j5?MAuC9kgO##`Z)K8JMt&N3gKf2nohgKZKiU1z2;Ffdtqx;TbZ#J#zCQ2R-u z%<+%k^QHcly=l$R-+ikr_wA*qwW;|+i_-3hxOP5THbuI=ac8fH=Ykj(&AgZ?UW$QA zfeoFVQ!YtxOUrkc;$b__4EAw{rjEw_}$ZaVKYgAzsqW#4cFXu~wTVD}1^SSy36v-a@%% zpXD1S%v%(iRmb4J^7r&zy?@^dC~f~Io$@z}@s`~Io-YBRQYS7%I?PW`Y})<*N4I3m zoVUFU1@;?`KG(VHrckv%%;Bz$yrf@zn>53YS>029DkuK6jcYi~_0-+tjT2*)w)8fR z&!)niFO0TVaqEjrW}St@$t$gj341VrzKO?nITUrE0wcnk;tc>x&9nOhPdrbFetbO^y@Z%xVGiINH zF5mnt5uvH29wAwj(3hy0lCbcI&N5z};^)Q&AfRDryhr`^8lBL}e``wGuK$++0;5kg ztrBKF>YHr?4Xpbc8ygc%zl*a0fgBrK+x+zsCrYkct&9(rNc)%e>(GIK69){QzTeMT z`=4X`Wi9POiQ|WvQwu^jBwch3n*EZy=i}PsExZPI&PbVNUs)5l+2Hh{Qx9LdGc;$f VmNs1BJOPwvJYD@<);T3K0RT>3VY2`L literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-rar.imageset/Contents.json b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-rar.imageset/Contents.json new file mode 100644 index 0000000..b7e3d4d --- /dev/null +++ b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-rar.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "chat-file-type-rar.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "chat-file-type-rar@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-rar.imageset/chat-file-type-rar.png b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-rar.imageset/chat-file-type-rar.png new file mode 100644 index 0000000000000000000000000000000000000000..70eb1c681713ed2d28496110c1003d4bdbf94d8e GIT binary patch literal 823 zcmeAS@N?(olHy`uVBq!ia0vp^Y9P$P0wkGC6jgx~OS+@4BLl<6e(pbstU$g(vPY0F z149*1VM7Z8!!Mvv!wUw6QUeBtR|yOZRx=nF#0%!^3bX-AFeQ1ryDH=O_J@r8Vuqr}pQHngV`BAmaSZV|{`Q)$he#sBv5)t6 zcqgjW3M~BMc$0mardzwy3n54O=}NoY+B=pA1bG-NI^eD1B5vy`aC7Od(B&RhA}o%9 zUmW8j*iSCvF}}UFq$1nrVJ)zi&4*)~>j!Z54sL&yH&lpiKd0nb z{*~isj*08`7Nb(Hue;s`|Jxw6e2SF7igNdvX2!W+PgKp7(m)<)Nz(rt@Xt)Fic&f=Ms-+sV{yXD@>>nZDB?{o8%R-}C1>TpgHqwvUq*PmVRrB)l=sVJ;i}&CEowicuciYo8Rhg^V5vyNLS|@o( z(D|O#ldX2V^PbLsGyC*|XDsifDme90v_G?dmH%dbP;FoOQ9i#-yl0nOkU2UtVd0Ki zR#vX#Z1)*i&oA7oEG{1jOe3l#t`Q|Ei6yC4$wjF^iowXh&|KHRP}j&X#L&pfz}(8n zNZY{B%D~{j{Ci(eH00)|WTsWZH5i(P7#UfaSXvnwLNr|czza&Kk{}y`^V3So6N^$A k%FE03GV`*FlM@S4_413-XTP(N0xDwgboFyt=akR{0B#IN5C8xG literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-rar.imageset/chat-file-type-rar@2x.png b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-rar.imageset/chat-file-type-rar@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..c6ec965d46c4350164d2978a57fb42c278e8d67d GIT binary patch literal 1181 zcmeAS@N?(olHy`uVBq!ia0vp^-XP4u1|%)~s$KypmSQK*5Dp-y;YjHK@;M7UB8wRq zL=J;6qiBJz6HrjH#5JNMI6tkVJh3R1p}f3YFEcN@I61K(RWH9NefB#WDWE}8o-U3d z6?5LsiOrC86=~RiS;ACgrNrBQg(m$)O{y0H);9f$au8sQcj@>Rn8eul>)B)l4kZl@ zkFIgx_tI?MCGD2&v)(m zwWP%P#TkQ~#qQPB+3zCxHtDcOPHWaV?KthJ!s((3sg@@;$)v!9uf5}aE4pBJK#$ivxblJeGa}Ve}sMfyi{dMw51#ONQ`5C``L-(>*u>81vO3dZS zNyA5LRd2GaUv>IGwZno}P2VD`j$E>wJ%83MJI)#*(YLaiC)k4OrRBQ6l^lyY(?#r6A{t>Hpc;xNVYHnPSo0UGT>5yTK+q~&}qrBJGLp5JFFICr( zy|($C@WkmZPsAT&KG52*V%76w{JWc`U5hL)dTgbUv;O)V;c4RRy7d=6O>extsH*?! zmTJ};_n+}^*Q~nc`k-dYeSM|Pg{*>=3^(#_7MTVoL;#$}DqT~eyvbYy!d zzV_x4Tp#sM^1w%J~3q4s(GycHoURh{l2?Bd9F@I+{yo3YnU#uM;_~+cF)o9 z4=`B8eryi;&a#2Y;jmX+s6L~*uC=<-_I~+SQC6Sp!lWzKYuh)Mqa{cj=@cgXpl*4| kzopr0F?F~Z~y=R literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-tar.imageset/Contents.json b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-tar.imageset/Contents.json new file mode 100644 index 0000000..44a0a2a --- /dev/null +++ b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-tar.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "chat-file-type-tar.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "chat-file-type-tar@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-tar.imageset/chat-file-type-tar.png b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-tar.imageset/chat-file-type-tar.png new file mode 100644 index 0000000000000000000000000000000000000000..e89e2981fc9795a1e984c5579ac432728b7a20e4 GIT binary patch literal 726 zcmeAS@N?(olHy`uVBq!ia0vp^Y9P$P0wkGC6jgx~OS+@4BLl<6e(pbstU$g(vPY0F z149*1VM7Z8!!Mvv!wUw6QUeBtR|yOZRx=nF#0%!^3bX-AFeQ1ryD?M5Rc<;ubuW5O_X4NkbcfmBx$;D$O4&N8lFj6tA%cD zdEs7$?RSt)Gua0%oZ93sv@32;@Q%p!?>V(-Z+&Ti5Ozi4>YI)hqc$Vey znPpe=&F+6c`{B&@bJhljYphyD``x!`O}=wT!{GTYL&q~y8=cE`JXvyGYgs~&^UTkU zxA#evhu7Xwoq4J}(&O5OJl$W9cBn`c|0>PAxcuGujShkP_10dDG2-d^HMjHGq~u5C z)7iS8UP=_Xdu8Rxr$=M-7zLtM-@S84C;NomblJ~lmS)Q9-%p=9DYE+Q{PIJ%=JpwmWkH;T{2TJ`p+SDw_(lQERm-@5*OB7Y~Ww@Hsp1;y4&PLcG-aJ zBeMK+FRi<)yLH{HDIZS?zMmHNtlak8%%BU&Q+e;*ZgaTis-Cl5`=l|quSB>}+9|iw zJXup%U4_%mEXzG0cHbr-dGDkPa?fqeXNYAR=AO!`RNa#K*<>B#)D3gg&T?H_DZb!3 zYkRI=^VBORb}u^2y>=6m@w>>CmX=~1S67zZPd;z5%IVmO{;0>NI!NS*BT7;dOH!?pi&B9UgOP!uxvqhsu90Dgp^=q=xs{QTwt=CQ xfx&_K_r9QL$jwj5Osj-zFf} zfqK$Qg8YIR<}n>uAYc&iSDkx?*#+iLj9)t}XSH8py%&3#h0{3m*TuPA8d;jc&s5&N z;5oQ-dfc~{e7Pq2%a2(rrMP#02;4C7oM_IqRcD`j9e!~B2D_u+cZv0{=VXhm&DZ`j z|J91m%Tym_BuLvD-F_CL3yijBo-U3d6>)E_8uB$Lh_D12%o9Dw((bBlypgfw&69HJ zNz?CkNvu1aSYf*D-e)nn7^`iTr<1q$F6B;5I~8a0`^2h*TU`mavJ!4FeHM$j|4Cxn z@eMX@PYreYC)&DwkvN&m(w|t#b2|Aq&xPOdL0|VC*mHF6%?P&Dwd?0cpN_hAvre*N zi&SgjkCkt0;{cOv&q_btZ}2 za@THNJAL4S(gE*>p0>%H)Alf=TAUQ9{aW^XmU++p1c|oxiH`49BwZ_gJR@}Oc`vV< z$NJRRQ&PgtFq`7uh>;cv4x(0JqN2lMe~A7MFpEQ_qVP~ zb&0&Vb%M(ue?^~JJ-!>hhnJS$;a^_0n)BZb6Ta|?I$e_a9ic0QO;<9AORZXGFzfc( ziU0W=zC9?=oE~!K#bwSvERQlL|7Y!dubo!&E%46Go$dM8zIquhe&N*+r#07h(M+FX z%>gBxS^FP6o1*N!;Bj1Vv8CsJM%$2IYd5mDPs(;q7FlrcRsXcPwpZ6iv3m{T6ebR{Zxag^E);!{tHT&p00i_>zopr0FBu_#{d8T literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-tif.imageset/Contents.json b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-tif.imageset/Contents.json new file mode 100644 index 0000000..bd4d7b0 --- /dev/null +++ b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-tif.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "chat-file-type-tif.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "chat-file-type-tif@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-tif.imageset/chat-file-type-tif.png b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-tif.imageset/chat-file-type-tif.png new file mode 100644 index 0000000000000000000000000000000000000000..e784c1381ced58238e4ca4b4bffd659f898be721 GIT binary patch literal 663 zcmeAS@N?(olHy`uVBq!ia0vp^Y9P$P0wkGC6jgx~OS+@4BLl<6e(pbstU$g(vPY0F z149*1VM7Z8!!Mvv!wUw6QUeBtR|yOZRx=nF#0%!^3bX-AFeQ1ryD@1WCj%#EA(h6YEITQ)P7Qq{pbr*F*os$#wUW@x~L z`(noDH*daQIj{0t;&fAA&erR~)jWZ^vsHJktJd#a<1?q|MCfxJ%`2?)-^dl&7rNhO z|Ngd1S5otyYVfPpNa0zAF_IFoy2ffIZ~v4=ELxs=>|afcrNoylF=viXZSQmsXB9gd z+I+G2@|3;L*b27_H6+A1n{N&}FJqj3>Gr1$qPI=!KYgh!z4FoY{jtP@YfitOboXJ~ zMXk(z=RVe6{GAx0>#**hV8kAV<;1#;-6!%HrVcLU+Vm|Rm}lsg}4# zl%ynNXo1c=IRteW& gXc}T7^aPA&uK)l42QsM+Vr-wY01cHX z3GxeOn8#!w@Zv(l28Vzd6PR^ZNK5XoQP+N6x8pv4?sbD-kqiusOr9=|Ar*0Ju5RQ# zpupo2=x~$i+kBn4<|SSGE?Kz9hubOI&ehJUOq+7P(`xhcusWapw`M)vc)d5Bi}&1= zy&2n1av9`?8sz#Kuk4adupiDpIFIrIyt3Z(AMpf#KGh@a>-wBY-CFL@6CUo zo9A`jem)b4wuKrz|Br=DSi8*U=5PDRUa7UIWyU5VivnCO2RxEfIB~pFTBuBYX|j0c z-u=lBr$uEgy?^|dbi?u0lJE0-7#jRHEHjH>-uCujYiW7G@yiEpK9HFzpfum*v{S0U zaVN#N=iR(JnYP>Ymu4m?^*`0UGIPyG{{2kpPHTV2Th9BcXZySKN|3j1t-sCbHx|q@ WSR$W22t1MiiV9CxKbLh*2~7aIa+!<( literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-ttf.imageset/Contents.json b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-ttf.imageset/Contents.json new file mode 100644 index 0000000..bc7ac8c --- /dev/null +++ b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-ttf.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "chat-file-type-ttf.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "chat-file-type-ttf@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-ttf.imageset/chat-file-type-ttf.png b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-ttf.imageset/chat-file-type-ttf.png new file mode 100644 index 0000000000000000000000000000000000000000..e6ba5dfde664735587cc151e7fc3e572c40ed0b1 GIT binary patch literal 682 zcmeAS@N?(olHy`uVBq!ia0vp^Y9P$P0wkGC6jgx~OS+@4BLl<6e(pbstU$g(vPY0F z149*1VM7Z8!!Mvv!wUw6QUeBtR|yOZRx=nF#0%!^3bX-AFeQ1ryD1e9dk_?~Ns#YkCtDJKQeKQgZBAv+3sajfR_dTNuCYX=?hn ze8=;7)s@fYR6mPpV?N8>Zddwz=?aO+#%=CpES%QN=CMWhbLDxiHrWPizHUt4cjN1! zolA6EALe(OJnB^yy{Zx;CXs8}t+ndhKP#OJftz0>+2~30SY^FC_IT4_75C}v(>hMG zFHXL?C-d~*9Z75sFLp@2%`khk_4Tx~H&5~XezoOQ!}8THXGyc)o8R6#?apt-o5o>1 z&peBbk6pj;()W{?LfC%}os|sgF=0YUms=(U9Bd0#6Ma*WXV0B;XAQU4y~yIDTLPoY z&hB`%cl))+iMG7=wx~Xycf;W2hRI=9eKn##UolLs4gWpGmiw^M?d@w9W=0=Q=k=90 zz4%EpYlROh2iqHlSW*5vUR;XVrrms+s`_bx2epf%4&4`yTrs=FtC_WS`88=~O)tOA zuQwX{wuH%CJmkDEPcCAG+)e%c{jXo9fB0_ptNw<3+t>Q^)bgM@=f@&et7O=@MbAFt z(s*?>zwuW6%PWyVoWKZGEpd$~Nl7e8wMs5Z1yT$~28QOk28Oyuh9QPVRtDx)Mn>8O zhE@g!2j<`Vf}$ZeKP5A*60X6}G{nfr%EZ#j$Pl98>IYs>0%GuV^>bP0l+XkKWGM}{ literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-ttf.imageset/chat-file-type-ttf@2x.png b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-ttf.imageset/chat-file-type-ttf@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a264bcb14e77b048ac86c64701ccd1d3bf94f740 GIT binary patch literal 501 zcmeAS@N?(olHy`uVBq!ia0vp^-XP4u3?%s{blm__IRQQ)uK)l42QujcYRcjd0&P+* z3GxeOFqp^mW5No70|7HOEO6kFV9}5(G_pAyt-`Li`He{bg=c4~MK{k;Wnf?w^>lFz zsfb&1bt7+sfdI?Fua3$c|Gb^n9cenjcrtog8Mnk=*ZVW>>b%Yk5HZ_zZ}B#pH`_lh zd=+<==S`eiWNlK@RW-GU#YdXjS^2r;#B6jbB0g+*ka+MgLg2dRiA zca71i@8VLu(x2~>?^$>}XLnECyN2<^oAPzHPc?4rvq-eE`L{7SXrlTJZP)0D%VN&C z94O{a`Jwd5tWkNQr@Qe)i3F{a?V(lseg&IsxY1g8RP_$$<0=Ua=AGYkbJ(nkuRQ&) q{QGg(%X{BlVqXPK-xr=bLpDCbD`L0skE5GFG3V*(=d#Wzp$PyWKBzVT literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-txt.imageset/Contents.json b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-txt.imageset/Contents.json new file mode 100644 index 0000000..6af2113 --- /dev/null +++ b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-txt.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "chat-file-type-txt.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "chat-file-type-txt@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-txt.imageset/chat-file-type-txt.png b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-txt.imageset/chat-file-type-txt.png new file mode 100644 index 0000000000000000000000000000000000000000..06d5078094326d326b953c7faf183a909859ff25 GIT binary patch literal 690 zcmeAS@N?(olHy`uVBq!ia0vp^Y9P$P0wkGC6jgx~OS+@4BLl<6e(pbstU$g(vPY0F z149*1VM7Z8!!Mvv!wUw6QUeBtR|yOZRx=nF#0%!^3bX-AFeQ1ryD9Q75Rc<;ui0k^CrTXucz$Mv<_d+5#Yt-eTAYq@?c!R* zSQ;d7BvL@+_9d^QR~NQ6IU92&u^seWtMqEY1BH$$O?jc+O-mD4eLMb7s_^R+eP6Wm zis#?EpZ1-%t$F`<@A+yQ{Zd{I;rYk6WiHA|7Fn??B~W0pq(#nj&gFY1tZ;O-^}WZw ztme}_+vvwZVJh`Y7xp}N`+D;D!%GKNXh~dDUtj%mgM;tEj<*+glo+hgl;}IQw7oMv z)_OxkOtnGQI*AL}MVflEnFMY<*pZby%`kbtr}|zm{@*!^|L9MAzwefMc>gv&?p~?? zXLF{Xwz{>^Qd&@Z_1`&Lq8mK^DsR}q^yO8!utw#|+syah80JsD>LlrJ>&^VyJZ1AD zb*^JP)#-Ow-QR4vHm9>>L-w-R(%Uoi`z&9qjWoYo7FK;j-&g;fCp!1L)aSM{54M=^$cxgvSrFvjAJ)I<;I-Uk7wT`^XNj)Lu%4S)#M>K` zvG<%tgvM)^Xl}08&GN#P&7pH^OSOOzt6Jh3QIe8al4_M)lnSI6j0_CTbqx%4jSNE! zjjRmJt&EJc4GgUe3=Yh{_XR~mZhlH;S|wbAp=pSbk(G(1m60Jt!_^PGpoGNW>FVdQ I&MBb@0B=(mga7~l literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-txt.imageset/chat-file-type-txt@2x.png b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-txt.imageset/chat-file-type-txt@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..282eafde62f653f019686bc949f73f620950c0b7 GIT binary patch literal 796 zcmeAS@N?(olHy`uVBq!ia0vp^-XP4u3?%s{blm__p96eCT>t<74`hxgu%I#$6fOZJ zL4Lsu^Oy`KXaqRO@vK^+1^$(mOzg^H*A8(vRlU|{U--tdhRB#k+TkKcvJuK zVRd8T-M7~by$?G`9Q$a$)7!-3BG=Ng!i!f@S(cq}@yk1Y;359Gr>6YIAY})K4ADGLntZ`U- zI`6$HbJLa%)11_6Ph)cR+3cdX`^RlN@v}wpG3%wu2$x#_8=V(!rDsI%_BmBJ^{jGP z#KvvBom(GTT$T9TAABsM;j8Ip*SjXC7;Z__mxMR^l}x*l!Ny|S=~uF@a`oZ~8-A_k zsq}Qwx!3t&!p0zh&9jQaZZ7V&64|(Ib-bOZZc^r#tGzzzizJRVTS9yC;C0|u z`i19@#A~g#hH_mvVEc-Xq0zo5uW0w3xznW6El)?j+nbeU{8(Pkuq<@Vx|91s3Eb1w K&t;ucLK6T$YWmp# literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-wav.imageset/Contents.json b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-wav.imageset/Contents.json new file mode 100644 index 0000000..b5a34dc --- /dev/null +++ b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-wav.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "chat-file-type-wav.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "chat-file-type-wav@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-wav.imageset/chat-file-type-wav.png b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-wav.imageset/chat-file-type-wav.png new file mode 100644 index 0000000000000000000000000000000000000000..b83f8f76293b9c3357235559b612182aec0eaf9e GIT binary patch literal 844 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 KP-`jBv3~)dd1&YW literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-wma.imageset/Contents.json b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-wma.imageset/Contents.json new file mode 100644 index 0000000..39136fe --- /dev/null +++ b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-wma.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "chat-file-type-wma.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "chat-file-type-wma@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-wma.imageset/chat-file-type-wma.png b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-wma.imageset/chat-file-type-wma.png new file mode 100644 index 0000000000000000000000000000000000000000..691fe3dda67feeac73a5da7359335868a09ab4de GIT binary patch literal 876 zcmeAS@N?(olHy`uVBq!ia0vp^Y9P$P0wkGC6jgx~OS+@4BLl<6e(pbstU$g(vPY0F z149*1VM7Z8!!Mvv!wUw6QUeBtR|yOZRx=nF#0%!^3bX-AFeQ1ryDH=O_J@r8Vuqr}pQHngW3uveaSZV|{`Q);cSs-u`-l4` z$;*0^U3m1i9O9B+nJLD?`nD=SAcQ;GWwsJW(;LN|FPKBN1ZN1_{^5Ar)FF0pQOBAk zH3?~odwD{xoRVBVHO=I4?y=af`)605v;AIv{^6bKbE#@)gBp)JUw!78@=ZtO;jHsc zl2L6kTaJpVf8{)rxmfG@PPwAnEs5o8PG3n0{1BWb{LN`~)!Ugnatws5wye0G_x8}n z2}}5Nr7jiUOq_7#VN8`?wa>GAPn%Mo6dm^1wKQ_=ww*C5+zP7iHXO;(e6uq4)|?CT zZOt;5ev8jqR=fG~yP3D_j|WA?{>t6(H1EXu)ERp-Uma7e7b}|Eu;r)v#wj+xuPi>r zCs@dSd(L3AkO?trj zB6P{Q8R@ImUQu3nLO3<+X|-ybl<>RAwH6Z66M~XMmTRf*deT{?nlgJy+|ff)JrbLJ zDhEy3+9~ctOB+!|E?TR8~bSbvyg0e$%DCiu}dTe;sY*jnq27!7tjzY*E0< z&|7n_E>)BGz0TcZzWFiU-wIkemz39+N^Xx>Yg2A}A+xz=<<9N@_GS6(ez~wt_?*P& ztM1|@-WJR5Pf={1Rr+{UQ1Hxe{};&G)@t=y&8?ileWLzN{-J04wy^r0{VY98Pg7fD z$>AWSzUNmK-t>RPKJDacnP;~0;lPBYTH+c}l9E`GYL#4+3Zxi}3=GY64GeXS3_}c! ztPISpjEuAm46O_d4$Qyz1w}({eoAIqC0v7{X^4@Lm5HU5ks(CG)epR&)GZ0JAviy+ pq&%@Gm7%=6TrV>(yEr+qAXP8FD1G)j8!4b722WQ%mvv4FO#n;HZ_5Ax literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-wma.imageset/chat-file-type-wma@2x.png b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-wma.imageset/chat-file-type-wma@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..16671c2dd282ae0cd7680b2cfcc51f590b46659d GIT binary patch literal 1441 zcmZ`(eKgYx82;HzTGkCC6t1ruS($3&I~tc{7x~RbWyrVT(&j71GE<5=j6(Fm#VmG@ zn0$^2Av$R&VlL&HMsac;Cl3m4kQLpe$6QLXLQh)p)}>H`{_Y zyf9)kGBK5Cd32JtGB?S)JwG*F68CQCPM9MYrmq-gU1g~$Gvy^@u%jozHH31g?4~>R zU|F(N7aai^)!YI=R`BWao8of1VniKEe?nMKKe)!FGAP}w8t89qgvkj(L(#`)O<(q> z9Tvq@OVH1SFD)MFp=!K$bIAT=S#Dz{h~YLeK?8118mPj}Ne5xv9J(-)q`9N!Hs4YS zU!O)nae{%xP(pP&#hR1PkCG=;r@cXQJ%ManBQnfj8xqw0ejj2vqPxzn&kg50Pq3)Q z*Vj^QjNa^Na8olAJP2&VB;zxVaO8ssiv3*Oe1Atn!BzK6m3s=t4(k63K4T##6(7SA z2H7L*q^UJBWZh@&5qqemotbWX0;F`kUXokl>Fo7d3%Ij|0C>XWAxclQ$!aei=gl>-evkUoOf3P*nf zYlx){nt#G@0L^39_1=dj{GuJH6sbL@=v;<@ZW~`K{F5o4Jx>$_(;9dAD2%F;hWcgj z@|`Y=Oxq=iw-vNFhB+-DSprf{+==}I3?go~ecG3Mcx zV)K~|mB)IRKO##has`I!KD)U}eW73Tk=9M8+ICi~k`S zC{Ew|P*TF)UeubkiBR2?Yl2TgTcadpx7#8|lShvtJz}%oCO@)QGIUWZuw8ErpiX{P zH6&%)cBnHTqY!i@+q+5znlKPK?wRp?g}b|HC7ItsO^G7=I?mk`)`l2Vd~r&m`_O5x z#Iv=_NVGz$s3!?VsQ3A@8GuYE_1SKLUkZ|R>Lp_@FWtghk>XvY(i z8u$KHj>yI)xPy|?nP*lgwwDCf>F=tZ<&rU**KXQ>zWGECw;$E1`SXJsx+0h&x`%u z5es;>kQ``P)9+LDp9w{E1^gqh<)oxGTHd%>$8dONz!+;-r1#&s{NKPz1>{!=F8k~7 gi&HF{f0Detqu`d))_}u%W$8NwTpV%OS_cySZ>gS`_5c6? literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-xls.imageset/Contents.json b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-xls.imageset/Contents.json new file mode 100644 index 0000000..4ecaf84 --- /dev/null +++ b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-xls.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "chat-file-type-xls.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "chat-file-type-xls@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-xls.imageset/chat-file-type-xls.png b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-xls.imageset/chat-file-type-xls.png new file mode 100644 index 0000000000000000000000000000000000000000..98814f38de051cc7e06737a783960768ebdfae6d GIT binary patch literal 740 zcmeAS@N?(olHy`uVBq!ia0vp^Y9P$P0wkGC6jgx~OS+@4BLl<6e(pbstU$g(vPY0F z149*1VM7Z8!!Mvv!wUw6QUeBtR|yOZRx=nF#0%!^3bX-AFeQ1ryD&t0VSm-y~YVkrYOpC?Mjtp`Yx0kQubQI#l`7{qW;wOMf*!Sd3+Q_?k>4IS8vza zExWC5FI+Hh=b86&r@yy(zh{4W+Kk}#goBSe*LrD8v+nlrmJ-&SBzbYwNm2E^+ZR~* z-UxbB<+4BXvD}Rioz#&(YR&5vI$DsJu;lB@OB#uf-yc>o`c-l>PC}fIO|tf! z$g$RT&3Ef$A_8M74UF<$Z}82x(-UJ7SWz5ewY^JfoBw(<`9p_;u6dv7PC0vHb*0{} ziiicbm&SMH76hkSrtZ@gm_6y|PL1u1tY7;NbeS%=rsr&TJNZh_4o1z8+Y9e)NN+MY zH_ht#j2)-VvI_%wll;81iUUmMY!>8yYnFIxf%4|{pSJSte5&>HcB0`qroY!L^A0SJ z@jEpobf2VtOv*|&o9`FdzJF3$oR@JmIrRoxz(S`Zn<_UhIl!u!Ui^5UN4oE-y+sN4 zmcQSfy)Jv3+MLZR{@#H278{<_tQiDrvBj7 zU2-5Rv^Ak|hH$FnDc@K8%qbI}$hBL%1tta664!{5l*E!$tK_0oAjM#0U}&yuV5nnC}Q!>*k;TjB0LyU~9Of0R83?Uk>e&7WqJqAx# KKbLh*2~7YXa5DA) literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-xls.imageset/chat-file-type-xls@2x.png b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-xls.imageset/chat-file-type-xls@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..63d4da1235c9ce7947dd7039fc08459184adbe24 GIT binary patch literal 1064 zcmeAS@N?(olHy`uVBq!ia0vp^-XP4u3?%s{blqTJV2ls&332`Z|36S<6woLH@>7d4 zfJT>;1o;Is%wtN3F!(HB=kfN}?;nh9o}4?f*jcz_u5&DLSX`?r%qsX{|DS&n?cdL; zxw`k9-n)Ko_*XftS2Mgrgib8t>tNQt6TL0oc%9!uDYMBd%5D`t`@4E`tFL8}Z9wv@ z_jiqgKhEEh=3KQrHFV{r*!*ui`d5y;S$gbo{{;pHCKgW@$B>G+H&-0JMG7U3e|&%9 zPw?VPqM9vBg%&C?bt^17#AKw!rK{0o!x~mrf5n6Aq^y)r| ziaB@Xu7pi+zA8&_bYDW2_GID7YmP5@W!PEeGfQsrlH*HW7;;wm=-8@FlN0vt?_7HP z$fe|@mxkiAk8<`sYx(DP@Z3eEGrhW&>+HTiKNY=c&(!Vfq>EWA65o9~GUL!>nU#CP zGjgX^#7W&-Q#G}x`ko@gl<7-W$M64}kuBT~5{yUs0<=2f=Q*+o-k&USfeH6iTR zqt(qQ{ zS(A}}cisH#|7G?9-%mf6{E?aKYxJe-V?u0M=h~Z5^QAw;O6_CW&6u1mc}>56tD(>v z=Lb=B&f&ajuFBK3#2Z(o{`j^0q-7j?_1$ULmM2*)e0+WP-}?uuAISfeZ-_9OwrS7C z_G>{J-jBSz<+n{f>DFg9v7;=C^Wj7WK~tSwCvwF1RT`gpwIy(~+gT~o>?=BFHf>0$ b_$A1|5V&Bfp7FX5prr2U>gTe~DWM4fs~JTw literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-zip.imageset/Contents.json b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-zip.imageset/Contents.json new file mode 100644 index 0000000..1dce0e8 --- /dev/null +++ b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-zip.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "chat-file-type-zip.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "chat-file-type-zip@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-zip.imageset/chat-file-type-zip.png b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-zip.imageset/chat-file-type-zip.png new file mode 100644 index 0000000000000000000000000000000000000000..5f7d0c98acf7d684ec66872e9038d6a9823e173f GIT binary patch literal 708 zcmeAS@N?(olHy`uVBq!ia0vp^Y9P$P0wkGC6jgx~OS+@4BLl<6e(pbstU$g(vPY0F z149*1VM7Z8!!Mvv!wUw6QUeBtR|yOZRx=nF#0%!^3bX-AFeQ1ryDTi0aQBTdcQw3;piaOqi< ztnBOJ;A>J);$X}+3@9uR+hsbLBdZ|e=t)nLowB&h$u<|n@ zeLk*VcRuYq|NZX&d*Ao%e&4sstwpy#^S4RhDlyhmc@aV`XLw}F5A5g(k9xHzwR(0B z`@7$3UM$?VLbLN)_)5){2|oK{MD+N2HtktcXSsJjKX=HJ)TPpoA01qv^gbv#re?;A zSGO8nAKhvWEWF+ESM62dN{NOGVaumvM_!t9SZ&UCE4w${vPJe5*3CPn_M@TQn&X+X-)wx) zRT!Cn=ab*^NXer+HbfrJG0wcj?sJ`s8OhE@g!2j<`Vf}$ZeKP5A*60X6}G{nfr b%EZ#j$Pl98>IYs>(qiy*^>bP0l+XkKMA0I0 literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-zip.imageset/chat-file-type-zip@2x.png b/Antidote/Images.xcassets/Controllers/Chat/chat-file-type-zip.imageset/chat-file-type-zip@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..77be3c580ccb1bfeb83a805fb492447f2a696d39 GIT binary patch literal 795 zcmeAS@N?(olHy`uVBq!ia0vp^-XP4u3?%s{blm__Zv%WnT>t<74`hxI@P5v6kpKNk zg8YIR<}uxvpY&CX1XEnZXHKj-J%)>JnWanN_1a+!gFvES3hF{C1H%~eOf z1_d6MK!rGdzU=qy>(2Dg?)q7BmGk835?9^xJ)bNC)4$z0)&DX)db7>9T_1fG9-O&J z{H$3d2I%d^+v;2Aj60hC2O;l|63^7ajMIQ?BT_o4iKOI;`PM{mX~d zjfr>PPCx6-3?ke{xcmoQ~Zu|Kd<-vyY-8e ziz-tYc04R>Pd;&;vG?Y`?mZLB85XdHUgMspUr;-jCsRmD`E}^GU(=2{T)4r!O}1(G z#MPhA=0&{XmVSTG@oB=$>pds7KDbb&;5L1~$CIL>8y}~(R(@LKc6phszs{})UGMs~ z>b%>z>+DK~dwMQC literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Contents.json b/Antidote/Images.xcassets/Controllers/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/Antidote/Images.xcassets/Controllers/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Antidote/Images.xcassets/Controllers/FriendCard/friend-card-chat.imageset/Contents.json b/Antidote/Images.xcassets/Controllers/FriendCard/friend-card-chat.imageset/Contents.json new file mode 100644 index 0000000..905b96c --- /dev/null +++ b/Antidote/Images.xcassets/Controllers/FriendCard/friend-card-chat.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "friend-card-chat.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "friend-card-chat@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Antidote/Images.xcassets/Controllers/FriendCard/friend-card-chat.imageset/friend-card-chat.png b/Antidote/Images.xcassets/Controllers/FriendCard/friend-card-chat.imageset/friend-card-chat.png new file mode 100644 index 0000000000000000000000000000000000000000..535ab440f6d03676991649d86163490900abf9e9 GIT binary patch literal 1090 zcmV-I1ikx-P)!nP@#EeL5M~r;#v4fkY2I6oD^& zSUm*21bsmT6~2U01Xd3bMGsb*FQw536_!>cHARM0WJOun*te85>f9dIzTP{xnem=8 z=iECF{b9km`|Q2;`k#HyT5GR;J7h;UF2Yirg%dFsGt&LN*o~bSz*fA4p&WCSf^+Z` zenTar{E8>AxaC&YVKH7Y(y#%n!WCGA**GG}Y@C5Bu^JyWjNORSTS=fB4`9FAQ(c9V za_Bk*58{ucYY6uV;-z9f-b<4nz(e9mPZV?TC=MpwZ{nB&^p1)J_$p2GHI|exM?bz# zbL_ypq9-_37+(=9QrgoJtNwACYddBZrML@Q)JV)2zk4A#T9ByVMRXLQ^sc1vTM-vp zg%j{|n)}9yDmxB;Vi=c9R9Oxz7ew}$;48K!DOy*6QF*aB*>HDW1vAwAdrJdV11?TB z42l?*8CN9*TM9HP4?6IdTJT+iGqWgoJPp3RaMQBm6C=}^VXVi=%?#d_1}!bix(s;O z=t<`g?r<3QyeD;@Q?89o;Tq#-(Hqe_*5H3qr>Uizd3f|Y{FdMY9Mw3mQ@n@O>vp57 zi9ToJW%SfHb_x$cqzmoFf+qW&FTC0zbmEJ2-B+YVIg!QTTqibm2qFXNy1zh!^5Vjb z{U5=R)gQ~mNAzit7UjS!@x5lP2i#OuFcm+f#&)hsH85wDo$BJty{U0?>+BwZ9uf5N z5UGe_2O@PIOpRB!%={X*j$vT4G9taYHZ}f^(^_JF;GQOp9ZxniDqW}c-W^{y16(iP z2i_>}G%B8s_tVX9aB7Jp?ktEz1z(OfL9Yms72H+=foY0&-EY75oyb?=2M1d z(214US1^f+NF+y~3ooRbn+hV(ho?&-P?fdywbv~pDMzo@#e#54H3VZeU8CVc-blYl@~R#b^RJ5Hy)cqy$){l;sWS~b0$@|kqT zQq3Bd;4)Dd+b8_;4pE*tV00`KCs~CQo^zm*YJo*Ws}*U1x}_1_Y2ouCYiNz9zSHoOc8(H zR@}a$Q8r8E(^kcRSt3@QC;q!KJ4vV5TJIJcxjs>Jo038Ic9FzRI?ThZYDd@2$ojTe zngNT%miP_)ZEPaXw=2EKgXuU|oO8|>PUR=Ot9|vj|1l>11+pILQ)x7>1ONa407*qo IM6N<$f)We*HUIzs literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/FriendCard/friend-card-chat.imageset/friend-card-chat@2x.png b/Antidote/Images.xcassets/Controllers/FriendCard/friend-card-chat.imageset/friend-card-chat@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..1c48e870cf802f739e28825820bd888543a476ad GIT binary patch literal 2199 zcmV;I2x#|-P)(fB5Hzo#3P_a5&T0C1>uJx22c?2fPjc7E+E8%Lk@S@<=P#8yxA~Q)jel- zS9kAx$xFym-Sw*8)cxvp0cPj`^aCyix&WPl_CRBx7-$wtR{>N4CxCsxu9*A|Y>53W zPZqQV9t0Kve*#g5WFN2)cmQbQS!n{wdB7Cl8=wZ~j9@2cfYrccpv3*+1&1quxky*z zwh`>48ki6Cbh)gKQ{dpcdIK*2BhpBF9QXm)gp3L0z#hbimB`ouGL{s_q!TjMbOB0% zzChCy`9y(FfTw_8(=JKCxd>Q5@@}aX*a$p^RAiw8`8Gr*22Uc!P1a&g19J%ZI8y*j z1dd@}5xanCh|%1pBQPDxzb`&ByTa{(9LA^3!2G&jeW|KwpF(l~Q>Ry??#Ss7CJc4Ei`Z&7?x{3`bY)RihfYPXVxu#4?`% zx|vi8q?!IqqGH>DCMK2gh}OV<63f2Cs7A<2T-_xtHL8)f+>YKm3^JumWAr_$cT6c` zkhSO=rA8R1C{l$u9@IDbqtCjG^b+bm&ny#4_=L|%tc$r`D^RK^P=g$o)>m#spK)E{ zr2@|@3M}(7a~~1`4x+EcHUbX;&D~aDlal!zZf6((lAY5Z2i^xRcO&C=Bo1O{fL3l~ z6fhpa-XQT^`$C|*lNpavGWpiYmj{@p=(DY4hMA88KjaAdx$?$bUm6mskfZ5zh#-4? z+mR!Stcd_Ul)r7u<%J<*Z-(hxBmT=D0_SF%>1Gm}-&NVZD1IBCEYpB8zebS?^qNg zGq)CY2_onNS0{&+2r`$t@Xn4%_hormDuSG$$D=M3>oZ+ldhbZ!9;^R|06!^z3%rZI zgSdI)Y8G-kSz|DXQ?%VKDiI{gaAwMzOcq#W+z4@=j!&5HwxqJ$Hb@Q7$13xsO2Q|c zFJIvJ2lovU1wOONT=mD=fwNbpgNEv3;HK1KF`H|HeqSP^O|g)%2JZ|K1zxvO;v*%| za;Hlf5Zd5PD3EwL44k7XGQc9?)s7d}|E$7WW7NrTD`nOxi8fHb#*&_-e~#|7ylbV< zAPa>iI9Xz!vkx=Ih$1n-ELo%^tiZi31V1qsbH=EXc2M!YWK zEm(^<8;5~b$XSr-RuL~tQz_jIxtp#&_*~Z2;1AjYM=);yRlZ6``N7Ej2=(DP`0Ors znheFdJbsW3=@#NT^qE&JHq$g8GZTNzrtIYFObRnuc{oTuz#Whvn5HW{l`P97w30eU zUYWtOrf2}XiNt>N^h#QmRHRNK+=_0^GMAKciW%s^bNntZr&F+&==azC+B!;rw=o;U zITuN}Z&(DZS01Xy9e<^4X#`9~yl1>V$8cJbUIl52eqTF^#9qvWCP+lL-Z?x!4)Fl| z1Aot&GLch2vE7DYYvk}0bUpPR*)gau})jrie>_GvET` z>O@$*^VcJFq0tL{%OnbX&)M&Kq)S8K7Q8>B4x(80JY%sQ5H}&MCSCdhuK<7hprApK z1pllEFxw{K7o=_(1;}pjvjk%S<~P}_R^}X=gl}QrXEz6KK&F`{k3Pd72{D7mTO_DP zW-@i0j||2Wkd^ON(w|};jTy}<*koR0b)IlvM2$5VMRr5WW0K7x>jdy=%n0$}0hjoo z0{kX3QTV{27gr){gK^kL%jrSz7jI6=Q7k^2F_z>XWwDbQU<>dD5|FsDjS*Dl`Jf{F zBAQcsofBLMFbTQYQ;Hsi^cdndRE|U_SdTc>Wpk&!CGZQGO{2reR%Cf_I#t2~q|!Ra zBL50_7IFuLjiCl*8X2%k$s5EYM>}X56v1D8RB3)c}i#GDAsfZIxT^Yq2CPn81t3r zq@2Nr>yAtrgFpRmvz6V1V0WS;vTJO*GM$oDgv2Lc7~vUPmJyOK7DbS5%n5$xd7f=5LZ#z(nK&$w4&EQRFNsloSEi11};DeYq?$4luKAd+LsSN5pDkPzij8Y!A%?D)R>Mjs}QRTnl6XuR@Nm^W@2sCr=(n Z_#cLro~T=L=9>Tj002ovPDHLkV1jDx^Y8!w literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Login/login-logo.imageset/Contents.json b/Antidote/Images.xcassets/Controllers/Login/login-logo.imageset/Contents.json new file mode 100644 index 0000000..2cad525 --- /dev/null +++ b/Antidote/Images.xcassets/Controllers/Login/login-logo.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "login-logo.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "login-logo@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "login-logo@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Antidote/Images.xcassets/Controllers/Login/login-logo.imageset/login-logo.png b/Antidote/Images.xcassets/Controllers/Login/login-logo.imageset/login-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..f09ce028cfd1bbacbb6ee5f9c422a524bca9d7ac GIT binary patch literal 11512 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 literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Login/login-password-icon.imageset/login-password-icon@2x.png b/Antidote/Images.xcassets/Controllers/Login/login-password-icon.imageset/login-password-icon@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..be017072ee25dc4b7f8e51bd3d73610d06d4dbf8 GIT binary patch literal 474 zcmV<00VV#4P)W!9q-v zA}=ChDO#DlfJ8*h8^}YGH;^(IQ5!v*1cO@asO!Ob`*b-B85nMMZ+ z82(pn8gH?W^YA@vV5*ai2e5`S>|h?V;q&+y->ss*>gK)Jl3ewZTk@Xb0GsHk65utC zP|uJ%fd*bx)x3sdEacEEN`Qx|0GN|p(LfH(AWrb2U1FC1X&RsKI|sn8(6qfPvH*cdtM-lNX7`$o zAL0j|;cJ}hlZ@E2Ec7Ys3I7wvkFXs*c3X++K{}eVSr!|O+Bc?Y*B9Y`fHDAee878* z7cJ6uQr%+fcpULCW{MOk^9!W6+FHx34gxHv;y2v@NDq@DyJcyBMk+ooTBOV({EVfD zzjOoO94jUCxZ{K9-vDS{1Ba4*|2e)@+-ovwAGAw+DS4@=`f2FM^<8si7i30ih}HDU QhyVZp07*qoM6N<$g1UXzPyhe` literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Login/login-profile-icon.imageset/Contents.json b/Antidote/Images.xcassets/Controllers/Login/login-profile-icon.imageset/Contents.json new file mode 100644 index 0000000..f794cc0 --- /dev/null +++ b/Antidote/Images.xcassets/Controllers/Login/login-profile-icon.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "login-profile-icon.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "login-profile-icon@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Antidote/Images.xcassets/Controllers/Login/login-profile-icon.imageset/login-profile-icon.png b/Antidote/Images.xcassets/Controllers/Login/login-profile-icon.imageset/login-profile-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..24bcc31a5e83f9461b0d807d9b90460d187b10dd GIT binary patch literal 496 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YDR+ueoXe|!I#{Xiaj ziKnkC`$I;4F+ul1H%F4*f zF5sNCXy^V_D>qtlNoQvW%G_Ec-+V>DMJ;IkOtU5Xy6nm=ZN68ZxBSleMQeiL(uIPN z8|S^=!W`M6H`T;CU+Ig-<(1M4YeS#bTi;_15}Q*UT(~x2bMo=(XXbymyner;n59MN z*zMA=)QEPM@~1m4Ixcv2RBXnES9t+}Wt|*$#)M z@0nJ&RmE1iQ!#JNd-I8}4%wgBZ25jymeo;U7^s%GMwFx^mZVxG7o`Fz1|tJQb6o>N zT_eK~LnA9g6Dt!lZ39Cq1A`lE(-)&?$jwj5Osj-zFfzopr09;hKw*UYD literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Controllers/Login/login-profile-icon.imageset/login-profile-icon@2x.png b/Antidote/Images.xcassets/Controllers/Login/login-profile-icon.imageset/login-profile-icon@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..7038944c0ebf306d897ced496f9782ad92cb87a8 GIT binary patch literal 573 zcmV-D0>b@?P)z&M^}gI)?+``U+`${{!x+Be5oQbKPQqn8$L5?^ zKQ7`m#xYoS@pbr)ZEbjiVh7HYE#L$mByz{_GKJV(K)@*OCvxwJ=Ik$1K%Z!^6wIgQ zFCySARwQzVF@uj~3V4cIB6kxeMAMcgU?LMRkigv`{Glz12-q%~a4vy+7rV+9uvD1P zrv&b#&TYOW_6mDF)`qtmQ#f0;09n!}Z8#UiCsh12Do zhV#NNQcg<87!|v)At&|>M~fsYata#woV{mqVslOL$^buu#b`US!X7MIuIUQ2fF9?JUpZctwSqG5Hs2{3G}YQsQ74lhD|%00000 LNkvXXu0mjfj-UG} literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Mocks/Contents.json b/Antidote/Images.xcassets/Mocks/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/Antidote/Images.xcassets/Mocks/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Antidote/Images.xcassets/Mocks/female-1.imageset/Contents.json b/Antidote/Images.xcassets/Mocks/female-1.imageset/Contents.json new file mode 100644 index 0000000..39363b0 --- /dev/null +++ b/Antidote/Images.xcassets/Mocks/female-1.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "female-1.jpg", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Antidote/Images.xcassets/Mocks/female-1.imageset/female-1.jpg b/Antidote/Images.xcassets/Mocks/female-1.imageset/female-1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f657eae57b934f3fb439f01e5eaa2cbd2fdae093 GIT binary patch literal 5464 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 literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Mocks/female-3.imageset/Contents.json b/Antidote/Images.xcassets/Mocks/female-3.imageset/Contents.json new file mode 100644 index 0000000..a40894a --- /dev/null +++ b/Antidote/Images.xcassets/Mocks/female-3.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "female-3.jpg", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Antidote/Images.xcassets/Mocks/female-3.imageset/female-3.jpg b/Antidote/Images.xcassets/Mocks/female-3.imageset/female-3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f112175a4695946d98b69f7f6ffb25015394afa6 GIT binary patch literal 4240 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 literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Mocks/female-4.imageset/Contents.json b/Antidote/Images.xcassets/Mocks/female-4.imageset/Contents.json new file mode 100644 index 0000000..79886d2 --- /dev/null +++ b/Antidote/Images.xcassets/Mocks/female-4.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "female-4.jpg", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Antidote/Images.xcassets/Mocks/female-4.imageset/female-4.jpg b/Antidote/Images.xcassets/Mocks/female-4.imageset/female-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..48eba8b7393c11613e41855474d46d69b4907997 GIT binary patch literal 6210 zcmb7`XHe5$u=jrep$0skKw z2qhIYEtmoX{0k$Q01%i00s&J}Qd2;v|K)%vzz|AifQki1%_^fVVB$!_<`C@s4yP%MUe~GDc9PTUW_dgA85I_O`-yHxjgo2U^1W^AAN-zTy6d(wQf)WD$ ze=~q605CIz1t!Bv`A^<2_AAn{_#NA|9odU%fc{?&1v8i#PzAtlSszv@#i!h+)D9I6 zPbp3r5{`2^`)W*!g^Oi!Ib@OG9O#Z9Gv2Ul(lPt8YecCwe8J-~f4LoT_E~@sD%{y`_i91U%|#|DY{q>JQ>#K8 zeuwe(0MTxL_I8-JlP%f@@wON;W(ddY{m8w@Of$dEZiWm243fZHs z=vF3s_{0tK6>x|UF~r{p7OS~8eo?tyVQ&;m*Gb-fk5IURy>X09@fW1zER;e**c9OIkT^9MzL9E44PyH@S`gt1h0EaB&{5lA605; zi&okk3Mu`?mMt>fik~&Bab+UL%$PN`FWwVp{3w) zF%IfAUk+4`Ru>(d|4`_rX{|zT;q$RilsT7+y;)tVF97NAi0g%U=^YiOWaBE*Jtq^m zufkHYQQxAlZ`p0dszF*1e05KrH_>!y=;n>I8j+7~xq}0|K&| z=YeXttk(SGPH+UAH$AV*X>m>+_oDPlSh}v+LlnD`JBRS(GVJwC*ozO{G3TmCKj7@U z#^V;D_o)J0MJDEL{F6>TT}8ZOH?sYz1clqw;uUKqo~ z_t+xpi1>fS&0GNQ93tL%{w3X4zNGNejbJK{yz{&Xy`;cdG2Xm3kr=Tb^NFM}I1xc*GCUFn-<{ojUq) zMb#vM1D@LJFGxX!W$;dyRc)7;-Q_A96>a2pTP-%HRjI8bO7DJAv8rMEg9+9ry{%M3 zyjYFijFKn^lYh6fNt6-xq5UcE zugi#@*Hc{9JUPAj?_Y%sNFwlj`Aa^7hK2Vnx&Nx2`>CE;SamqqKCTYR{YM9nq-4YL&naT9JGSgokOOM1zS*7tql}up zhdpyXmA8E31<*{e^bL1Ta~hU1A<=DC9W}*}ecvd)8+r`m(P2feN_c2_GR#jCA{l)v z$tlAz8*qb`>2!|*?npnCJj-E1F)7i#mh}2{DyVqbvNytFepD`0a!0deEaIyoHYe1u zl~_+}P-v7yUGb}B-8rFgCZbCH=<2MI4dd|^W8Vc}tTlidYH@QYD7dG}qaFEm6Ry<6 z6lN7fypeeF#GISl~GXyP#Cp{ld*5>vTi0?o^mE_kVFPx&9F9H802+U)Js&`o0kL^ zr+8zyHbFpkWWQ%&m9ufJQPk%=ZALFvK~(iY#+r!UGpY_U?Y)hNTBZ2+eGcG<-1rRb z1xlcPh_$Nt6RW6lTZ?^8%cI<5`)t{Ukl3qI6Y#s^{6hVgN@+q3YiBOkc%ag=4=3rV z?|;4|W^NdyY8f{=Msop-UHkXHKh>R@HVE+vJM~-h#h}B7p%_%n7~6ygvwYMty5(_Hk- z9xnBgk4chKV4o4Hv0cQo<`|%RC~6=t`qnphr?+Yq+6jpkO_ya&>uPkr1By|St97gUWH0q-eV)A;PbDAY1uoGZf0Okne~LK@S8ibII) z_nfdo3ys|yk?wjCU&^`ke{#;x#G$7O_)Be}~FoKRYf-6ImDo zMt2u}CQtis3h9~br2ZBg@t>_2d!-+K+Nd!I}V$0M?Z;>`T@r*?SlC2u$>#>ZjKh*{7mWtj~3 znLZEJb)83Lr0U*moW8sOpLwl<>T0n` zVC!PjMn(y(!UOi1MjdCBg(39KJS@uP^ewRzM^*U8!S8TmNzQFbHt9vyR=LRMBRq@h z&a@8xeDJEi&3ICPc$k>Et~FK=_{EU>q!7P1-&I7mZ}$E?&I~e4;*v_ReaFWX@mX^Fk%|<) zEBUNUNZ;+*I8|mfp&Bd6jXl1*?Nq$i4J9Ypn2v$devdV_=91ovn{TIzTkr?KnjkfGLC zR`5Ii`^1R%OI*oPZ~XsspVI3vUO6$c(^JvE;UPa%&YQ4eToG6mU_(JM<*3vhBY~cu zFy^zY@Aj~WWLjqwlgv0PWus(0Q2m*6ZOnDlR6%a#Ck8&#^S8Sqja8&}Cr+PZ&Eu_7G90>2zz@>0u<_Ay3u*1`c1~QAE)PtJ z@OyNl(`J5zFqJHCxxrO1?bKdxV|`o5O3{CGyFbR7Ba{-RhF$O`I?LjA^iTs=P1NjX zt|0743taWuvpg!esxiT;T{?0vN|j|d z+w$QPe1SiB4K>DY_l&%pEgC3B%g-8*PL6BqM%~kqI|8Qx*?pn9e%+wafG4jaO^AfC#|96oAQ{Pp=1O=zDE>VzSoj=W8*}E%T6;TVJ_w(MoE8#Ueo~N_C-uH3 zq$>0Rkd-ZaRo#ZSX%U2_q@lESQy6+P6-pGk?%uZ>$=20Kf_b)NyuSe0W23YCySI{K z%M6NszEBAvhvj^m^g6#5yMJ=N0@t17JGS}?b$uO5K5=XkMBBD>PC8WbgO_y9(s;8` zdK#@306}N+kMo=+XA*w~hGO^=F;VoZ^920!ZO&nqWo&iHjA%r(YGzlqkA!x*p;x~b zmYVX5I^M8FYXmpTS6WFrk^7!T%p|3_diC}ZG$+=yx1!637J1<+dp4nl+cj=FGZi<_ z@SRz#?5wFzThSMyKg%-=@d z_E%p+2+S9?2*AzoZh^<7^?1Xcxk2Z8`jiR5(>`bv7}#PON`E0>H1QsLez zKhW`_>uR(M&BT<*>w_lAJ<26ZJD)WIFvt3zmoDiQu-BPaHnBZ>-j-p;>HuwxN@S{Q zlzTEb93Y7^4`)(Q_^Mk6JopijVl@a#u&Ok3p=R1k64A|?>p;xf{N!BEcV)%>aKWfm zG?kdqLLJ9W;KIGs<$mhzrsS_4jT>aU*~^EXZ+{2puUc0vn;mBSl%zFvw?TU{Z2OT8 zySuq3Z{B>CM$jB##=IO(O5693yUK4F;8RTOoeFb74c8Wq_-J*hRTxP)5mf_3{rePGQ>&4UG}w6tw{q zS<@#drc~fEwp3jQ)w*@JR+HJ@@b^p`pHN|Ym3MhJzMUS^i8ZY-$&WQkcB-G&oq|8o z)6p?`9|;mOsFhN@44ME!8uzsA*{iza?t#%+D268gPpTC?Ir3et-?fjXzOtMqL2Y&Y z&u}atxaaJpM8BU4;G@P69J+PZvY{4LbwkQtK|7}_(I^Q%S}Aq`V1d`+fcMS!)!2X} zn+2{-DhMa5pzddRdDJ4Ag~zipuJoq3@fo7)o8w}Q_fuY!;Ak$pzHufD^4NlL&L)a~ zY3I8o#c?XN?3?TK6}(BjUrI$@*&wL>;{%&|ZNC>*@03eF6bm0VU*edRv6w<$*=hU^ zHE#lyJLquFAG72JWGcX`rMO!deD$Oa-%jNFUn6^D)aS-%;#g|%n%z3T!X4t4FqC_y zazqoGBa5Ye7gWAqS)Ee`w23uf6@Tw^u`bqHsLF?VR1xDMEQc4ECI$e=)YNpn*zo;k zdd0Djduh`T66K(nJ2Jc$8tEcirQ;Ia>Pt&YeWE??li4*w z<5Bsv`>f84LsXvq08ncYC;3E8GS{7VZE{!b1a_RR40Dtl>y4er5ueSKZ%cpQhuJbC+zx0?5?W6AKN_W#A%ECaN>Vlrk4-;oMhDyk?h|=znnHm) z>~q+cKiNGbb;oRjx~-+->2g5;B@mY`fY`eNIsee2ES6cg?1#!TkTm^e(Aa%fM+YZN zw{G&$z;)E?BX!=VbNhHoxt1Urm-hQP##ls*URyVv=%0{}W!LO%2kZCn3}Uxj){u_b zSFqI0#zC2ZER24EFAj6xbSOB35kaY;Z-YKii@V%|(q#rCLqf3cS1-D%F zLu=x6gM3_#EwCAJ3^kGcCMp`?%c)NKhkODW8LSL(btc9(JnFa_Ki_QZBtSD;aM+DF zViuRLTB$OiDk4s?;n~tWpFpo2OIJeYY@beEN{mo~8hX{$kA^l}S7)dQ?=0EsKzfp57~RrUvGx)>X$-0@C{CTc33w-EYb>9nhd9f9mkI1=>M z?m8|<+z;PmVCXd`(dX)tcIy`FVPYbN=e>3^CE2-^f$QF8rnhM5uMk_fbf<4i+eY@W zLnyZ-J)F_`$*;mPgz{V7zdn z`j;W=_Djfp%r)Pl_Q$Jv;!L=CD~$O|YYorFRT5i4w$(a2H*2Iqyokc+qU6By`u?E( zQX-@oy&kZY#U>FJx|Fue?mLv%jvZ!^@VZ`L-&O+)=Vk%5oL^Ef6v0so>$M1Ft;i#; zjUARY$HM#H2E7YXT*k8tZm>v225+Yvw*G?k8C1#MbCoF839^71B&v@N(nlx{esnT^ z(>kB~K%SSu%|uA@t+q%MHdQ6KbA8uRN>1$@66nD&wZbBUFXZ0b2ELj2%yzg*HQ-nfk1%fZ2)d?0961X!9V_; zgtrip5dDLUgoK!coQ#5koQ#~Df(k@MK}kbNPEHM`rUB8?f@vwJ=;-Na>2L3}|3rZQ zDhY|mZVPEC$tiDN|Bu{!1c1o^QGh5yAP;~53?u{tZ!iE3002ltc-!s&hm4qnlpIJ% zL;$$`R;C5q8WRwb5RwoPk`mu00SO3+0K{MtZc;jNGJ0i0J0Av~XkMsFX8Buk33wkP z(^CkaWY+8b1AE_?v87uHRv_S3|9?9W5)l)S0RPF~1p^2OfP}soa(2=?qzn(#w6c6W9{{VNy`>)yERs~DZZ)h8mIsC)$vL5|71pC69J1+Y0;s)S{xG;L8IeFB%@X7F1e~I@hpWwmJrto}iPrlNy z-egt~NKVUDmzWP)Z)R2$wGusO2Wznq;*g1wOLsRk>`z}#4hpqx-+9l$I28?q+jdkI ztsRkB!<*bw2p!vP(F>eUah^K$Qm=CuuLeC@NVSbzlG^zym3;sJm;-Ol8xF+-8=7$a zCs47lZ-Yx_?5$kPt!KT?-B@@G0My)sTxW=+7@Oc4FX?wyFfo4lNmO`yf!uY|0;`QU zd;&KTiEH|eLNCWxO+=vGulScMvR_#6;2I@=M^ztXp1!0n6DHs!xrNpstvl z!W{9Ix{6NK0b{JEZ=c-HFqiV@^s!HViA@gja4>&SaI>{}T+*6`c@3%%lw3B>D1St{ z3T7@w*^jgcFX}p^8YboEOCL1K#ZB+?D99SsxKy$ky|73lfRkuFm{L;ERZ?h^PLh89 z5!d}&YxkLzw#RSqpLE5A!5aXr8&zQH_o-KN_h)Q4YJb7eILuR=7XE$wYS5$1EKmD59nDg2?BclKm`!h#FAF1zV+~Uq zb4`BtQX?b#S#EZ@G5GO5d`+(e_?-H%oOz#R+j)QVeX%4g#~{zWxdj4@>p&ebTt3S| zn-NQ1e~%ZrG_unkSyBk!(%8N?7>)7mO{iHrN9xe)YCdk^imL+uymMHiXrmZvP{1U4 zcivIgPGdtaP<|nz6wP)~_09yvJ!mIoP~ot|%Y0gHnG*J(V=Kh-bI$TaX4dSFq$=m1 zd{rd+6aI-PPg0&o>3ZfN%A}4j`!+Rh0RE;o0MK7)%`tfu`G-Bjg00(Xagy<+$Qqky z)o-tMOA!W{g6-zs6{@0l)?gpbueYox12bIlJoaNYzX9a4hEo6ePR2}vU{?#y zip|&J=Rw+i5ik>!V|9masq}pp5j!=V_z8?$b4W3x zmIKe%aCav>GOSm2IcII*IhGx=n(+0D2dq!JY}PNHbEQjiNGdG*&r=UBE@R0(Fh52a zxb~J7oIxfn#Q6yj?u>86xRC1$M~XAB2lDq~n!SCelBIUC%kTHTw#OJH&wpB$+EV+B zoHEs!hL=fivn%x%hQFR29Q`R*Yq}@F#ZtVGF!2|9M}Ap>yIcfCV^}z_L7YLhf7l?< z(fWx;WdcA5DRiCdNLyXYb(huN@~1BP&wvi=aKV^a`1R!{0=uDxK9@HJVzW=Bo8uN^ zr{X;oHrty{^L`}_iAqsKeb$qAj(xv<`Qu@b-}t*_XwzqgM0k3HQR#R_qqli63*?Rf zt*^Ms+(etbrIA5CwC(}q;S!=GTCfF&r~jILmYCE?=^u9_Sklnp_n~cNA<1)+m4<=b zrAx(DY7>IwliS!*J;~PpwO;8k)!@a%-Ttem7Y<&uAMPjy!~|#n@MWa(o-qhMU}vN`(|u=_W100 zei#ap(z5<@m`2w{&*56dJ#yFcNAB?(;9UDq@s=34_hbwl)&v2uPK!T<#7XrvAr_GF z0FucyD_LwlMu$1G-5LM5L8Q;a%-3;2W3IiEC3a&S5*QfrWU2c4(kmGz?p3p=?XjNeP@GLT9jRc<~vMSSqrLT!z!%Ve`Fe zcn8iMznw%~yCWqQu)%||bV>WLX&pEspUhId@;34;;75F_@96E=s7mkZB@r#UG*G& zoc^`u!eJ}oJDanbp;T@I5NzOrdm1^eZMxWP3g0pe*n;0q9{BT#Oc4?=q1K5 zZRsVOBLFU`%nR0iee79`z3Amwpm&4YH%jk;4?9X$tE0j+HwM>qioj+cx{)` zJa!_m^%5VMp)*=oi2wBcIn9xMCbB<2FCSu%7X*RMF2psi5c&tZ!>-g@l;CmLATbX!fyYP=ENKXd`s$1IN}1EtGUw^p(kx zkq;l5B(+l(eowmiu(<^9`utTSaD*g0-c+C2KEJELdyb3-y3As(^@UFWu(vBTb%qDh zw${(vFnRTTiw0x5nxT35TrwW2gFcz7;opr*dU8(2_pb-`RnxxQw;zn8P&Ekbpt}L+ zz$bIh`Drj=kCN>t^IkH_{CzY}mux7LHh`hJ2l9zMej~Kxqt=)A#J!03%Smk>dVAye zZe6SEmmPDH&efhq>k1BIMIP6${!^%z7(I@GpR7Fl@qFvgN1pAs9s#?I6@O2JJGygu z?>jxgHket@$fuukWjEGXy-)JNd&zIXjSf>iwnKsDZ8MJO0ONL3UP;Tf-O>6ZVTA}} zQ{rjeY0X>pZgKypc6}j;q#nb!L`MPzkiM9kY0bNNk9r-?XU*CWngi;$WCXo-X^8A1 z!cumF%X{9MX>2=GuBL3gzIyh_xFNf2@QEjE>u>qv%U3jWTt3Ru>Jo*YGq71A_(rS# zH7S<>SDQ)Li>}zH;^e<=W zJ&CV0XDs}u3{qBj1AN={e?F<>DUGw?Rn|fK4HF%$bRa}j2B=!HVz%27A)SoTbeF8C zWp}vWsZk&_Z-X$s4ggMfSti!^$iSFJSNOEF;Y@qM#_AuPfG%ts-frb%RrY$ZIC|-k zH(rql%ncxoNH0{jIHmyNs4IfL0ZgXv-R=yFV+ZdM6XYP!SSEa##4k=dLt~rTOov~8@6KV}G`{p}J%5{< z?n@arG@aEh>QzqqwMtA*cx1tNot)XWOklWqr$|;?|AevlPOk=1r^mC+e_lG}_y(|< zkF4c>CpFSeD`V|m{I(@gkh$vD)4!ue(#o}Cs1pWsosNwuO9rwum$!CCG@ZK`x%DAl z;(-lLEp*9K3Gw75GWYXU3hyUuXzK56?P8z29Qy2>m>{j!#FlOXqp8-fatEMm4S_^b z+v^sPwE`J91vvn9P8-Cq8eK^k4~3LD^4}p^bQ(U(-c$KtuLnakN|E@BR%)-kck{}E z#6*m?%0f2wY=h4Y`NNjs%PrOW9$1b5RRBpd=~VeU)?`x{KjML@b=1bN=|s@0@R-@< zg%AO4`c8fZAs>FT`QT(3oMXKR)0AJ9#L)`o!Z^7GZ}GvhLlKjlOfLsz?Br}k%02#w zm2$F3n_eFrelt;M<`X!41pJS4ksebF%V%9ed@8_5<&Kroe@D>g8x7y-L3i<%;7fcp z^)6Sw@ju}9N#T9Gjhvr?nc{@DCavfcB_2Pog|YHdJ5lKKOU>&+BaN&WsS9&`y9y8d z^2?od99oT2D;5F|Hq>nF6OCxt&w!6)s2_Kc1d*?=eYr4r^(-eB$#s2yHRR0j{*3nT zIS=nuwGx{YJ6-;X3fq;#A8Xd;zK=c{;l!>|ckRonV?uymjw+Z&K7zEhlL#za%44z= zh4xeim4X-?4$BpzjvzFXYMyQ3Iyl9kF8iGDW%0+l`VK-N+CDOZq>xK^nG;5W-GQ0P=kvmfnI>MCPbh#zXi%@r z*rdj(!qq^#nSSZzcUr5ehG85lT1WqW2;YEgne1U&X$9rOf_TrSjqQ?>2X5Ly0(7FS zM0~viZtjzQivn>KPlk>TYjDx5@l1^nB~e;bqRO}*R)+LgQby(Z9;D8Rj-fEZg>vOI zT#IQnCIaKByj{xGz%(H4;GXQ&rj`0FA(72gC8LPemwZ6DwGQ)sK&x#wAp*!LO`AGwo+rVa#~ zKlE@Wt!N3w&Iq!RjeTY*Y8LRV^9Q$be7)G%rucIBwsRmI1j4OFs-TaS+#6#~cFpQF zKuR%@9}%rapqak8zy0&JI9@i?xvn*akUeN}%@C*KnQ-pN#8h-xUrsJWp=c6`HGl{o zbpIEl4xc?w;@>ZcJ^d~(r`EG0n_vuS%BM`el4k$;_Dk?Zf^MH*UzSO z?HWDS_ZxGWf!la|x{=l4oTbOmV}5dONhAA`qYaZxKKBl$UN;+WvYiyS1^oI#{u#DY5won5r&iz#vZM!wW&j^DJ(x(sSZUE;-q(C%%Gg|I6 frv5Fr!X+t8!{=8q70*j(J~^)XhHPeyHPVl5`FY8dJjR=5u&$YM2k*BwCEv;9)u7j zYP1k7?)d#a{O^Z*KiqZqS?}4;+Iv6GIeWkBT+Lj42dFhwHBx8+Y_Ot$Zqxk$qxDkkOGVV13(8ro>+UiE9mQM z1OKZXPXRb302qf~YyGcf|8s)e#@5Rk0Psj~X>n_JPj4KS$6;MRZ})4QjKdIXhbJ~T zT!O=QJ#iPr;m_A`tAFvzHMaj3|GCDVMhGQbZ#Qt5-Tq&E_ZnOMi?4fOw|4M!!PPk9 zFwDi-2X}{m?7EX1wyws8IM4FW=LH}DH9!$y2dn@e00lS$-T)luU2!w}pLxRn@N@w; z9LE~By954!CyrqcIN-QW~)zK-mCr8FO`YUUYSJSquOKGXT(u{tw>`jT`4KE}s0K7%Ue6s3HNN>HU9V zRu}+i#?6>;KuVIsq^V5C()1 z;Bf-@U_1ga-qi;Hiu(&hxc7v2-NHWxA|NCpCcy{rNO5UdY5*>1SaMH(FiHfLJT}Og`bezQVdTiq`Oz!MGsR#d=aVJ^Gq%3Uc&Kj;sN*s|4keK za5BUo{OhCPU;zKx@bHNN&_74x;R6JOU>Xi0AzESu2&b^3!4oJdu1*qe$m?T<8P56{^`-{~&yfkbm zf(;Q`SoG{!&eqfz{nFAvFFv^rKghA-cILG3F_%2M;;|BZ7 zmg%DT4iT2NZZQ)L+@2|O%qiM?tV1An8~;on8vzj8&IEt%le+}N*mbNc>0x3RRhebO z^o5&TPT~2tUVt?(__O+%o1z24=;ND4S>qoS@*!ZcJeZymyt`VPK!n|h@lPy9=gLxW$;%)1Z< z&IywHJa(dLrF+@a>sWAy_UK6?A5?GaLH&-Ndwb{$xbK$Ekh5)7k)~N{Q`gBVXW<|7 zeKzkSJ z1W|q?s$4;WcSCd5)pzn6r?N_K4Z~<{0?T3WvM(l7Or?@^CMhe+fHEvi&RXL=e`JW5 zCo*W~m-3F~@Nf`X1miM6MsyilW+yWXmZ7JM8?W(1)5uF1g;-PV6IE~<$kJT_)D%@+ z^GtEixrmYe)WpQ9_Y7}7S!3|?A80ky(lZzrIXJV;9L`FV^YmOI8l5Q*v9>a4O6^KH+dw-0Pcsl2QSk3c6y zbeEH&EEQ>Py+?ElIpZ7Ag?}&Kl$(NXlyfuZIUgiF&LOKawCuXI!@w8T6Z*0DtVU%x zV)Mf1Db|H-Rl!s^*ZnMC_YXv@Exmg^ZYXZS`$=cY8>n2ntBV50MVISwo#Gn>6Ti!! zP69CjF0bN)1@T+!G}GTZMIBgBW~#}BnKL~8I9cjFIkYNTLOg+v5H$WA?4*pMprGzU z(R_x` zUHl~pNs3aD@-Zd+T;Jfbm_l|>PpoVHMXysi16`G-V%li3q_yKnj%N%#Wsy=!wz@!B z&X3x`qJ80bIYvrLv5HmZxp|}5np+>7pJhEz6iTgRo3WO|XjOS4!-lcJT~U;V`Q26f zmyVG(xl5WnWCo1s`zqT=(TK7&c<5jG~c^C_h2aO!rl?b{fA9f$4Y!*T;o*C~K$*iTBOC{ubFj zj3I~%=P}Gj=J2R5mT9`CC6gVdEMOKB#~^xw8wT|>2r7;%los zeSr=3ILHqescb8?RC*5M0cBEqMBIn?Emvn`3nxkc-wqND`8mc2~nr6gi%Vf;BTmdM@>SPRF8`pOF!(GPSx>` z9IYsCjyShv3D=yl<7wg@C2jSQbsx#Ln?6>#<;jW*t;#8zDXF|A+0w)Dv^LUP&r@fv zfV-cbLDF+}g?*XrnV7RswzZqpiU+B~l$bz5>KE_Z-mzKT8At3bbVeS^-EPnp=}J9% z8Ivim*$wdan*^_9vDw2P7Zlai6|6>u%b4>%^tfEZ&{M z({T8dd^41K^v6k6@$tjjTAD7835vRx8D8d3)uH$X9ajLSjAuC7!+J#AVV5MIDfFP%_D22i{g@K584m3 zDyASI#ja=Ok2Up(iJ#~~XR8qUWI>TUTM29wqA{QM$eA|GeeO3QznGL)-J$;$F*a7X zF~D2@TdJnJtzE0*i%-YsyqqcGo$pvv6}aejDUJJ4Bd~d1!Mq$ctzMq>BhH6?CFk5= zIW$~qjpnnYb7`TY}iMqg~tLczlYa!_ECgd9DHyU2PZuanjf&j)c!!P2e(gfMGr z!sdmEL~{K%Ud~c>lt@!U%X!HOp6c7N43k`2Uj6RG731fpRZ)qSM-p~2j2;HJ=v*BI z&)ddy8!~=~e=)&NMTES9tSNUkq~sx^IT`8c2VQ79ujbBv*xRdv1mD!|g34{IGU_;_`I;0gh$0jr|H%FJkE$&_Mk~t1()U?>r z@3Lm0cYm~D1x8u2E9m6fR01bO$SMlwJG#X`xU{=sYh*S(*r(uIRy@6sxr) zK4ze6@`X&U-uOM@zwV_oQHyjE>2uQfYH}*to&FOgDgf2tUcPaJJs~lgZ+0Knl&kp7 z$?-Hi_62t@`Ye$qD!{&$`^jnEB(_?pP^RQT!(29)v6+K{Fxm@tZ~PUgT<_uN--hvU zNqVuor7dS&7tSqT`4rK{GWLR`XbhEnTFX|d4o7gdPvf^NyM8yF?ty2gx0N)`r?Lh$ zJnDSS{WlW7uQR^R$b4hRXCk{$`r>F!;QQ0rP=k{zAeH$MvSfktzIXFC>)6!-!6n$m zEk?%UGkxM6&z7FxzDG~X%Y-F*tU+__j%L1r1W1|VOb=VkVN1pX4mIxT{#!D!m0Q)E z9A8;kwDO-X9jWadMdkXJKV1lBeIvi*5xmEl)sw5w)PABTxE z&QDPH=n0@XB>o`u+z^fdC>PJ^P=~i$;Vy24yEIHzqH`wZgrz;naLV|E!jy!vQ;o%H z)5s*{shp*c&0HJmy{mNaqEdA6B5{3%$Jn=yKPs*0R(Ls}<&I9hs1q81h#>$u(w`2I z81WRlF)!<%{WIC{A+3zn3|z7@D*86565TDz%!Q=Qn>f-RYaK(5#k58Z1~o@>+y)iGH{H~a;-se{I+r~ z-FkUN5>XZSSDQwoYUbGdvz{XDC=8LspsHXFWv|MuLo5YbsX*4-y=>zMn$MB6TJ?g+{)E5Y0->q+1K^ z!9RXcEmsYs%-`c1NL6+LH^5sKSVb0pV#Gf!D~ z$0yn=yzA>@&;XC~!J$vDy@aLJXh6-x zWNna+YR#uzQ}JFb_iSOioL*tWn^dC<5pJ|(;)-=q?Lwr$BK%}4%dRVUg3EzX6HO{* zkY>>E%HW~m7+ur-%ATinkJvZ;kGCuy&r!609C}$KoKETTK0D>qh_P&);^WW0)t9+M z4~HiPzs#bX%uh*}y8T2=TO2iHCC#2K`Q-$aYplt3y6V77j~aJ_N|b{?l=ricYPl3( z*QZ(0k0T3IU(~-g8u)Uth1D<&>TE+_0j>6zBEOD4{ZjpsSn_+Gfsg(5cCLJGna)D> zv;cVO;d$|Lo6)_c66l0s{&RV^Aqt6!&nqZ3=6J5P-P>!aW_jrE{R(r-Y~kHvtDDKe zy|l=;wT_&;M$zR?lp@RHN&N3eD}DQy6i%d!J@?=z4ygsRW`E)CIR(r4>U;=TU z*}`eI@(~G)?7cd!fUS|Ruz-AV+j1Ck(T-@r+#!Y3rO}z{a<+uSJ|kVTt4|mLsYz=J zFpishoPNuw73*VB#--(o(i*ffO;^&nXwg*EOb>4|PI8P1jL9IshiXwmue{LQ(@HIp zT#p;Cg4w61hujU}m~C>l zFX7Qqe7!zc61t|8P+t0yres_H0TA*%u4TjNY*$Ck{5h(BtbqvL5k9dhPa_k$Tu@i{ z!+s`*9FWXxowUlXvS!X&n)VdZnP@+oY)=^7s&)>ob4e88hw$!yXV+{Ua<7^X(sTi( z^L#2*Oj=iVsxN3j?1YmPA$VG@ z-B7?};0owX6BLu(XL&7tBo&Hm9QDRm*wH^Y&F{IRVHp2MA5=a=mRF#s=rx?=DbsE- z8vSB@XUf;!!ls65zylUr8`G^QLvQ4%=UfnIdV8OuJOku%JUG;%jWBA^$kNjCVYjEG zyTPN*M8F#PUWY~0k8GQA!!){gP#2lT$TKO{NDKX*k})QUwh7WX`jyz2>9h8{^$K8q zfhnttb!(fosTBqB7|PqqF`TOzvu@5+Q&{eMP#Zylqp*)so!``+_i}dnSGv)EDp=QC6_?X*YVVo@1E^3&*?sqfnwgnlyQacs#yWgADCEX<=0#p1*5 zpi`VecsYp@q~NW59&c)Up)(Gh=p|y0ok3W{}`ptuEaV ztbX@*?XLIixSv|=m^o@HeH6cb7;5dVz#LZ9om427%WuIKocMD)+em`kRsT*dopijm zXsVVg$K*DWcSyGfy{)6w;U)HTw6diM)|Mka7W1Kj>U0w|*f?M9J7s^L2}{2mQBwFJ z=lyI9-$x9=vZ=5i<1Pr9mPBx={-u@ja`=SO^#Ep8aGw*Bf94}xxMtOQ(U{*2kt5qM zn`S%?obWZpyLiWOm#a~EWhkzX#PmKt$npq0)+S^&DPZQZ(aL+zlO=f~I_%j+eN{xp zeW))16ZghcJpCvXSv9ThVB}w)XQxE@96o>0j!sLRO{IO&OmI>oFR$m-Pq-O+_4U61 DHrz*w literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Mocks/male-2.imageset/Contents.json b/Antidote/Images.xcassets/Mocks/male-2.imageset/Contents.json new file mode 100644 index 0000000..7788b6a --- /dev/null +++ b/Antidote/Images.xcassets/Mocks/male-2.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "male-2.jpg", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Antidote/Images.xcassets/Mocks/male-2.imageset/male-2.jpg b/Antidote/Images.xcassets/Mocks/male-2.imageset/male-2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bcde0fc5157645aceb5e7495b99ed18d32850320 GIT binary patch literal 5207 zcmbuBc{J4R`^WDY#!#|P+1F7%HVzRFhqHH0?m{B47E~4xuOCe;* zmL)y5^caujk!*?I=sD;6{PX?&@jJikbLPHZ=en-<`*YvdnK@?;#}8)!8&(^m4ImH* z(4{@#a1NS-L8EUNkC;ef zF1)LQ6O9XKe9o74KpGDoU}D=Z@I%A3nN^Fy7VI zgVy6tW2A?B0PPIFtuiH z41pI-gQuip44-daf0szkd;8*P7;m^Fo!(aIT(2WDoO8!^xMW&5&m6j*|n?pVYfb~8Ab#MO7 zITiv?Pn$9K7jFk&hu`m^qpeUE7XUVj0XSg=04HtM$87$;^?&9~^FHzi`JVtVy90oJ z9{^9%0XR*2AFJ)*6hH$Q9X&lg9gMcXU@!(aGb5Z9tjCWtF|)IBaImwovvZ#0KgG$# zi(qHx7UAX<5D*d);yfja6ct4B3knGynLub#I0Kx8k^i=9jG{~U*{fSnOUfCxH> zD1fp<=-45L?~c9@5ZKZ0=|2Gj5PAkUl#Y>By}||{baZr3ItDrz9Cp+Mfzr_f7&`-p zh>QlOs0p0Q!6!0BHn$ofhI4FVM9OJ?oLxs>HO1e{qsjRozs>(+O#_-7#sGoSiWk@c z^tU-}DF1Xopn#5^o#qVFFk#>nm362VL(<$e(YYVj4<`XL9fWpnI(DE2{#bY0vb;FTdbJ zJ$UNn?_v8C?I|9=*|ef>HpLJSsmEo|aH3Kn(c(5$W-RYby9tSD*Nhq#I67^%K$v%J ztMO*~Tg)--L;$w3;99kzmSW-6Gcd8COvrT{m!=Oko2w-1S|K*mgmI)pou&43`zwDD z)Yg<#6S!456Wo8tF+$Rhl-Wax928e!wh$Y!du~TD9x7_|de&IAq&<7FdQyMH;7JhU zfXp{6H3Az*6)%PANsS-FA*Qs{RrT*axYog-^O!%^E~Zi5TvrHU zg1iI`!qbOSDwe+F5Jt5mXPDQoR#v!_H4)$EWu+7&N{OOeo24d9-;CmYuyI#WrgJgW zTY2Z|cpf2U(lV4Gt1sK{s=epct1>@#M@#gSeSYf6ig44kBI0+A6NUDda+;@NSSQQt z<}+`O6?Zoz#KgWR-G%t+`(GA;L);_{eG9hwSnK@vK1GD&)_$q(59I$TF>A!E~Jlq*Vvg>syqH`}y~&cSr-&2RCWXuS!SBA+@%ZvNZkCnJz2nF3-fIO`AP zpK4v^R1hh=qc?B1Y8-Ibenrm^c2CHedblYdsu~}-!pGXNHn=Vr22NzP^-G*TQ(=E& zBEzhAgm*|@Q7LFk@8m0J{tde?d8Hd~OUHjcq1!H4+qbej`wdtQDkzZN!a5|xl}RL{ zT*VU0yJ@eq92w~aBG{?wBRKkvLc<(f9;=CgT^!48@;kh1DX#E(X6A4_ff}b}e&xo+ zCq_E=`9-!#TYSfPygF1^lvDnm@eR(~iwT*#YU56dHOv0nXx3fu5FkPz<~G(=DXJ>k zQ2P8v1F5&)4B?VHVV8GC&ZcJ%DtC|hAA*KEx|n)wWMEpO?{%VCLC)*kh&;G(n4ea~ zb=BJI4Lr<$h-;cr8hTmCk%_RgJ7sOI`_R{7BZPZPo21ZhAHJ9jR2A%`DT)>HxJmfH zj$_Rz$Y^o2@cr?mxqEF?RfOaZhJen&O&gEtpI6(VPttnbtTZDBP?pCqf9m*rNg0%B zQzUN_KQMlr7rw|7bIl7GB|om|w;b8Q;kO zH=1nE(iFY8KHs^W(exC4~_~iCFrrN3NEDcv;>>yiXC7gi-Se5zFI} zp-EvdYhky|k`o(bApnmr4YNbfu2%qD)Vc0hoFWJgs+EDkzrSa=wt=< zAaKKdoFGoWK2ZFymZ8;-kW*?R%T{f6Md?X;%M1 zA1DClI%~d!A{EN+D?cE}n$~u5QAyWLRQ$P=mJ3}v;!{>vOEuKC21q^|Gh@BO)8}`j zn<{0SBi6VptUpajB+&_7DcGG%zIw(~X}YaI#wQUSt~ykZniPp1R$MS|)?;bc`|zyc z;j37Ia?o_mMjz4b^h}CJ?_o(WNym09`LB>o+u=VGcL!o#L*ycH|Ouvwl zHeR$P<`0NygNvTT0Ze_=%TYHdR?*+P0;@r>$|HSHX< znMFcEn+gB^pW68&15@|N!?z$Pdd2K_nR_gUpi)xQ^j6Fly^wPES9-eJ63NxjS=9KN zirj2&E2F?h{@$_m8oL!4N7Xv=uvc(`7k|Z7mL9dG_`U+$N;xm8uZa(VT^*Zl+DO}ScB9ODahMGUiR)5%>UW{i(yYlM==;+z-{=_#JPmv?XPw@5i(F9p%za@-F!;w$ zbDL{7R?+5Zy>S7ISSB0;ThWLvT%bB0eyWoNDgJUccNArHqv$V|u(Qn=)R^eOuK{P_nHo_C!s26cupws(IvNzXUV)~p_| z`E_0H!^tn!j;_^3y(+16N+E{&%2`}-@OczcHFeHS@8R0JxH7{_ui03PeLf3+6Y5Q8 z@_bp!h<$xt8DD#~{9^?bm;kk$LxB5K{8^65;&(1^+Nz9g54WS9}3a6wlm4BWxAN84LEoc9}2=3)4X4{?; z_uaXLH7OQm1>Y!5JD!hQCEf5aLg@voM3_fXSYDfVbfG_hq8_4gK{j862DcbL36+tc zWEddml%O|RBA;~Hb*+XWKr$oJm0J(aQbP(gKX(^JO`)oWNgF1+*6Jp>dl2sY9E$l` zkePG$!q22ba4h%zU>&*WN_(F`Nl*}iIL9x-*ooCqixPwjzM(jNOnhD0&;5BfWwA2^?Qp^a9o$a#Bi^wOI%t-ZsmjAUb8OTW zN90EpA~$jBKe$|+CplT93#6*1;+Q^9GPQ0Fj3@3H*RQgw&TL=vRAQ1kWg$((Z2UN| z*BLSIQ1(SFnMhDA8H%p0pn~)qJ+|o`3Zx`@ZIWT=5_y6_nfTbq7h{N^psxZ;%Oh*+ z_Kwr;(wn1fKZ|{FgZ)F~)ccy7!_U#{qiZbUbS^VhK8eZOmAnL>H|q$-eum+(X-DUT zm$&s)ImT+9mWh#=^6IB$=Pzvsi9|~mKvkl)u6)-j=pa6_@$Pco+7Cr2Y#0xG#Xaon z%#l=ioWLj*0H2Td9%XtvGcP_Yke8GJFi?!|X(5rfDCjoP?{`{S^qjmmL9k|xn*Xw~^~b(JFlAd=XDsP@ z&G+wXRrn@ceskAn>)~2;B%a?pv`0*>*KW^kk*}%e@%-5UeOb|a%ATsCu@fjE>nfYx zVK1*9hx(J;u5yiStzs0&-;!rGDo2JvzzGkUcJ2`iP+}zXFB}p z3sSyL9Nc&x?s89WL`o8W9DU3UGs{v}F|JEB|Ks_OO#~)^gW4-nmo^e5q9K(Vrt_)A z0q5{RlOMMry>I&T0g4BMy*o0D2r$!>%j_x%=X+TFU{mUanag9}UZuj&de2Q5@tR-irZWdaH1gUauBJ9pznCo#G-0@ z@1@!!bbDonHdtbd?ZTX;4iszuhdq{2&0O3rAt#YTuj9MX)LS zyH7%qFyyACW=Qg*Wt@4j*QH|9fDERw{GB(UQENCdS>|cUDv= zD0%~ZMt}Peb4$acX0gi1+%MTYRZ3vi2c2B;PK$aQoP}((C$w7o zYeP@dM2*BAB$tt%zrZeQhYQzR}BE&GcsPRo=lFvgRMm7m<4KucXLLH3sSXnc;%R zwjz@wyb$<$2CFFc8if1jLMc3jlXO?9q8j2OWkM?Hu^Vr_9euWE^kr&WC&oMd{96n` z1`;zILEf!i+V80x(TIHgmACk^XaI{o{x12o4!t~Fav(&^JH1CZQL$e|CD=5psJyP2 z?R@HJlad(+93mvRBX2h^BJ%JaR$Z9`%d{E}EO{R@i*{Iu)U7%lzt=oxDxqm-VS7Wu zO8~NFMf=YbC}6wuu@}`PH1`@>#Sr3BBfRW|Ny6C$JLrjZccFNwt}K=Hl3E+8cp`D~ z-m;iu;iiGkq{xejR7yp+T8af6c5#SXu10M;aEGCeNl;1|z zGlEPm4P@Ii$gHRTaw82A0Qo=Y|G@+2dirI@>jXMk2%ziw?6I)8nZgDUGi zl=Vr|E}8A}F?#fy_ZmT()K4CTf@eVVt@c?#%q9^cnEY3d2QE)8|m0;-?Z?SpT(U*S5O-ujcb3 zg+Lv_H6r-#7WutnMS-yD#Q9;47~pfoOR8lgT0G=?o7j!1pQM536p z|G`gUApPgQ1sPdEme8{U1dazM?EBtq)n+qpV92<~XLGcK$;tLf{pep9HPR1d(ZTQi zko1^jbaRGrchR=j)m|FtWBbmlXPtbQNfV+@zGmKWv(~s{9lw-d_lLxpa|LK z4!ifEb*(y`tUdRi4kI{bjBa)x)|`_#(e{}<9kG3zEToe7gC#W_g`jK;){MLQ*~tDe z`a&db;~C(5iyOH-?{XDyVq8R`qH{?{BwD5v?-)gQooohX)3j=?0)KsU`?32i1 zo`Q-;U^tur*68To+--EOI&VE~cvjtHy(R0gsFH3%AH1ANvCv!x*NDUkFhfag+XkQ$$o;SUiX z2kQ_B;o$bumuG+qp0WiFXVd=9RSj`byxqj0;2T#xIUq!OYP!AuNqWrW1GJ?|&mxmR z3x2~Z5f;VUb?@`<1HWFX8;)Z%{X!5@Rlc+-Q#giX7)7cb7>t=-0)xT&w!z@PM@Bhy z&wziQoaBa2Y}`V(V{Vb&-WQ!6290#P_>bW4x7cmbpDEMc(sfAqkQ87^?LB-boJNxR z3^B4dP}F>6EP>uUxZfTULBE0Ku3PaN8hYur8md+F*wu_1>Nb}iUGBq*By>ujRP5s6wQ1FZVYs7a3Ow*irSM6b@oV^G-<(}1~EHF_;$x9F%s{tXp}t# zu}sN0K$XsxKTO+0oM%i(6d?uFKD3V|5{_xMqy7&%JFV+-^@6Z)`bakQwuAVRB5(ot z?y~Q0Sx?x&#*eDFGT}n>^;m<#(@vdx3bB8bJ_#xr*97N4y4=fCUyR&AXIaul2++9^ z?azqd;dj*)(wqRaDQ<0UPQ9S1iVxl3^-%0N|d6#8YA<@l&`LZ|h$YqI(MkPoS@Yr9{|u(3N)wOf+6Z53TS18AdfEsLzPeUE>y7^Ld`F2o5pYsa+{;YAJpR@T1GCr_x< z$&gPJkGFn$lisN}f|?o^FNYv%ADKg-T$2sdv@EiFmZbI65fFj1`s?Qn8h1|Q&QEUp zdjZ$)wn)PY;O4fH?WS4-|HL|ZAgZ%w83K0+%%Q~fuelAyc4qw#oX~!5FD8S|?`!J( z^JP6c?@w7zBcbT#NvsO#XK5&*)@VK!Pm5T)G05=4d}>O8@Aq^!38S}OJ><10^eG7L zZ+MgIIo5#mQ0i1|nl}p_pQNYHUGs++W}00qUyn=GU6rX%HgGm8Z^<~dTfWW-VBVAX zLFgm|G$2$!RoL#OFE|y~ThdV0$%8uq(kzw4b9v!v4Op#+Xc8F7s_>Ymx%5!tE3%oS z6l(oEimPnJv$9dRx_BHM;yhlq!G-o zqVtua9!MEEVz-tEzg&_=aPjGnxOR^_^LJdI>3_^0pb~;fmXp0-T}v?O%fvrY?ynrW zmJ$(R#VMj_v#uU0c49NNOOw6x+>Kz_%4p4W+|`-9R=^9;J#A`Q%DHnjW-`70#quU2 zevf#xDSE3-m`yhh!1qHQ@RW-xY@PPaROsm2W%I%(w>af;$tA^-xe!|~MOSdoHgQ8s z>Fr~O$U5{G98ds<`hhm?ZN3S+Y#Q*|F$gleG7Jzg3A8`6b!MmhutD&-(KofWw$uZUOJ)5o0u>-z0}ptgy6)bpyWuoC zGN9|DVSzzK1{l#_D3K{Cse;89&OwAWs+p4(#a6XD?w$c|O{Y-6R{B7LdFYRkt&4lQ zvjaYU3NVrX8dtlVBIrV)h>kX6Wp@AX`7%Gyj9zH;Ztni+8E}6YOEm(Hjlbh;#TO1H zl4Ux)zSI4q?lmym$M%bwTJ3}Et^omrf;ie2s7P~*&DJj+c?+>Djf9oOY1&f)KJ-=v zNIU-sc#N^Em2O5PC6dq0ofVK98EFpHdFD`PSi<{X>wFSaVadXckJ zgYebow{~p1Yaee_cGYzm3_O6Q@TAp)5)I!hdqwYuk1^Y@k|6>`M&V5vP7%;%dXJA^ zemevUSeKMAL#b?&oQUpWc0Il4SN zGGU1`4mQ5O$-i3zMHYMB`8T>8E-uKF&B66FTFNr{cRDm%yIXhMl$jYl@;%$5ft5lA zn?es^?Z&&cbFeXbupi_RZ>wrAmAh~0uv&zGtx%N$;3Pw@`_sa>Pv#1v!Ef##Q!^YE z%ev8%le2joY6K6oEEO0Z%ig)#dAR#x?w^@&DZO=ny|QTv4LPNGtmMk@eg=H%`bSFb z_WG(%YtcPN>lARVszh{N8>|Y^J8Pj`n{|k_QriY8s^Z!;Uz?4=kIW${sfM zyKkwRDOKf@*@!t%nu`38+UPeG*f^CAK!t_=Rr#Uhjzgh(&cGH2b|q9S0Hw6jg{J42 zlF>aw#mu%a)ON@48DOwbvP0zZ6Pe0d4TGZEzGh~tBhy#m-VDOO>3e8N_p5Bp|K`>q zhYZXJwKHL&<8Vm3mOMiyB1bdKaIRionc678BC55AATPxshu`uODkS5xUQ!|t?$e#P zH@1GI_HMdqXrZ}r7m44gI`TzRY;jG)ePv0^C^>9&lZgftl1xSE=yo?d-iT(UC?M7C zEc?lrJBZgkxY+~e{YB=)DM@L2wOm=@95s}dnA&5H<~X~R^Sz3?iVoJXp^0zkSZR7O zdx)h>?j{(sGZqja5&P;CP)X!4K&t@1MQyh#ayqQOL$6M%()!C3Jr1ZC3?pmOR$z0u z!(zFiFAA|Z6vIy;evP1YrwV?|_F3;yTUND}$8L~Sy&zxJ}+W#>Gx&S$`4>xSCauOdXeiy@LO!S>YNl30Ys};3|I_6 zMLCEC=+d5?%&eI1V)FtzqGfj6xkG#Ke7`gK&b=91sA^qX!s?+-9|{s}W``A5!Hx<} ztsJ|(ABagvbn)r0!x>G0uafFXL#MY=4NVbw!4 z_FjRci*V&-+sF^s{x^bb2qSkBvOpsVGnKMUb6gigB>meeJbh>xsKWYPEDv(dPl z%xG*Q=%7@vRy2>h3R@VJ>cXYyL{zHt8GzS8DNn>A3bvG(R*YPzt&KhIP^&nvOJ_fd zWs9^FWK_`3M6((*rDgxYlAC&3jn?**1zI|D&9Ej4?cb_~2gB9?WK;;;(RobRo=>V< zTtg+bckqF<(PpswlYZFsGa%(D@LwuVk%hlDdP+S^x!);+=ZiG%=*RqX-li^0BfbKc zl!Qa*C+KI75%rS*^5kts7$b~y{rHUP2iuv`A?0GEd%|Z_*Oku5KK^iOaw*tvBB*gr7}ne>%Z&U-E!cCcI&| zfV1wDQ!4Xoua8v@=6Q_ac6c-XI8V#K)s~X5WnWCapC@097qx81xRkO@4oe&J?|80s z3VNcGI+nr5i9?@1+Nan+fs3dV0iMRiVO|bJ6YXN-YLKywOX!$FNLv_Jc5^mc)Q6u~ zxRx`)HECl^Mdd#Eefzxd)#WyBPLPeg#DQ>&`nH~bVv=^qlDdPoQ`<8j>$>0kOAK|s zVQ>>i(Ufg!KU0^wAqhTm{9ml4u_JsMAKIAgW}B}Y+8{wpXO_r_Grb;q)I!P7pDPf} zkNc9$3!{e~J$R>rCX64+#*^ve#Tc5g+0@5;EUqC6G&!O9fh?VQ@gpVU8!4m9!oEBS z(i=sW!WM>pbWj`TP|i3TU4}QfAeYw8&uRzdI!M>p7gG5Vvagw5_0Auaw9^mosn@pG zw#N8Cpt|hKZx-Pz({7s3S_+(W5>?N=F`GGF0}umEnwX!jyPsw{1TL2@w}A}Un0N%O za7+LQ#}S3E4m0kb0ZmkDlj)p>{M;%@oAFtMr4Ma2Gy_n2qE>(U!uG##mfpz|zt&C6 z<+Z_!Yj{%R^2C&FB!SSVgBIeWpMWcBhNtTpR@}EpEY~PDT}hTlZ*Nh8DN3!lhosM? z$h8~^X3`dIMrrm5f`MkS9h}27QJzm}{YjHZcRoE)! z>k}c_JnX3VZ4aa|o?EKzs(l z0#Jn{hvYLSAq}t=KUt)!)fm~f#=nbheU0X<);2(Tuj(@z0g8UQ(9O#fk?u#Uw;r1WTHh5awKGp=@v5_KVd#-3EvKEQcv{n*_Ue<~9o zWu63F$CdvZblL*frdAuqPY1WC{*7s4Sd9oy9qeE*s`It?EbI0GGR2>i%;n`=Wyrza zZ@qBG?S59Q(V0UEb@Ssl>Bmd6!Y`lLh1{V!)I_g-K62L-P~UYOSXtqwq9aKBcUWWa zdE2DiunI@a4K^j80YyPU2YrSvgfR?gMD2spfzN=g!*7N+K@JCg+(LB`j)e+4`+kr;&x592MOr0Lt*xAH z3F9=hZGubvF2Tc?D`Ljmq~aHi*s>gmXzQE%C6FOPzXQ3ow(K?U)3DF?uYclCC^8}o z1tC(_v9T3#%_$(woOp1kRH*(=`IULZc9tbqCzy2TAHez*7;X92m770~6k-)TiJAyi zD|GI_I5xmoIg+{z3528b9ZH#J;kGX+qAqF@dn*FzxrY6ZiauR!%?IlKS!--ww$B-1 z4|Qxo-%g4|O8^nbd_L%tBz&?IWo(vVa0+iQaM>D;_(mNPad(Nacr?!@_whVAqGJaS zg{`tv#2kCB{-BRXy{mF|s;lyMhQ+7K1%$GLF0iyUQ+0E|c;sHkEjpF$-OGtbGv5+|zYHac9tP^Dq7R7*NpiTfLadH?Vdq5i6FGV0-B#EWe zlbB9h4!7kS`6)&PI12{!{_>7f+L1nT(D4uN2R7k+d7Z1O8d!)-E^(7_f zM%Sg90DTN5<*-5~6Phdgk4Y4?lXFA*lNqu=5Vr7jB9$L9#Ri@epWm*5)>`JH`k02Y zf2t(d^GD-=jOgFl)W>f4>$IP@ZIC6mHry%s$-h-!b7TJy_WhITV#-}mfio@lvV3Gy zRJR)8u6cWga=2aU8=o`McdGt-uazW%HNT)p=D3v|e@Ng_O&BU76|eX{zHO@x?fnT; z$!d?34>l$+uqZTLw$H#)O5?R+W_{zKKU&@{PBYuwv2N6ql=X!at+436@Hknl12MbQ zouLHxq%ufJ{wbijyYB5BnxKoTNvNxDuWjykaH1hk)LhY!I4vX1;-iEA-7O|Etncso z7Gy{_v3l$Mua5v@K|RWy9VZU15Y_&QAAyIzB>y^T;vkx5?p02<-!)nJ48+f3MyXV= zJgCuU1J6%DwUr8SMh>2oTahp@rcdFgTa}n1VJQ?afv%yRS(Kss*H=Q|mki#U*r>Fs z-Dpqrl(bd?3K-8qZl(1 z(td#AU2CaR2gr1r`Gukzu{}tSW4JCjyp;_qYl~`f+(dR0jYWkr4_TZ48UD3^VL6JssIhR7T31#l_KpN#Rt3z|TYPBv--iyKDwCqzwqe^Qzlbc|&@ zz8X<<6<9wpdiJJtu0n^?a{!bU){pUbrAHA>NMZdM(Ek#lS$+u;3Xn8q1hYX%Fz%)I zR=!#J6sflR5?9y?p8U=VRcOI#jGQYzi3HqlSHX|EY3GT(*BunE`U^{Tf8olJpBe}I z3178*i72%`W_$+R99R~mcAT}r`HgKlQeV-I+>r%89v0T@(T=uAOcD8h6H+SdYaK^6 zFxpXk!|A>*#N<@*!0`a%>#^P`V5cnMKB(?jJ9-EfTzY360T@%c`uk&K^TV>O!3lPk zt{Uh337G<52%Um4%D=7A%#pO;JqyZ|?*6B2l~gR1BgvK*G2#^9;WVH?qyqw>ZL_wQ z(>w#jPhdqSvA{Y9sUjxf5AnEP^Owg-hEx3k$THMAKLZcW$tY41M&(wK2T%cy#y^9o zfv}f6j(3XTee|f{GhqBg>#?ArZ{Zur`AtC<>*!kSE2&7^+U~#0lijceAVfhcd%?x{ zmLM&Kg5LybHI>ZCc9_sxn7te%3bb<)bV(|m0tM|POwh56b6PpJG|7~{jn=~e;D_kr z`&hxA@Kb&RJC;H@a+e?gR2OR4%;+WnQBp7Tx~V`JbI?&o-H+@gtqufP)byWJzH`aF z&G>mBQb!@4LFeg&Ks9ajbEmc`14WkRlN`J{+~D3lPTp87{d&S_GAwF-`yN7KU-y}h zmsqleYPI+S?bkGC7WtYxm)fQ`yNf28kjhV`>7L~Dn1s7xRG+ot|DIub3a+Y$#Od^7 z&Y!blcU&Yc4J`@YT91F)&#lIqtlUuaV?aUwsWWGqv%L}N1^D-v4(*UQ6LboNau!~iaB2VH~`-bD=+P^5+ z{t>s2RcSg(jDJx&rmIPf0})p0PdC#Eq$VEx#i`_NqHD4$(9e?GKV?9TkDUHHf4UH4 zzI-Di27WQpJ6h=P3)2)y7FJ^j*X>_^H@+#s-9UQ$3UQtA&hGjE@etxm+Wv24PrX&D zNjPIS0Ux>0_<0zQVmQtG-9pD!Z_bx{q~$fF-bp6NkN;M7RDQk8rQH)>PkjF=BF20Z z(YPM*o38fB7dP-^hf~W9$GEkyYCg7|AC*wIyE`Cz0wFIi_bx^qG>b2hEpwC+EgUm= zlQ3ukK_$eND($(!Q`!08RPB2JjZ`tWM1hd6AU`59&Y z*uVdP3-)X+RpvAU8R1|FxR#hXS))Mu40B?tCP1sKx}%fH@A;KrOvam=Skkcx@+5WrT)f!nZB{s3&9*-s7 zjHKShFgntCm}-9!+C(B04fQWMDU#&&@lV;~Z)T2_m6&lbyov_~pWi=&*1#wwT)YT%G7+Gju^QPH3vPNo{qm%EQ6EMQIO8R}KTi_bc4HjpWuBP* z)Y~4je#2*f)9Tdir#}!|H5|n>1)8SHiu>(JJnDZM)t+E`sYdu|j5RPV8vD21p((8` zvKbT5&e42)(#=?tU#I(LWs4P%T~htqmkbf(#cCj_4k81mJEfQ2dQ}LtM>d$FNo}~{ z3iS2xqnX2$(l6B*{|jL8me(7}Qa6;b0{LPLEQQNnHg#T!5zJLCTE7T#67x1FBSlI!nsnw zA@x6$Wsfop_;OD|sFEpb>R~;f2PRq}sILXDZ#1topY%&<$l5Qx^ci%NszmM!wZE@y z9X?rbc31Wade=HclzCA|(Mgs?48n)Q-ILm!>r;C7o>JgxrAA?um9Dy{iTxA~@D1>C zKVvlbcYWVGQP7I9*3PPYYVjfKMJJ4N4tMVHtz z6tbwP{>bZpHln_xE9jLGz7X%o$OPJsuaGe|-ZTKoX%IL9(M#4$a+2!&Gg{Y~^YtrF ze!<(yPW6sL3w?Jh9=eXwZl|WqDLoEuQ|LkrBh|5L9CIrR^Jp-w!wAuVmdw9K;^sIC z<6}c5Y^7L1e;=Xx$}DSHgb&eH5HeSqtj+jM`#x(tQfI?w`tvbb&9^7w?KJoi`ohLO zOy~m~?vbmox@OF#_1f%RPUVW(#OY*7G;`ORD&W7P~2dkTbx15z#~Idl9)w$ipFQO_NKiUx&KV3T^W zR;iSAq`6klhZ|yqz8!a6%TcUaVB-2!8d+^wGj$_3)c9bojk}c_OvFkz1~JXNNvpjt zCtu@jGAk)>^U^wiPgV^2Fo(WhI}GIcZ4>v)3ak>!srUg$1dTF3wvU{hepO=2MDWqh z=_kaGxQu~fG*~$iUh~mhVVn8QP7=7{aNM9xk@=#kuwT+}s9H8Vzb7|K$^eYy%U!9!UsW0q8<>!xLdg9Z)vr!&?n4_t*OgE2dq^x+zkMV~sz&D63rF;9#64 zCWQssN2AjO9~Z`ZfX4pup)`X#i21XA1_i2^dG4XHmN{#eLiqlLQ3NF;X z*E^-$TnNzCCFSKK6P*HDN7Np)#XAA7k)wHDgvYYK=-u0{?)qq^dh}O#_WCH7tu+JYIC`ywKbY-qnka68vKFctAJ^&HUXtva<=*w^yB&2d}ul>|pCh(f_m0ZlL>us>Rj z)XB-KYo|5)WEb}!fg*w%8!Dz(g4~T{0^Koij}z(9MeQHcE&J}H$wS7fJG<~LnSAv# z@i2uw2+fN~^QbgchI$pX$U;5EYQcvyx6$Jr`Rr_Y#0N#RuqyMkV^So>&g}?{vI3^o zs)qV3S`=5A2*Pq(PQxs;if|+Y8C~gPy-lN)-7rb!pePXqhayI~Bd#(*)y+ZHaQ}ud z8H}yuk9QKB5QBA*yZC1A4$^>~L+i&o*)xek;`TShTzcYeeF{_bw%dXflewxMd~ z?D;5aJN@hFuXSmj$pQ_zD2(LxyyuUWI8ksDPIYn{@s!!pl8}@-C1DZCid?Q5Fgb{Ehl_BM<8rh#UmOAa=h~VRtNg(1sflvM& z)RE`YQK4$6AC2)H(suI7zCkDGKO3Y@9%K?ce>I+{_Z_xvs-4hY zPie3u2njvIPhw<_B&qQAMvAl}ysV?%wGI>8voUM^cCh$d z5P~vMtmu*N_a%9KXKl*hC~7V@fw~YBH~5v5a7h`hVovG;_>!G+i>!VMlzb4J8JQf- zcS_}G(ThQo1$n4m&Uh#8?C za_|Hxo5pIt~18LVhq!g?@+%?P2ygk-^ba^FX1{o|c6tJ?kdtW~>)sBIhN?NyaO5&?%O*SJ1q!xA7 z*TO*rB-yMn;`&PrBO@nD>rs{2H)Sq3+4kbs{=V*zSh2;#MPszh;8s2_wfa$B(5Se> zUuD(%q~W95X8_EwZJl7a*&GIQIGOFo5Tqe}d-8(BBeLIo6y^HC-N6^M$e2 zT@_Zw<%l>?@DKd6$x0#`w?5`xE@ASO0|6(j3}{Zv1~UrZy$F@VQ=?;vVLazb=I=?6 zWXeF!)u%W@O|Qo{#E|@IWE*IHeaPC{^23Dl%M3MQxWdp=Smt|4n{4+O13Ee4wjj2d zX|89SeVmRSR9=vDkzp^oN?Vt>K z5X8EYQo&hTDP^>l+)FXsAYA0oQsZVyRq&U2Gcr@Ec)0Q~a;>H=2r6WdjxQNn@TuPq z!lct2977hP9>D22@i(dW$lxw_ev{RI#5La`i=}{c#amyp4Fb{157{lBD08UJVL)zv z&}l9$Uh7!CLh(dE=~w_k`UC9_*HTjLIE~c44;#$alTpq$2`J=>Sks>yJbbNHQGq4+ z8ug#|I(pkU!cq^=orKVV$wne%@3`sG1zUC2X<6(pipwt@<5Ajs=Y-aLHk{DCsL^ zdJ`;P^Xp-W;=SLgk@ua!;yDAZKeakc?_QOf6=<~uIA}n-?#=^Xe=(=dx~AmJvouwO z*FppRMpB|bq||6rn?PyzIXG|)vPh=WVz^}`jsbIm7>u3nH_7F7dpowiPX&2`{EaHu zHi!=)vkK1Rr%FxjY$X==8|-gd=61BZzm~c5y_B=6R*!SGs9Erjwu-yohyY8(2R-g3Q0cuH?KgTT=u@Rf)3^HSZ$?4Q*+2a35kVwIOhO|N4Lt$2 z4=unoB3jbmBB$1YG(rMcNhJ4Ha)yVjP*V!^h_4JzGyLD5Vm7Okl6m3L%mg)JK< zKIxCleHfD&N049vJM>slc)bF{EtERcnRKxQ~uJ)p9@VpBNz*}^Vm1ObZ=ip{Gu!n!j8`bdoy3MOz+0bSf zoy&5lrImS4E6Y9)Y>|u@c`4-c)ea&5mLkQQfg-<9rt#7Lm?fRwPiT~o4O#{!MV^eD zp!gE_f@2_gJmpYTNADi%|iNjdMmo$g;%;? ztwKMfDh-!YSLqbi7CtWRc!wf!?8{7PwI+W{cNYW2s$5wAG}qM)c&ESkWv&V_1e?lu zQ2lUg=_~RK$ONSEyjR0#TU{?ksDMQ|R4q~m>$6wxz)82cp> zLA7(jJ+FWsP~OeN98@bO*@!L4r!Gz>NMWB%c1^Yk#|_nxZ3P(fuV!KR74WnmWZuX5 zLH1W}*mJ5}DDgg*&2(tS7HsF$VzxyE;~SQ1Mk=1@i1g+3CsVo=lpj1+)=VI?a6{x@ zSoW><%@(+vyQ=J8+ba^WH(@HDuopwr`&TSH2L3H{4PR8EHI(%Aykn>yvt3dh-{o4L zV@liuPKg#Z&)3wy_q}q(?Pn~XZm$y9@YPE|f6r7I;ycOt=g<0LMyjgazs)_JSQ1@jn_qo@suEVbuM2TJu0Hfo z3^$c9(3e)f1{?RQz3Sb_c%t#p{xwbSHygWp^5?8SQD}2ezJ~5M%?S5MakD16Rh`4u zCB^Yjhs1fO6yhCBMdY`#W|>%0NQ`E4@tbzK@gvGwXoAR@RaxY`sEcHk-hf3atX?E- zaV6)=;dy@t{lJ`$Q%O9g=jnM~Goh(Gze4@YquT(Z)xHe7EK2>!0`vGc!=&+XUuZOw zrGZj8Hi;RMv2w?mSpc^p;k;QnMQAx(N4+(2srS%Z@xrT=Pqh7a!8XSzD6m{0i)(9V zqlZ(pZ9V%(mitBDS&sUt?Ki1CZz@BBcZ9LPinnV!N#r_pKl7Q zdq_z>BA}H3GO{%KFs~Ah7e;#>{Pbhu#L;&CLs3en4vjXE#Ke2f@_Zc49|236!C81G za@oHlSm!-?U!x5>OeB2)ShW3|<(mv_|0EknE{qa%9&GhJEXjoyQbj?^7i$Y7w3_5M zBVRHQLA-ZXOjh+|e+H0%O(&um1s(Z6-e*j(FPjhoe>?35;w*=eo2d+ot`R84L=$l3 zWTYa7Qn1Y0=lh7Pyo_JsoY;l3;WRa7aUD~eD-mF-Q&A2a&^J-$*yX!tKz3oIwG4Bzz`bUe^Z3VYJxNR?9_ z_rdTerBJ%L*Icz1cIG3!se!vtKRiHJjG zDh9o>=twh(Kl=QozxC2(sH2Iex{gZjj1b+*Qs(U%q)cQCtva_rc--<6~HZwk9k~A80sMU{RpUR z*nN3CMIAZ(kltLN59Y6p=;T5DBBsG>InF#$08BU3Z49L5XSpR{$Zb_pE4ax0OS_#X zDDjZjtg|cjDlJNaanIv@00=F$nT(<8b^Xs`&jsSf3v9PPXw{2?``iD+S%De7) z(6_l}Qm004wlcn{Rt~XGAJO!D$JN3o{Q({o@DU~lvBcdE)y7lZv9&deE2M;BStP)# zU+H4dmeX-1V8wC}~>Dc<`OTBwrZ zJX9$N_DajA28{>~5YLdy*|ix+f{7z24;Fcti3#Wgx5 z?(i{bw8;Pqu-_tAx-Eeqjk+E2I4TA@DnJXfKH)o2t(7{|l-?+fpLoNQTF=*#e5aVINZ*z$JawFyadXLq zA0;cX@6|1YwoW_)rAeCbUrt-|7ZK0biIJuxi4A+i!;8bC1H5EIAEfe+P8YSNPiFr; z2+SrJjSafaaJ)_SXa3QV!N7DO;!uf-+{`nri{@CEg)6)C@vxJ6w;LOhVnwMLORT$* ztu&yPdNqEu)(j-*$fz*SB0$3QdkLo-ytP(envw7?@|cp9XC~O7lfm(9kL;AlAy}VX z5uPKL?cLG@-7%+D7NZYGy!)x7#=kxYvttoWo%{MCs;!6rk$C<=S-N}5HOLqK4EL$k z^po94?%6LCs3s#x`n8ykZcA_WajT$+W9LPXBr*OVuhgpb0l~0 zAoig3Jt$0TG)1mRBSAui_2Yr(AoVFx8OM&`F~u6!ztgtIDZ`|$d5d4Gd3VW`Fy+k~ z(Q~Jh50b0y>7E~ne&x{1Sqdr10p)8}aR)GJNWKOoJqomH3y-~~!#i>5nC@pB+3PrV z<4F6JpYRraa6gF}ld~UFu#2%aJOvb2s1=SGex}8-V5j@wwR9;#qpUSEyMP#*lB3CX ztTVbqmwW4ZtaPrB$r2}t^yj6&D*>_4a^w#>jlP!H~^8?(TX>bS=8c|#KwFm(x>!|hI{`XypKdQ;w z#4>#0X+wqy+2T`O-t0cKo1=@A5))r?T-|Ya71NQM#W&tZ(WldE#|$ypAh`eNxEU$C zUp*}BcU^U+q~M{7c$P(2%DsIh}DM;$MWWWVuXYJjqw4V zRSIrTdjfTaZk+86+*HZttNWAzLGtf`;Mj1!xveyB zpHi-pqn=ueD#+!FCXi|C^~8Zt@Ta-T9ov!o7MmgNwa>VeU*|cHnjIMY#_QQQ0-Zni zujq#!O6x*3Pt;|2HTfo1*+p6Kv&5l!=2C4F0vxeAYFxznrIP`=6RIro4OGGEX>E9? zv{JEx(=7>AwZgKk5j1JmH#7DOv}x_t3O z0R5Hr!yD!@L*@xomStzXVJr0zx5Pg}vgMv<>TU-f)Y=9WCIa|R1#8Q@^V@tT);nC{ z4q|ux_~cox&7il;S)uAbamkXZ@z`3w{G zDN{kz<&!?#Mi*xrrCK70%F`op+5|@Ui9$^3gW^S6E-wjOd!u><^GPg}_v)Lw3-Jh* zy`PlfN0ombfrcR(7o)kxVhx5Q?k|Lk75p`~ zR1}CXI!R}E4C*6wMzCZlz~ zG{|-N&Ba9!i?T36n-0tgrw^wwZoE{zA{WqG$_CSy*@)^rN^-7LVhL736v3Dg( z2u~x*RJD8>pW1}NQ}7q60j+|491ViVIK^wqc@pz&VuOaJJcV@%8Mjif9j7d+v)#s* zQ+6iUXh9rWWVN^vw3}*Q{iOfPCeKL`TW9o}S))X)@-h2C7oDmt%2%A`nxvZ%v`}>g z^|beIL~;eU0L+RQ4)i=-iL=|IM|JG{7jg8iM-$tpzxd*vT6VBLXyg^@NOMPSGUqsJ zCA5OjR&0+Jl*9!cO0s?$I)tUgf`M4G)VT9AopNLH_P)bJi%PuWpWQ+~9CE*nXi1Y@ zbTp>vc?flLSEZTYHNC6YOk#x1nj455nYXRIQisN9kcVK25{RL%UI;q~N&8;?z^i0I z`NLH+4AM}&8e@77pOR2fO&z%GB1`2^B_uk2$>lY4`P8Y)E}!vw`tZ!mpb)W8S*m2q z42_=D>S%5wQJA!Ep~rG8V#r^zaA(ZMrSBXprrTVD#?e*H$#!1kV7Bn+hnW~*U&v+G zGoW3syFujYxRF? z#}CY3&c@ko?m6TA{qoYk`VgD!Eq__9lf4j1^V|hV(RT>#N%#5EkKepEH-!!`(QJ#vukC5RB<(^tp#K+9az@vjLt?&$0>}0z)i>nPBrZ;Hd4$D^4Gv=njr`lzX~$#UAuW;pkCCXd&=$|Hgh&ckD!N+~de)8$_I4!{p0NQG zt6&&CbKVO%fr~*o4vJ>N_Uzb4<_<-cW1~eg5C7yib@OO;ah6+IUvlX4acHNAkXnWnlhsBXPo;O*0XtN?{QuoBMh{j#+|cF{fxm!3M9# z2`Cq?9z!RVso{+BH(oZtIb<(MIK`=@?WHZ~(0}!s`jap*+cr*|ulmEF{OG-d6MHsq zRY3xA2RqIeqs0%F6$qEiG2l0Q^Br9fm$_k~+xBGEAc+ZYfv8?Ew22vaiCJl4WcvVb zmS^xo_N4)J1^HjmXRq4wbLIP$vgG((48bD zY*F|gu11#sT9&E`Ze>T*RDd+m>|ePI6*m43U(&>$+khu#GL5%~`?VU?$C9^|xIbNZ zhIRr2iaW^(hw$YRnwVT#q{-|TsOYqo?#<{r_^hQt8I*#PuMDCX$HO@qQ6o5rWW-I9 zE~@`N0|sWK8F6~G+k#e@+Po^xT6yqnW`_Q2m-DPl%#Ceuo;tjBTx$GQeQ$c4VddQb zTI6C_jK6-ZPB+CR5 z-fE`lN(LRY%Uf4XQ{y8)OWR3(_!p}nYuD|MjwegBJlDPbx((z#y!uK17PEAg1l+k(8=IKOjh zDnj7`FE{=#{ylyt>lxYl9)7oxgNZgfv@vN|!YE_KHe*MVAc-3+6l4ezU^i|Xl#&{s zhTryg?0qskEk-CY&*ha%=Xm4K$Yu?>V=9dTC}jfbLfo5TpnyNtEi!6mPCB6;aOF^S z2%M&YjnmqFIaZMqD$O5p-9=I`&e{Jo9%hpp<`JNEue;|DiF z-I+dSS~fF9gv_Z3j!_YJ$#Tl%d}Di1k#R$yGCMOL8zy-2beRE?C}NK!yG1;4%)5fe z3p*k~AO*q|kgIUAZ6Ql7`g+spo(q{~xR!reFB8b$h|Qu>yHXC&-4sa%`zFM?*B@n{ z0yNg_6qitl{WIwaX|=B5)$`IlTTInr)aoG?G|e$tapsuqK30@K${TSjkg>=2GJ8&m zb1*P5A;X(V(&mpgEAvY7Jc~Dws);v9cQleyhVg7gi3Nr>73$VZn;(ZFO_ncJkkDIQ zMvo@bCcwtFO{9rYT?T6FEbSXcLNJpa6A^XrZJ^|?CdfjfU9X9+;p;eA*!|HCt)t>h z5aZ^o`06~sd0Gs1{KStMF!8*p5t3O+WgwK>s}BnoQ-d+{biI>Hai+;+NBewZCurC~ zUoPQ5lYc8I?|&V~+V*GJUZUp=&as!D=5>wX7$mvZQXl=7GR|0g&1}?%+vRC-8G@NG zQ7nR!!2& zB}*j%-G4Jm(Ys$%Xd`@i@j=*FxM^p4i6cpVY&Mc*CaJcYDhTT{eTMgP<^fG_r5Wa* z(CU5{mCv%jl$UU0TAR5Ppd)T=>(ZK4mfA>g+!q~lg9_v3tvYUdb^a=L8)})@-NB`6 zFQMu>Y@&cs1#();SIbs`+YzEkcK3Yd&m9P?{Lkp&DE6Ji}00Mubujw(Dx% z!h)@+sG@u$cenBM?%?hGC9^BSs;p#f(paE(oyX^6nQ)TK4oML$~HqO7QO9hyVJo*F^$pjC7TIvxtYu2yF ziqlBL4Uz*bGKi|C@omV-2k&r~VNdi=N%OkhW5E_2a!l{!k-;p+_zUy`#R2vG`i*SF zxh*t~e!nApasVUtp?v!O%yfK}tt!G>qQ`2c#nr3l*;UKfkgX;ajXfRK-D0s?brAAN zV<7i^3;zH}9F;e4!-D0oKkr7dCVqZW$=bL9uM~^?{z9;2^6ngCLR5S>^Dv@9t8QlE zX61Iimbf^Ye}lO5l~`s6VXW84;Y?pzzG$c#-9(2ltdw&Ht@)-h;LXZxQQ~= z#$PEaz?duMkFPQY-BBe|B~?^YRV~+ktsAxaZV_yzWbsmP%<{5sA1;q$jg;CMp$ePnzBMc8E}r2=oWQ4tkQ~Eo2qhDa*lYWmQk4s*#Yvw{7lH z-exjz! z06{0IQg-+8oV=Yc14xtjbhs|%q-9}{U7DFt)t5GrDIfyJ(doW&`x?|*$Ln%Pufxj- zWI)I(8+s{4e!>)3{{XpI#0JQgHyIK(QC-AHR8w^5lS}Try!lry0Sa0xLnqC5#>K)| zV4_1Jsb&jBLEXK!_7;C?erhO0kAVcE9g;!hY=TP>pe~pSr!?JoBJhR=6Jsmt+1jQSuR1^#4mNO$E=Oa^M-nWp zi3k@>wOYP6`nv2aJVa>oWXD{_k(YcDE+lZmvTj);WLA-3byfJOO^o4+t^Aak@W-M! z60qpkH+qd&!%yB;)@4<-I8_Bqh7tGYNe2!`)8iEC0!u1UyyLz%6o3Ub4u&)GH5JLh z)n6YQwsMIW^5kMok*Lo!WG{_f2rrj9k_=D;RNSL;6K&QS!hwh zJl`sRPr`38`ulki-?h z!In6&F{A#7rSr-FBtpENuAtV|0X`N_a$%$HeVT4IGD#jYs{a5oIWrnR%*e6rEE-Q5 zJD1xSqP;)Yy2GdXIfCRDnZB)H^;i}a^%5*5+e(5qEWaHcH5gDEVIH%&@~HS&X$;hw z@$zj|P=vc%8&%dd1B#uupDwwqDhT65mPIFX72h+z@-d`Oj!Uu=Ood~V3s{nBc-YZR zpT0P;#|B#ia|Pd01^^)_2`gKkg9U5jAU~+beR_r8Zlu&Pz05ro!H!%#HpQmA(DOMj z5X;K1nS#r4*}Ia;0PG^B!yG`|BjvYzeiZ&6>7R!BM6$~)Gj}d(M!7Sh5m7{eVaAJj zX^Rqr|{TnnYY7wi*M;m}8RDoto z_@H5Sr`Vw1PKP4XHM|@b)G_yCh9!3f*kn|&%Ax2;1%+cbUX}65sY*iQ(Z4ng^hjCsizWRfsqm8mK1>R! zBYD0@1Ovz%b#tgDMzp$CB-m1E`N|cVY>m}0b*T1yRbx$y?#ggnHL;;BzAzO{DzNHH z6m>)D8%|q_Y@44IR0LF1L|@A9vTe4-I9jRAbuuA@k$Xw5f9v<5>*{(L%hO*R?Fspa zq+kSycoslAfU(IncgNGCewXO$c0nH6+QvP7Y&hY2kk8oM40f3x;>??AO|(e~*Gy5k z(OdFNn&}Hs8gW%jK|8CxCC4*j;o`K@NXH)?O#_uZ3rG-^@`ML;vbNYDKwf8104M#Q z+8Eicxw^F9!|*Ufc@xSJrdVMA0L_r=@r05#q-=bWIolGJvOQ8NqH0#E*EGb4_1M#s zW59Y)u8BXy&PO6B~JA>qmO8)>= zX9^it*C2Yj0*6F7IPv#)c;Lf~@nPu2SS&;$%5l=&RpW@*X-!a!*UGmO^61xVruI}| zWGa8OxG${vF~yXxrD^#C8or~ z<^~+}Xb~X5lHBRn#Z8P-w){X^`p0Z9BC^}_+YUt~@-uzaYl0Cq9LZ5p5fgN}shW8* z@?kjmm>z7Y%DM7QvmM)PWRb7{6*umn?t;N5tnoX2^KmqsJu@;bLG`4M0}T=&3UA3$ z3ndcr%~DLsx8WKGb_hk3vg~#hEwW+wV^z52JGll+R{i62knFOoovdEDk0X}WE-~iv z*-uHcU1hamGYw3O4MbRsoW(Sp`7*H1xvfbir3IiGnh)j08|39f0!0*Y&ymZ3NSh};*K8X;3mU2- zu$G$y&f0hP`e>6;>eZJK>9AZ=c416GeZ)g`&Ab3UfLm-wiU$$fa#D=mDjZ! zQ!pb4800wY-2fZ<-%*@mAKQ%N>IvFvfVv{4Ol&}uOMG~oG zjxeYw5P@l6Fjzig6pMK2;>y zSkMO!&GH~H@n)!SYvSO7J@kQ^Gp6R{;bhI`gAl@G`5|E& zERP3>5*Q}d1%mNqfhB?Iz|Omk#WJ9COEM>@-le3F^jfE>7?Ejk<86bCq?enO5*!NG z)%5^Z73ahNNQGS81$i4t?2SW8MDA@pvQBoOsPlQJv$2ajlnRnUZ6l#ppW&94M`w>|%?wLO zE(>qmSjK}nhXxyu6V1f4$tBAc&Ke+kZMe;W66}h;$w|ALxnt8{#@4%+Q)wY&O z;8H6QeKS=0k$2nGTX(h4@cJx$$KkE4wTc(ElI+ieG2fdtw;GLL=)R})&`{oGj|sfv zieF+aF(b$CeNHuxD?c+<##az;Cl&~!8`=C(9rMDqURWfIHP(!45^y)F#wI>0S4s^eqT0&twqw;(_i>t8YCfjBm*v?WcX3B98c2mc`Y=SQ z`nL$t$rY86t7FElibzZVIpN%q#1K0#|^`3>Fw4%2Cg-5Hcq=TOo^1Cl^W6@?>0wK+Gc%q%b>I<|SzrBSE^! zV&&umVxeFygu*eXNt$E2Yp2j!E3|l;e&Y6>_?3)12*s-l26quzVvit-DLJ#P`u_mg z&_;fxksgt(cPDgDAk)fjFk#G(EP_S2;xtK*hC8;W!GShN4bz88(|dm(Tf^;++8>^e z6&TN%m4TG;`Gibe)*-a8Ru>6*Q7nT>z|_Z5^jI&>_UlmL#+~A|jYhep$jF0Xe`2DH z{@ssNvru&Vk-XtRqaeU5`9a!=8qy3R8)3~Q!MWy%eFYBNj652#~|4mGrr=-a*jGr zEjv80my$)J$EHVeJ>}F!{;GV|n2B3nx7`sr9pCu?KrG%e^PncmE6rx4cr5*x)B0a>A@x;m| zk!%%6l|xM7P$d$=f8F(cW|qRH?fXvT62L$OEL_hQ4bH z23rvxVVFeoh-}A_vgSVVqP;Riq(vekPH2jyz!5l#0HXBQ)UsfZPYjc*zCZ)y$`UmI zfPyo?1A{?#6Up4wOYYjh)bX<8&q!V(jY|6^4CP7zCgmHfs45jt1Kk5;xGm+kw9LSV z9As5Ubfdtfgrd}m6Wmi&uz!~~oKLCBWGWoDkfAoi#>6TE z*JlsYJh{8- z4YEd~$$A>amrrKXT3taJGbmt`8SpiQ+u<8i~7nYvLq zaV%kHSqkG}!J5G)LStHzViY-BV9Y^wuZnSI+qb9dO<@95!;faF?Y(5jS~*NG=Y~32 zJPn#F2J_~BP9~pd$L1-vDCO`#HM^q z92v2tFmc{$N-CiUgl89mAnpp%4*s?h9VbSY^7>Ojk+KYSjptgTj;**9t6!6WX8u6f z_sDN?cOZAmpCb{7&k~GsY>x}ZS8J~>o-p7i44eex>RjxfR{WH6wCg0C=tHEnFvsOe zM;!gMS;Uwqi!||hNCj8S4SA`WfqlRg;1WuK z{ate2x?31Ss$@wd$p-iUJdKJ0MPg{!q7kUkinMNRSrdts%4;PJh-(*br8h)jyLxhi!g&v%PVm$1a$`_Ph0G}?ti;mcfhnuL&!mjCFIbyGcmULHn z0>)XnRw@8RAP>KDk3qV^>vBwFADT1{!HpiD!frrnTWGSGo^=E$l4KkwoD^3<6J~fO zzyz*r{3MSf2Up6`^>mICstF}Cmn$UD)C0Ut&(EmzBGn2l>29)$8hrKe@` zX^Q-VP%>B85TmXg!^GNsBM0IJ#Lsj>IL**>Uf9LW*PpyG`#VL{nc!@x5KBDUNojGk zygULQssaa`Tc9w1AMQSbfQ2zk&GI1bC z7NRF1kn5Y1T`p(s*4K56ZA(e*oku&jT8<`WsSJ24HvO!##g8ayv9O{9$S25+-gC6V ztHbqeKC_XfL!6T3}7 ziHV&)P{&}6mg@1q@(=@lQyoi9ECPy&9>ny{i&WiR<9;A(T85(l)HIm!akUILF-Huf z%N&u?r1_JIMOgu7c!*%DM|mF*%h-1zLtxU`=5?5z)y&t`tY(_7sq1?DZbX*hh z#0J^2BofG2g-TilI9i@gdc&sbF--aM*mCp290k*kkUBDGC#Dw+3AhXpiVM#H6Z;DQ1G*JcdZ6d;Lir8-{_<`3~>0_&j zHNkA3GbM1Gb=RLFQZDSQTz=Z@#yJLALgh}uN#7wdI?!Sic^Cs4mJzQ2DxyZ90lwwU z&+bm=jgi!5$&DOs;Z=)r#tDrmvv?F+?STy{ey&NTi$OHv)pC05Q#h4h0jU-7->oT4 zGUa>Bp*bQmQVf5QsV_EwjV}T5xgZJUAlXep_>bIp>7{0B`VKtV5#|EQs6y``z3fzbx(o$_ zm?b7fWd_?Gax7}JbkfojG2(>CCVNfEKi}>GhE_SfyN*kk$m5u;INWs)0Kh4a+T}Ed(%Y&xkO3_02(8s>KWo4U{ zQyIwK=;60omE@5_+aC(A)a$%zu;j~XKh&4e#fl?Y8R-JUlR`x3>=3yk3W*lyu{!I* zQe-$Nk=klZ+O)m1rs|nOD8$OElY;>3e^1ysM1VhLan zr$ES29GDqhe0&cUZy&>JVNANnrc1Q8nSC{<)-`ynr=~aIIW8pWT-pz(i5fDy#Y13l z)_Ea;^sJZHvma5`q>?;*WDvlxAyCq`#f`}k0~}i&yt7K-H--h2GCfXQ3}c|Kg^h%f zLmZh>N(`+y-V!#DD*}RPT!bpcLYuv|dR#K5Ya>c~BZ!Qjh$V101%X(LB?+@_hWKn! zP~L15hi*f$w%;ODMmCQ5Q$-$^HsBnu19d*iAhEj&LYCTn8&+xp#kKTPxrJjDZL?RHTCI?L~mGSN7|jHIb-gX_}OAJ5MZs{y_j)e;(jL zKLuPFPyhXXXA@+y|9nlu613N{)((|PjKgNni> zlt~V5r6>c&D!j=Q&+!GeyIV+sem!0sjc2*?qS5~VG5jAsX$jUE@XKM*~lpM zX&@YrRTdHrdog_Gq&=tUkF4rluO@a5{O;j+#Ly%~W79Nn%_JHY3Kk;|6vhPE-ZHXg z%O&JXH;q@K#?xidVagg#wAz1f;$g`iGw&$_%W*bNZghii84gN-T*)MArZ|nTP$G$d zV=(YMDmEdA+{VbQBaM~jadynwsM6k+py4rG{n7-dU^^}KenhuZ$oT_e$BB|8QcTY0 z)$==(xhB>1B*@e8U%`*3;>Y=ij7LEE!~yaAu_Ackf-)nF64D7Is;2FJ%hK|(moG0W zPTzpD7$(dH70WLnQz?nxbA1`VmI-2H-ZmblmmRSEK0Fo@vglFo<|9wZk5^YBY>O^(ML!Q2MY^`H0yte8VdkfCNr|4A**KyX4!Gr(IOoV- zM3q~lRAnJI-a3#RM#UGQ?6iwSIhfjpqPm7FNd7l+cE=ocWb!H?Syhk4DfYV+1A#$4 z)qGBk#fLqZg#rv;3b`4$@?5o(B>0xMWMTDGf1T zV~21YH;qy?>M#8`{r;fQh8IC=b7JExzbGu;8cKLFTJadmxw*0dZMx$td}+P-rUc9b15)!Rhdx78&5l_+zfER4Y85Rl98!%T*}vBX>wR+Yp_S8$2L}M z(X5X)M6lx#C|%4B#?~#DBu4+1)W?=CPtpSMh-AK8+Rqp9A@im<*L+p&4JvUS_!4qdk;oAr{O2djI zXl8Z+&=eaSscoPI9Tf&KY<&f?JChAFv~~?9G!YX7lSrWeY@2xuvC&j?LTHQesVA;( zX@JdsM0r#_b zuLzUv6K)8DPM{uZ+1cIEqUyN0GE8vrp_IEwtg+27c1Y!xJ%`CGQn8XebR}Yt6fDw4 zSP5(0*MvKdPJ(Snj5+0uE<6lLM2n5i z=j@DxdGhAu_cLVq2$poNZ_JF`cHDJKaAiJ;589$9MK~HdcJ@|@g3>!>7?aN56ps@g z81{kVj4W#-IS2(AKby2yC#`ypzl)IuwU#%e7_&LV9yp`NWG+geCB7=JfgUv}&W|jG^ zV_DQBRTy}9a+r`%GlLnkAuI@iT$W`kPU4)MpaTn1?tL>!(lOT@E~lyMCv&vwz92R+ zNJ7v%qkvl%Yb@o`)F(+sp+>NfEd@12jAmPTMaLF2x0K#6Cr(3+fGDF4dltnMy*4PN zzqNVx(kyJ}K6RDZYz`C!27=k5S^cwdc4${z{{XEvQew@8HudulAyRD*9H$&n{POODr*~ yPN+gJrCKCV;Fcf*{rz2Y(7Z9hjg+Z4GUG=eNj9yGrmZN^WDGX)O%J~Vum9P1Q&6n{ literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Mocks/male-4.imageset/Contents.json b/Antidote/Images.xcassets/Mocks/male-4.imageset/Contents.json new file mode 100644 index 0000000..080c894 --- /dev/null +++ b/Antidote/Images.xcassets/Mocks/male-4.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "male-4.jpg", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Antidote/Images.xcassets/Mocks/male-4.imageset/male-4.jpg b/Antidote/Images.xcassets/Mocks/male-4.imageset/male-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3eda450d0344610353cf9babe49779c96cc9d90b GIT binary patch literal 5844 zcmbuCcQjnxyT^}Vj26B3mM}^X#HfiDX2@U+VnkjwN(@GcE(jt-8@=})BBDzoQ4%Ex zqxUWd35lABJKlHQ_1-`3?~l9gv)9@Cv!3!jdp~ELwaz)8JYNLp5x3yC01^@sK$kdx z^JP#zTvPKeLzKZSxV|*5uUTFP?r2pimwzK!N1ppEXVgk(8-NTE>H;Ih&@p8Z51R^ur zI$GNixtPcj9>fh2`SXR}<{w_YV26MB_<}vqC{5zlX^714@DEE|u+2YwaTb1CM-MD9 z$A!qkSQl^N9{#qAlhD|^nivyT?!PZj00rm(8UR0F19$^YfD7OSND^09V$c5fx@&*e zAptjHjV*C@2mAmJVub_XNUW70dc6Tpz@E6?C;IJ)!-beZw2R(ftN`$DPd)F;Ug!~z zOoIRb@XGo54>16MWC6h0lk@Xmh3DsIMF2oL2>|bs|E+gRCbn~z=ui09C!7NSbdLd` z@$J7pn-TzMBKDYl-rd^6`tSRY5@*o;`v9?~^LGFP z1rP#+kdg=jAO;dr29onGfQR@L$Ve~VoBuWl37DJ$L`nuw62ofr00}86h`4z$IT_?4 zh2$axW*}#T2*{{28Cg>>3*tgqt|h*F&nhHqQ!q@a;eppg87I|!-y_y@kpLi~`u~t8 z1A|D(0TKu?D8+CgPD)AwA^W?7L~&v^8G`_rQHDuS-J0c^5iT_GJ2|t^`{AX%^J##F zl$gLk$^hH|UX^1X+@k1}@8mPUaJE*iSLqum-c1pD&owk&iZf>UfL|eLD9{vuuV2Di zNQzqP!prNMJxcG=Q7OFQ5zoDQ?2gI{z|Uxfp;E+`&3e3VAcE6ekt3xh^(UMWJ;UQ{ z-gGk_JJl^X_RdNpp)a!0=`Zg+epb5P9C^^YrZa-^U-CsUqwHXLASDBX*ERLhE3~bx zgP8|~>*4%e0#~Jb`>6IdW{uW0_xQE1s%*=oyLh9*=<_}%6sTB2+(xt2o1K#sD;iT; zT8fJ@P1hBF?1D+|{mHiO=Fn-viF~R2P-8z)8pvSE`Xcsj%i>S=vTBZwU$IM$i83W} zeJvsWW2J45s!FbEzpbuwzav{o{D?HkT$bTsw+{&q4GoPpJVV~jx+9TJ-opnU{;`|d9bwZQm^s4zvkv&8cFpuCo2ap3Z1+)d}$1p zyKTJvHOaDOdiq+O-BhbkGe64`Iq$pc3+!Wce#pnf>e^!~9$3Rs9lDon4~n@GJHtN| zTkSvB{aNgE09)?(sLg9-N-z^m5h7fVN^REFhb%})3cwMgy6dX`#%(nM#cZtk$)R}o zs_139`0ac zODSn&jvx#3r}Znd@BvF)YL2Kp@Gw=u&)*QERY$E%f&!SleACIollDb%UDzOHi_J8N zidwO&8-`!JZnW=auduTyF6QPpnI8wdGKAaAmzGLW=*4_k-GM`L7$4ac3L)RvS}z-J zYrkNZ4ymOJ)_ClH^rWtS7oPz=WC-@7^TmaQa%l`I#w{q779_D#rYUM3h;C8X31Q=8 z`!0)}*|mP$lO&iYOl`DKkr%ZNnNHS^mG`Ei8|WVvkct_d7}`kuiVK-YsIML*MOJEX zi9cjCdC9fcpLf@Rqk@e+=`f&8MSA-wgzVXJvJw}9b1AGQG!_PlV9DvW)bqg?I1rj2 zsJzzjjNTgYue19VjXjN=Zl-_MB zqkgyb@&KkU>-MmCP+g()VqbzXeE`96IU;AA-OxAaFzivW`m$R3QI4|kTSjz8pjH(J zgqdgQwG({#(o=o<29BN%q{^9d52irzQLU<5GI~1C`gRI!Q7TD6Kr4bgt))OJ zuU7z@RtlnfQLPwhs?LXYPaV)dorp3}3r0+Cem@7MotB~p9A(fa6j1I zIKD)Fi{i{_-Y zE31N!a4J?VxDKkG#qo5H8?m4-=uLLFxty64|JC1egi5c-7oSg^ZyyenyH%mJd?Oir zx~O=qXba)3rKMV$=b;+w8hyrw&>I2;5bbdzn46Ai^^NvM{;~ zp|yKaw!(l!lxr0lqgA>j?Ve|e`wQ&^Z*uGp`_={{bxQ3;q$)p)7I*)%<~xePo+yP; z>%ZnPcE(c8$3J0L`Evim8*Wu=Ty?8f#}j@lw!4OoRWGOEP`(^CU+c>Xw`o6hz7$I^ zU1uU}qDG;!HnZ~-byQTTbSs_#F9J?QTSg?5E4Z59M3AQ?hshGsnN=t3nOyhBpaO7< za9T^n;Zo0TaWMolDqJ+14ngvuf3A}I;8x0tq^ndRBODo!`Qg_5FK|`q>@R%F4(G#b zbMr%212@lNm>6!FbC`KJwck{Fb*Z}z4;qRz=}A76JHTbC?fRKC;k;{V+y#_3_vvrC zr7EJY+L2VrlSc22avOJ-50LMp5xuyRA!cU7P~c%ac-z=ANMOyO3l7&>%1 z?(t_U*kNCOv?%dzQXJ<{Vf&tZw>bH(CJfV#jNMeY)dZ%$iHM`PA@=30nlQHuJqH@w zcg)R&K1gSowKd>#+rThihW0NCf8J|ni4BPcc`wJV^*)3haUuEVa(GEYwaH>972zD; zv{uTohwb!wNxW+8Vj5IEsKXP#&qq<*DlL{Z{ts8|lUI5hQqf;Ukkn3QU1(K5TV~BC zR@(2N6O56wq@CiZV7Veiem`C`86)D;jmt{aSfSNwKxnXXaGjd)M`;x4bZ$m>}NpOzvc_2{mJ5XmyuNpT>~S0ue6~=<w_(5s}L?>SFko&NM-NNg1s!bonh>Egax&_d#w)Q=9NBms^hUrrf+T}&RAXD1Hs4h zpJrXSueL2nHkH3}W%a9)5{T+no(>cT-xLiE%WW61_{LUJT~;iq%`d!z^dq?mmvYVB z&Oh5=4)&8TDo!icGa$KtAR6K*f_HtJ;okWSBOWC^x>IA5-=mkMI^v%|=z|TS6zE?R zRCxCVN-a{pjOnHpsNF|IO$Rv0@8cz=WDs~lGhA`<7Ai1K`R$1{UH8#y>Vp!g%y_He z>ER_uC!1N!5sY?eDDe?~(sk&{OoOwz6pTc8HLv=bbF3e0uUrOQ<5monQCvzOT%|F^ z4#DP2kdrOdtB;&Bu)k|t`EFpq>A%=9hV&m$rH=llyV4W?PwIGk>BKI|A%I7%B%%*dFCnm z9{()&+D~)CKgpf>XBpKhienz$v5j`I$lvV!mW6YY6pp0^s+GnW(*}0gG>it;NTra7 z2>#()zIPp-7>IGBZh!Rbt!$nc(B{!no4GM*?gH z=q;T`d}jxyrZZj2Dq-n+#UJ)qW`dzlOq|J@ms5Wh)92=~NtJ*wIQS~9xJ_~ME$V2Y z(Ig`*DJB3RK0PGVQfXA_t%=8=?{t+w@KN84@MJHDtfWs{022*CT zo3fALW`yt6cA33LK1)zB$^4wGkU>@4d;UE z9&69|2HSjtb z=W@l6eyQK5&}(&vu>OXBFJRlz^LKrqKZ8X{Z`D3t+CkE#Sz8uwo0+?@`miR2m0X7Z zIf$-#`{Oe5DTV3oow;nPg!g0D`0G-SAX%j8cXqxwayl;gyj@AL8&OTAvFeD|XrGs4 z`VBV}(HZLS=zDn<%UnO!r#(3GscEG~DSN1+cn3Bl6gO4FMVlY$=TcH@;qI+|2Hk|| zu3?m5IZQ#@@s#p*18Lw?0WDa2XOLpooahez7Y8p4F1=nN)E&L92o56qMT-+R``#wvemr}4k9kH=`MT_nje&*TmmDbLHY>7}^0QI9 z&;-hj9(!ZK+0wknvbEaM3#x-GpO}K)%(rf*jkZYJlP7ZoiHa$TThcWk zqxEWt|86EjD3)^or0j%v#FXjVyzuQ;zv+M?F1w)rA&B7s6~)3bdaa?T5}r|pfo&|k zQWV2HDiz--ew@%K_cgKX%7T4d*2wj3mx`+mk|#88lf%-G=qUrQl~Vs~pR$0GhV_gq zV}6?9v@Sicp?nd@UipeY-cC5Vk1#<}McwOqaigeZJ!U^T(-Czpk_J7MEydzn;tErE;bOlP`_}hYfLB>ECXE z8^{My^|n;JIx3Zab%@3bw=}F|9s~*5os)=VHbV++${~BrFwC|K`T?`tj zHi^YK&DaE1hVGbElh>_W8kqcc-1y7sml_nZBv9v59yrnV1x&^LYb;R=(*)H@!o#<2 zTWu&gQr$Xo^&X)@m#M_3h{AM>HTp~`hF0#COK1xs(c+^|w=?&*@wxXCMvk7}_MVW4 z5KtMAaxo=aZt*x(FPG0&cF}GTv(T>#&*{h10wda# zI=AehjLDN2ZmnkLlkI3ipX=y!`@>20J>7HQTD!W=!uKPBdupss zT;sUy@6S$6v8}o;7ORQ|4x?F2janoJTHDWVYi;2hcWTOQ^Tb>pAm&6qb;U4=&GkTk z(p-5?y;DyQAar@})UZ8PH`fKmaG%NBQm${k0KG5J_8L!YvXFc^9n9>&gHSickU4zj zth_gq`4*W!{&kbu#?qfQ*P%OONw@+UWJOcO145y)bGPKNu&0%Rj%RG%qn^6o7j=v) zh~G9!rvf)j=+zp?53e>|{==?6mgJ-AKAOh1b{jVrJ)d8gQ^b9E4v0P7$jvBwSC=aj zUI@=#X_;zYLW3q;n=LP2k*s6Rz_Y|w>o_4rR~J2WReOFrcAW#S_?U{mpCT)gz>&o- z_p)H7C(e#RYfFkq9m|ZlXGd#h{@wZYY6-bz>Sao5hnB$UYLa@#Y=5`VXj(>KCC3Z&In*d+}w3 zvUYU>7PcDUA$`|rBLe)Ybt=R}s=3dQlA)gl2$BlwnQzVHc&gomE6)LsCW9te>Mp%q z7bbGGAv?w=!+i0ZlL^<}I{pM_WQ4N147Df;7nD_;G8 zADId&Nrp`mA_Q(OhAGoKMq?5U`=`65MxDUIyRkL1kd!L9l$CqTC@{2m+T=4+^nuc* i0;dCN#!R5Txd$K5AjX~i><45s^Q#}~fe#FPKJ{N4+z6Tg literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Mocks/male-5.imageset/Contents.json b/Antidote/Images.xcassets/Mocks/male-5.imageset/Contents.json new file mode 100644 index 0000000..2cd3019 --- /dev/null +++ b/Antidote/Images.xcassets/Mocks/male-5.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "male-5.jpg", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Antidote/Images.xcassets/Mocks/male-5.imageset/male-5.jpg b/Antidote/Images.xcassets/Mocks/male-5.imageset/male-5.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5ee9788e37d860485d0fd52664e6f4d027a59939 GIT binary patch literal 4967 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 literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Other/checkmark.imageset/checkmark@2x.png b/Antidote/Images.xcassets/Other/checkmark.imageset/checkmark@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..374eb6f2c32cf1994de32baa5547a9793619328b GIT binary patch literal 385 zcmV-{0e=38P)9bKf#h+}Cvm_dCAtd7kfc-sha&hcadU5mgvRb*utr zaEqoG@($c#I)=Og+t?S{@aIh65j`>F8C+o@h8)(AM{NxG2wu@2L*9rpEX9z+GEUJD zLp~sU`k@%|dK_aVO_EHC*hQS9x!43Pc*a~2vDrfGSh4biQ9K}r%5TP0;}Dx^f+N4VEt(S>_V{-!*kQ#jRmw0-iv5_{Mc{(2=LBlPz~*zHHA zg!9r}DtST!ws48Q!n0OfW46@tgj%c$W7RM=aDp f2?uElC{yMgr6@Fs4z%c900000NkvXXu0mjf9UrVH literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Other/notification-app-icon.imageset/Contents.json b/Antidote/Images.xcassets/Other/notification-app-icon.imageset/Contents.json new file mode 100644 index 0000000..f2114f6 --- /dev/null +++ b/Antidote/Images.xcassets/Other/notification-app-icon.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "icon-20.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "icon-40.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "icon-80.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Antidote/Images.xcassets/Other/notification-app-icon.imageset/icon-20.png b/Antidote/Images.xcassets/Other/notification-app-icon.imageset/icon-20.png new file mode 100644 index 0000000000000000000000000000000000000000..58bc7a39e0423983c1e4d013b12b839e6884f1a0 GIT binary patch literal 4188 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 literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Other/notification-close.imageset/Contents.json b/Antidote/Images.xcassets/Other/notification-close.imageset/Contents.json new file mode 100644 index 0000000..e7f48a0 --- /dev/null +++ b/Antidote/Images.xcassets/Other/notification-close.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "notification-close.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "notification-close@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Antidote/Images.xcassets/Other/notification-close.imageset/notification-close.png b/Antidote/Images.xcassets/Other/notification-close.imageset/notification-close.png new file mode 100644 index 0000000000000000000000000000000000000000..3df705c36eb6ce925d16ae8f911aab84d61e694b GIT binary patch literal 378 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YDR+ueoXe|!I#{Xiaj ziKnkC`$I;4F+<|{Lp09sz2L}qFhQX0p}KFq=p(*uerds%Iy9CiTyDMG z`Hdmx_SDv_6};T{uByC0V?Og?e-Fzopr0Q^OP)Bpeg literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Other/notification-close.imageset/notification-close@2x.png b/Antidote/Images.xcassets/Other/notification-close.imageset/notification-close@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..21fca40f4ee10c33b4c190c3f64e1e0b1e8e298f GIT binary patch literal 283 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdzwj^(N7l!{JxM1({$v}|{o-U3d z5v^~hS@Rt-5MX6rVltzeZcai<|$_Z%e(`!Gpw)hGmHcp? z3#%f;TNY_|)cxP)w_+``RIc;%%paDlgN~{&VZb-a)6m;Oght7v;&OC?Z+kOk^3BQ~-H8CUgLrTIC^|!9u zOzfR??J{K?eJvRnnwJQb-4{6~2eeAH#5JNMC9x#cD!C{XNHG{07@F%E80s1sh8P-I z8CqBwSZW&>S{WE@u;8>q(U6;;l9^Ts*I;NGVq|1xVrgY$2+?r$124$844$rjF6*2U FngFqkXmS7m literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/Other/right-arrow.imageset/right-arrow@2x.png b/Antidote/Images.xcassets/Other/right-arrow.imageset/right-arrow@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..d19a9718b1d2e7ed239b10994de4d72f843baaf4 GIT binary patch literal 162 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdzwj^(N7l!{JxM1({$v}~CPZ!6K zh}O5)HgYyN2)JBazOijt6YH%d5$zFOyfZkex((Jh{wyfa5wyRYcr-xN;Ng)lNyEnn z`V0j-JzSLXbmVHn{$4j-JJrtdnDM-iYNz}+eOhets8syQG-a8XsY{B1Rxo(F`njxg HN@xNAZp1p~ literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/TabBar/tab-bar-chats.imageset/Contents.json b/Antidote/Images.xcassets/TabBar/tab-bar-chats.imageset/Contents.json new file mode 100644 index 0000000..cba6439 --- /dev/null +++ b/Antidote/Images.xcassets/TabBar/tab-bar-chats.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "tab-bar-chats.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "tab-bar-chats@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Antidote/Images.xcassets/TabBar/tab-bar-chats.imageset/tab-bar-chats.png b/Antidote/Images.xcassets/TabBar/tab-bar-chats.imageset/tab-bar-chats.png new file mode 100644 index 0000000000000000000000000000000000000000..e4f5fe854242229abdddde71593c76c3acf55d49 GIT binary patch literal 731 zcmV<10wn#3P)P000>X1^@s6#OZ}&00004b3#c}2nYxW zdoIyQKVlnz-Ax@w#&PGI2 zM0{UJC8Z=+GX_tv3qNDbf{k1(aX4OL>Z(273Y#3|!6R`*1p zBEg1?F}f0&gR@-)bt6*7HO#0LQ^HsrOPyV_Vm*D2X;J7;8Je{0B{la zF$kw3Vs&-ETh#XkRRyvEXv_XcG-D6S9k^~_Fh0kIN7<~<3dC< zrj%M!N_TJ*Ya*gAOvh!pv|gb42KO;1j~mdC{e5UE;W(aSQ!lI7j%HlxWbG3E?KsU( zc!;?@tYRge;=4RItQUgaV>yxWklu~Lh(&UY}g)K!8 z<@XV+`!rwhHm%A?4`4z8T3Jr<9fz z7O4;`V*m!BKc3+=W@0{Ca035h9QOBEq?-fOVKT;JDBj`D7Zs^x9|62Xs5uY{sa^m8 N002ovPDHLkV1kR7G?oAW literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/TabBar/tab-bar-chats.imageset/tab-bar-chats@2x.png b/Antidote/Images.xcassets/TabBar/tab-bar-chats.imageset/tab-bar-chats@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..bf7b912e8bf8a8c42f4a694b7f3ea811812768fd GIT binary patch literal 1537 zcmV+c2LAbpP)yhMI`j z8U?Lbs|M8=MZ}=Nph`ka^n*q#s?n&Zl4vwV#V@MJqSg-(l_pwRQB&-Tr3xT#f*{mx z>Gi`s!;aJ0?#}GY4xHrXnYqt%&pH3+oO@oL8>JMTP(%#jEUdvxFp3j$zpx`f< z-!BkNG8bVN3Vz%xAn!%NJy_Il5KVHI;$J9OJ0l>NkB3mOezrg~fq4%K?!+-O0rEu@ z+%Vf9QhqeK^_5-nFbDUdVC5iyq#~QmeNZ4$kvaGe3ijZ#P9oV5-T>HW zfK*C(62AZ}#+UJrh`2f;7EiT)2&V$J^hd>x=mx;eco_3=1$IWnrH5NMgp&b#`lVe5 zv;c)GW{vz}`0Z9>6Nxg|qQ-0C+|KDW$wB$5y-+2l4)h zI2~XJe*wG%gQjx;w@1WSM2xk0=2N%}!}v155Pk@_C_gL=gd*ZttVO|(rg(e@9>BQ~ zu@00{UGfpHWp90Ghk z8J&&8X3##-CvXxT!QInYP%4^70V|pjUVwsssy3CNlO_Q@K;?yor6Xu{BD)6Tid)Y>J2_(=l^56cOj)XPAS%rIb&0!Dbs^MZ33j zw26(kp$}FV!Dny~1sl;-fWeDUu)W>Q7o?DVII)KS01|%Y0 zn$I1?-Dr$qEWiRR#kr|`0QO=7t}UhPn;{4h@dK>KhZ-iDk4-3e2xql1<5FCOzo3&N zg~xCM{)n48aGS%r5H|hr(hYDrMb3YYbm8&rv`8Z zR^t-w6Mq2(k7CU%xYUdB2o6csGi5x2@1S5m-j05` z({enBg6p(Y12gIfODW@}ly~4$7{RykJOrSZ^kE#2ZFpO0J?`$I*)KIw$?n8^ame?l z8SsB0p2UA~@*($o?8E1qXq!t4-J#`-Q1?l2BMN>Zqg7)(RigBY@&m?&_y|@4#<2@K z6WAI&j?1wKC+77+++9j}SqslGz-9P7=HW+pOX)?_nudj5jvMhLIw@;z#rw25y2eWU z3k5e~USBNIjw0d+oPtwxEX(U0+=qYWI1LwKE?^u#$9J)*l=5&|=Qu3ELi`oy%nFcB zC?bx=>+n{r#xMYO;}|@O+wexfH=lMunkgbqz?<ezXK$P000>X1^@s6#OZ}&00004b3#c}2nYxW zd}PGSVlP*w6a;t?iruu{kyw3g}e7$VejK34Z+2kU~0QQuDG+_`~HR4C5kRddoNV_nCtmaTtDWnB` zWgvZMK~~jyHH#o41w{Z3$#jxZYQ{O-Ta;b!dYUnXtvRtqOrkmCzrf{+KVxarD_qL) zpP(bhpO*7^mxAoWB&rv9RhYuIoc!Mk#!BH7j)>0)tOvka%tgdR&X(7Bn^LN;=uRR6 zYB7UN3%m`OMO{vQ!X5m=OYB~1tn9}CZso+TV+e}|VJTjXHjJZv5d>$@gArUT)8z#W zqgTNo#ddtf@e~nKN;}Yn2DIaSM9dZ47o?O{;}mXV439B^g*uC-gnE3!L)?#uf8~nj zz}BJzZTNy&EYv)7<7&~-RJw2t-FdNualFGAmZLhHj)>Yt-Qwmli)VE=BK`tEiU?Ry Z{Ra!+mYVzWHaq|T002ovPDHLkV1f&f6_Nk| literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/TabBar/tab-bar-friends.imageset/tab-bar-friends@2x.png b/Antidote/Images.xcassets/TabBar/tab-bar-friends.imageset/tab-bar-friends@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..bdc5434021f0c8076ab45820da3dcca7640f274b GIT binary patch literal 1368 zcmV-e1*iInP)JW|WyAmn_ zVMRfyr2rrZR6vvfeGdwWs3d>|rV3P&5*1;f(U)waR&De}Hrgs{L!~?0cmmFIxW~)x zdEfWk>m0*B93C#`|2)t8f8X=I=Y5}ZMOB#$$ers3R14>YOf*cXG=PZYfh&P|Km$+! zdhF^@)k38?yxNgvvWrL#co5hKtV*GF1M5}wyAuC7MB?*66EI99{2Nt08r&c<2oaIl zz%Jkx0N^C>A@B>(2V4X!0ag=@&?%rD*bVdoj{#eN+A=9#1-7c{>7a(Gs`mw42z(DH zFaSIN%qYXH1Ku)jd<~l&1r7sm0FMGsn$UvX{}Xr}Sm52ZKq1dtqHdtU)8{JSSzyR~ z`+&>KaF+oc3E^eAnS}tC0sjFbz||ogVE)YsF{>QhrNAe~-Cu1X8!hm=p&}A7wp)x{ z9^6^LY2aU=&czRTkHnMvy#Sw5>@mB-MO4*)fRBM`z&aN{M96%zT>(C&=q2jqMiH6j z!9QsBIu|iS$V{_;1^Ao+RUNgQLNwoe;arMCgoxRi0G~4hh|C1004Ge83-xA)T*MF| zy=IpL_>^Ln*}*`5RfY7JtwhKrW{-RFmz(|8MI3J-tIdAtB8td#poQWtAQf4JEDi7} zMZEeP^58B4rUC*iaFMetzfA!?rC4LuxnQVjH}E!58<#uiK|-4WnZiZ-)%d-7+S zb)IQLge)}cd|p!!`z}mn0V1*$xCZza*ze+p2svW*h5(;Z#J)$;NFp*9c#)`mJ5}|h zGjhO&Z!Ms}aiBHBhOyOr6OvAp zIxWdf0X{dHPnQRGbE2~@_RW!{9Q2Oay8?XfH0zwSz!PRSsp=oz88VDWGoZi;An(D? z8&`o99{gj*ofFiqP$8D=O-t4R)TZ#J0ACn)pJ(i!jqgjU;P?SK^D8&p;2R^0G|*{3~Ekw9g&-?+e*c6y8Nl`F=Lg)P7k za0k#WBKL`i)4v)*d`84uh^qbyTn}^ti-_jqF%fx2MCPYCW|<>-;9o$2c`3Yl$b0q?%16@GefOb6ICuL$a0597ktH1$Zs#6G11Ka}~29m@35@m|lDPmqQA#t3~ zf%{2$52eJr7U;J)&y^KoiMIj2ClU{ufW=vQ)8aM)ZNT4&xC6i=Asv%=+(xWpSB^#4 zP$HlccsMkX#|Uizj+O}86c}fR`L>Cw0$?wnS8SyK_zZYTRV%6WIw2yr1CLYu@^u*4 zi(e&j8Br&H8Y>fuXN^<9z18adfZlDTxGIHSh4^FWHsA)J54cTLzs}gfnW3t?MWi2i z512u;7<7ij$W#2}b@O|h#koN>VHnp9Q-LbTM*JuA(r9Q~?#sSi;A1tu~YRrMzqDbqh6CL$)ypK2zJ akpBTI_0K)@m0g|y0000Z zF;7%M6om&ufyp)&SQsm?(Sk%`XQRE*auZ{;Q48&@CsJTVBadZv<~t!)U@S;z_yq*i zg32FY16dkl*2E>C7Q9Dxmwmf4yL*#KUS4L-IWu!-=3HYUBg?Xi_r3}^U=L_WYDsDV zjr^bU-dD3MtHk0C4CmY&PzQcX`WM-nK;1bvH#D)eb{bd$P7;Va8gK$ES!<`0$R*7J z2g4Hg5ON@CHj3PPKMx#@i@Z(5k@tQ+X69ojZx>Oz68WB|Ec+qw75J699X)eG()&n& zGf8i)wNtt9Dc}L{QPOE7#!?4)e$=9}9eCL%f9~u2ZWwqvI*uq%k0k%zH;K+y@GA%V6B2?!xPkHz!eR}J721ndqH0N4aPXMp{L z0V@$(@G1ds&j7~>1NI{Xkbu`Pia0i1?RFXY^78T(;7;ES4cHw5XD|8|%m7n>ByiU`w_vTEEdGZOZUXNl9S*|v-d9bQWtBdD?=*z) zx_J3gB7Y^{sQiU&UYOTD+pv~O+#QnEN>;Ug(W&e?4k6qbRe*DDp$GZNCC9AGhUCx~ zGcl?FW6VT%K3p;+#`LsgTVo(M#uy`MtNjR<+H`fA(#0_fSj@@GO=%H@E$?T&QX_=$ zBFdH*A!%09j`#lYsN}#SNjn2)-W^40CTV?`8qYa5Cux1C(ySW@s7cxgAv}>ZQ`T3~ yOx|Y$sEt&dc1L@8F6k4nDQP1o+ss>XdHx^bv6V))@3aj700009(E6uu28O2CTN1S3XF+_?gRt|d`-8X&b%0t<`_<3j3hT(nGN1E#hz_H}aKJ>M6M z=|T)9B<@Tk^*4qnX+Rbxq%K@o(^#MjL7=#p+xj|v%)Fm_X3Ce`O=mjyeBV9q-Fxmi z#~5W;YkQn?yGRa_90zckyi%#GCV6ZHkjpxbRVtO$!N>zRxdKS#8URj)5TWZfTlr<4V9GoW zygi=zR^xCX^8Rh#Y2$;8+`EHw?oldjbpS2{_zb{N0G8y>B(E!rFq`X~pmE3na6?3f zM@B~OZJcjxY;1#bu8-silK&_PKarLEJ_Q5*2Jlpt`F(8hHh_zv?Pz&yw$^qt@Yx=~ zoO5nlCiN3=&TRtlOJEVEn+8xmstfIUujD14Sdbo)e+0H?Aayby&xa0ae={YIr2t+C zY|~8YeFDk;(5p{!unc))jOp#|UB&P_Qh%BN=M)5Zv8({b7z5y|z>mS%B@>9q76tP8 z4ldX#ZCi532w+G_fIT4u0PwkjZ9~ZkCY1zuBai?;DA+b>j9J`j=9L5(Ela+) zw|5nQIR*RXt+hP{z-|rlejF+*fQZ}&;F^Yg&beKN^^A>*03z~8SpkeOhUE83HV&%1 zVHZXm$B%~)0Kl(GHjW#gkJIvi{Q=0Yr&72K;Iv^qQK=#TfNui`@S2u=B&Q6OQ(AEx zZ!amp?~3-#7}nF%Y61XwvnY8Hc}&wbl2_Xyz)wX5AbF@A0;p$oMdXRROrVsvTFdIYek;qlWbr1 zd0h1<+#tXW0RNJFwTavB0dToZ3nHa__dyYPmx1pr7cWG-03oi#t^)W{ zL|z&m9=^NP%dQAme?fj4!Yh_siIuq&^=@7n8ynl8K{^eiqoel&cpt!(qINGUye#5k z04^3udxe6vc59Iw;<9UTV~Qn4037H5?YAJ} zLwah=nB2+HVx=bv5RoG}yf!^KYD~WLcqgCzM#OQvJ*(HYtS`<|AOYadHgU^}t}F|e zxvn@viOg|jLb*Zmc#B2LRw83ey%?HJBC;~qTv`y3x0(o$uSm+6=4Eouxg9z*io-d# zqsf95%Tn_eg_2PeZ47LGX+%-9QDe7SRw@f%E|k%s(U?R9@QEo~Ii6B1eJ+f-;gRfD z3RNs^j9FGLe=5k2DgeOO3o9Rtd;*IN69A%WwYnzs1VvG;R@adHIPuJfZJ0m*Mmz{Hc&bdAj+3){0MDhfH^NIhvJ({O)g_Yhu Z{~v4^^jeaAza0Po002ovPDHLkV1j9wrOE&R literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/TabBar/tab-bar-settings.imageset/Contents.json b/Antidote/Images.xcassets/TabBar/tab-bar-settings.imageset/Contents.json new file mode 100644 index 0000000..7b550bd --- /dev/null +++ b/Antidote/Images.xcassets/TabBar/tab-bar-settings.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "tab-bar-settings.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "tab-bar-settings@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Antidote/Images.xcassets/TabBar/tab-bar-settings.imageset/tab-bar-settings.png b/Antidote/Images.xcassets/TabBar/tab-bar-settings.imageset/tab-bar-settings.png new file mode 100644 index 0000000000000000000000000000000000000000..6e21c0147cd7ce26b446231f66a67efc7486b96b GIT binary patch literal 782 zcmV+p1M&QcP)P000>X1^@s6#OZ}&00004b3#c}2nYxW zdPZZ++qt#+&3ZS&Xe zW_PQ#wl+g$q|g9DQ&34EQ7R=Qpp3}hDvc7xBn(OfLm-JSG(ka{UR6iEUhsXNTW{|@ z&w1`W_dMsGE6Xy~ewdE4m=g9ZT*Ay(cpng;7Edt|cQ7A!!+wzG)~Ir1S=NUOxEUFJ zjmfwbxRg@EOLCrV=c@@a zA!^VP_CBn{KrF`Lz{dq|+=tw%Eiu22rkD>zDdro{R@LpoMBK&rusg68O_5P&;Qs}0 zUJBr~ky5J1Y74^V?ous!syMJGmLG`3+Xen!u09go2%p$%7Y9KHB0 z{JZ0HSFsv98vkjyg&F8WLovvAK^%fcH0MdVOn;C0#>i%T9B6h<;v;B%@RHm1%?%{KX3*8%e|2`0CaK$xwi}pX_88U3GWYgmJ0zaGnvsLAAJOBUy M07*qoM6N<$f|4#v;s5{u literal 0 HcmV?d00001 diff --git a/Antidote/Images.xcassets/TabBar/tab-bar-settings.imageset/tab-bar-settings@2x.png b/Antidote/Images.xcassets/TabBar/tab-bar-settings.imageset/tab-bar-settings@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..c7d65cd758e5b02c7e98e0ff80d43d46cff62c30 GIT binary patch literal 1835 zcmV+`2h{k9P)U!wl5cGIe)Pz?|7TJA1FY zeeU<^z%X~_JnsDG&YW}RTvU~_Re|oni@bLpc+^Jl%H1DSp-oD)B|d@9;gWD zLjszwRp%5Cpd)b7CiemGzCC{j6amG+RvUW-c-Nlm&M6=UW`|9#H*f*4$NIIvK6~B< zoELnZjam9SaQ4bNYX_=o9WW6%jypHqfTO@fRXqjtGu{nZ%8K(i(Pl+NN>ue^Fm%+~ zJ^-q^LPV|tx&RHpAp;0dZf%pih!g`?s%kB!pb*>WDc}UK6Sv>zlN{g?ZIFKeXf*z} zfmJ}A_1`GS838T@{-vb_QsD6v{!*ZG%J_r;jM{U(wbvE`$dmTsPk;(wGVmHOD&iXp z{1i-fr}0X_b1(1$Fao&P^f=2_03fUEWgh~aGI-tzR{A*bPtachbV!l8BGCO+A%Ki0 zaeTXhVG(__(dvMQaOSqyR{fCCrbII1fFnjb0u0YP5PNY2uqjya%L3ZhHa;muZiLZx z1Y_NRQ^9uardmLUi1XOL*aRwUOn_rH)+I%zLre#5wEnh`w_pxYRU2?7*n{#wBzTUC z4_6fT6~OrzfD1*Wvu7*_5D~dnMAqP(Up;UTKvf%o&Bit^MRYVSF00nWIqm}vXRQ<$FtwB=I8$fRPb>ILXlu1R2zY@s@lXSB9la9rHIS{Mge6;`Z(8BemPn}Un^61OGzwGT%Swf7oaF*d|HN% zM&O!Ufq0KP!un&Zzbu1)3hoT-0^Y-2Z@n*gtc~YPaTaSDPzihi>;=0qtvkQ1TdNaLV}i4C zv1q3O=$+Sg>|SD9<_Vk?oSY&v82AX74s<=O{uJR`Z7Vep9P%>+G060t0{XS*0%ZcR z7tgTOTb@BL0*2X2EwOeODUQtez2BLU4-l%FnGU+x+S-^PB0X`3vww=*1`!#rsx{I0 zAJ*nC{gkqLU2*YFlfw&WJxS6q`*9BQ5o`C8Tv>ZYas!NZ5V$BWTgxUl8)s#FsbqT@MYp8 z!!5w~xQHNpUu}B<@d}3n-2us9oNj#cT2VNUAoNI~7X#OkBo?$?54);CN=T@44h{zaVD^Q~@10I(h)|RKx!s6*W(ug8bf;*SJ{@+wv zFaAG;uP1pUH6n65a1YQA zD6_4y5m>D*qZpU2))q8G8H(G-4Zz@bI*3C8orChewSdlm|GU~EwR47Gd;(!NDG81C z2I9T)1}w2)<9Fb0h_4e}aZ@JT7k86fN%I?DvFTM{ZlQqG;?742E(hiB%f7AydPlOo zad-KUuMrm*cBJ{8{j_0DdjJWuD77Sa>{GTi=8 InterfaceIdiom { + if UIDevice.current.userInterfaceIdiom == UIUserInterfaceIdiom.pad { + return .iPad + } + else { + // assume that we are on iPhone + return .iPhone + } + } +} + diff --git a/Antidote/KeyboardNotificationController.swift b/Antidote/KeyboardNotificationController.swift new file mode 100644 index 0000000..8997447 --- /dev/null +++ b/Antidote/KeyboardNotificationController.swift @@ -0,0 +1,70 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit + +class KeyboardNotificationController: UIViewController { + init() { + super.init(nibName: nil, bundle: nil) + + let center = NotificationCenter.default + center.addObserver(self, selector: #selector(KeyboardNotificationController.keyboardWillShowNotification(_:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil) + center.addObserver(self, selector: #selector(KeyboardNotificationController.keyboardWillHideNotification(_:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil) + } + + required convenience init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + deinit { + let center = NotificationCenter.default + center.removeObserver(self) + } + + func keyboardWillShowAnimated(keyboardFrame frame: CGRect) { + // nop + } + + func keyboardWillHideAnimated(keyboardFrame frame: CGRect) { + // nop + } + + @objc func keyboardWillShowNotification(_ notification: Notification) { + handleNotification(notification, willShow: true) + } + + @objc func keyboardWillHideNotification(_ notification: Notification) { + handleNotification(notification, willShow: false) + } +} + +private extension KeyboardNotificationController { + func handleNotification(_ notification: Notification, willShow: Bool) { + let userInfo = notification.userInfo! + + let frame = (userInfo[UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue + let duration = (userInfo[UIKeyboardAnimationDurationUserInfoKey] as! NSNumber).doubleValue + let curve = UIViewAnimationCurve(rawValue: (userInfo[UIKeyboardAnimationCurveUserInfoKey] as! NSNumber).intValue)! + + let options: UIViewAnimationOptions + + switch curve { + case .easeInOut: + options = UIViewAnimationOptions() + case .easeIn: + options = .curveEaseIn + case .easeOut: + options = .curveEaseOut + case .linear: + options = .curveLinear + default: + options = .curveLinear + + } + + UIView.animate(withDuration: duration, delay: 0.0, options: options, animations: { [unowned self] in + willShow ? self.keyboardWillShowAnimated(keyboardFrame: frame) : self.keyboardWillHideAnimated(keyboardFrame: frame) + }, completion: nil) + } +} diff --git a/Antidote/KeyboardObserver.swift b/Antidote/KeyboardObserver.swift new file mode 100644 index 0000000..eba027d --- /dev/null +++ b/Antidote/KeyboardObserver.swift @@ -0,0 +1,36 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// +// KeyboardObserver.swift +// Antidote +// +// Created by Dmytro Vorobiov on 25/11/16. +// Copyright © 2016 dvor. All rights reserved. +// + +import Foundation + +class KeyboardObserver { + private(set) var keyboardVisible = false + + init() { + let center = NotificationCenter.default + center.addObserver(self, selector: #selector(KeyboardObserver.keyboardWillShowNotification(_:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil) + center.addObserver(self, selector: #selector(KeyboardObserver.keyboardWillHideNotification(_:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil) + } + + deinit { + let center = NotificationCenter.default + center.removeObserver(self) + } + + @objc func keyboardWillShowNotification(_ notification: Notification) { + keyboardVisible = true + } + + @objc func keyboardWillHideNotification(_ notification: Notification) { + keyboardVisible = false + } +} diff --git a/Antidote/KeychainManager.swift b/Antidote/KeychainManager.swift new file mode 100644 index 0000000..677ef3c --- /dev/null +++ b/Antidote/KeychainManager.swift @@ -0,0 +1,182 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +private struct Constants { + static let ActiveAccountDataService = "org.zoxcore.Antidote.KeychainManager.ActiveAccountDataService" + + static let toxPasswordForActiveAccount = "toxPasswordForActiveAccount" + static let failedPinAttemptsNumber = "failedPinAttemptsNumber" +} + +class KeychainManager { + /// Tox password used to encrypt/decrypt active account. + var toxPasswordForActiveAccount: String? { + get { + return getStringForKey(Constants.toxPasswordForActiveAccount) + } + set { + setString(newValue, forKey: Constants.toxPasswordForActiveAccount) + } + } + + /// Number of failed enters of pin by user. + var failedPinAttemptsNumber: Int? { + get { + return getIntForKey(Constants.failedPinAttemptsNumber) + } + set { + setInt(newValue, forKey: Constants.failedPinAttemptsNumber) + } + } + + /// Removes all data related to active account. + func deleteActiveAccountData() { + toxPasswordForActiveAccount = nil + failedPinAttemptsNumber = nil + } +} + +private extension KeychainManager { + func getIntForKey(_ key: String) -> Int? { + guard let data = getDataForKey(key) else { + return nil + } + + guard let number = NSKeyedUnarchiver.unarchiveObject(with: data) as? NSNumber else { + return nil + } + + return number.intValue + } + + func setInt(_ value: Int?, forKey key: String) { + guard let value = value else { + setData(nil, forKey: key) + return + } + + let number = NSNumber(value: value) + + let data = NSKeyedArchiver.archivedData(withRootObject: number) + setData(data, forKey: key) + } + + func getStringForKey(_ key: String) -> String? { + guard let data = getDataForKey(key) else { + return nil + } + + return NSString(data: data, encoding: String.Encoding.utf8.rawValue) as String? + } + + func setString(_ string: String?, forKey key: String) { + let data = string?.data(using: String.Encoding.utf8) + setData(data, forKey: key) + } + + func getBoolForKey(_ key: String) -> Bool? { + guard let data = getDataForKey(key) else { + return nil + } + + return (data as NSData).bytes.bindMemory(to: Int.self, capacity: data.count).pointee == 1 + } + + func setBool(_ value: Bool?, forKey key: String) { + var data: Data? = nil + + if let value = value { + var bytes = value ? 1 : 0 + withUnsafePointer(to: &bytes) { + $0.withMemoryRebound(to: sockaddr.self, capacity: 1) { + data = Data(bytes: $0, count: MemoryLayout.size) + } + } + } + + setData(data, forKey: key) + } + + func getDataForKey(_ key: String) -> Data? { + var query = genericQueryWithKey(key) + query[kSecMatchLimit as String] = kSecMatchLimitOne + query[kSecReturnData as String] = kCFBooleanTrue + + var queryResult: AnyObject? + let status = withUnsafeMutablePointer(to: &queryResult) { + SecItemCopyMatching(query as CFDictionary, UnsafeMutablePointer($0)) + } + + if status == errSecItemNotFound { + return nil + } + + guard status == noErr else { + log("Error when getting keychain data for key \(key), status \(status)") + return nil + } + + guard let data = queryResult as? Data else { + log("Unexpected data for key \(key)") + return nil + } + + return data + } + + func setData(_ newData: Data?, forKey key: String) { + let oldData = getDataForKey(key) + + switch (oldData, newData) { + case (.some(_), .some(let data)): + // Update + let query = genericQueryWithKey(key) + + var attributesToUpdate = [String : AnyObject]() + attributesToUpdate[kSecValueData as String] = data as AnyObject? + + let status = SecItemUpdate(query as CFDictionary, attributesToUpdate as CFDictionary) + guard status == noErr else { + log("Error when updating keychain data for key \(key), status \(status)") + return + } + + case (.some(_), .none): + // Delete + let query = genericQueryWithKey(key) + let status = SecItemDelete(query as CFDictionary) + guard status == noErr else { + log("Error when updating keychain data for key \(key), status \(status)") + return + } + + case (.none, .some(let data)): + // Add + var query = genericQueryWithKey(key) + query[kSecValueData as String] = data as AnyObject? + + let status = SecItemAdd(query as CFDictionary, nil) + guard status == noErr else { + log("Error when setting keychain data for key \(key), status \(status)") + return + } + + case (.none, .none): + // Nothing to do here, no changes + break + } + } + + func genericQueryWithKey(_ key: String) -> [String : AnyObject] { + var query = [String : AnyObject]() + query[kSecClass as String] = kSecClassGenericPassword + query[kSecAttrService as String] = Constants.ActiveAccountDataService as AnyObject? + query[kSecAttrAccount as String] = key as AnyObject? + query[kSecAttrAccessible as String] = kSecAttrAccessibleAfterFirstUnlock + + return query + } +} diff --git a/Antidote/Launch Screen.storyboard b/Antidote/Launch Screen.storyboard new file mode 100644 index 0000000..34872e2 --- /dev/null +++ b/Antidote/Launch Screen.storyboard @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Antidote/LaunchPlaceholderBoard.storyboard b/Antidote/LaunchPlaceholderBoard.storyboard new file mode 100644 index 0000000..37e54bb --- /dev/null +++ b/Antidote/LaunchPlaceholderBoard.storyboard @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Antidote/LaunchPlaceholderController.swift b/Antidote/LaunchPlaceholderController.swift new file mode 100644 index 0000000..7c52a66 --- /dev/null +++ b/Antidote/LaunchPlaceholderController.swift @@ -0,0 +1,8 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit + +class LaunchPlaceholderController: UIViewController { +} diff --git a/Antidote/LinearProgressBar.swift b/Antidote/LinearProgressBar.swift new file mode 100644 index 0000000..c0add79 --- /dev/null +++ b/Antidote/LinearProgressBar.swift @@ -0,0 +1,163 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// +// LinearProgressBar.swift +// CookMinute +// +// Created by Philippe Boisney on 18/11/2015. +// Copyright © 2015 CookMinute. All rights reserved. +// +// Google Guidelines: https://www.google.com/design/spec/components/progress-activity.html#progress-activity-types-of-indicators +// + +import UIKit + +open class LinearProgressBar: UIView { + + //FOR DATA + fileprivate var screenSize: CGRect = UIScreen.main.bounds + fileprivate var isAnimationRunning = false + + //FOR DESIGN + fileprivate var progressBarIndicator: UIView! + + //PUBLIC VARS + open var backgroundProgressBarColor: UIColor = UIColor(red:0.73, green:0.87, blue:0.98, alpha:1.0) + open var progressBarColor: UIColor = UIColor(red:0.12, green:0.53, blue:0.90, alpha:1.0) + open var heightForLinearBar: CGFloat = 5 + open var widthForLinearBar: CGFloat = 0 + + public init () { + super.init(frame: CGRect(origin: CGPoint(x: 0,y :20), size: CGSize(width: screenSize.width, height: 0))) + self.progressBarIndicator = UIView(frame: CGRect(origin: CGPoint(x: 0,y :0), size: CGSize(width: 0, height: heightForLinearBar))) + } + + override public init(frame: CGRect) { + super.init(frame: frame) + self.progressBarIndicator = UIView(frame: CGRect(origin: CGPoint(x: 0,y :0), size: CGSize(width: 0, height: heightForLinearBar))) + } + + required public init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + //MARK: LIFE OF VIEW + override open func layoutSubviews() { + super.layoutSubviews() + self.screenSize = UIScreen.main.bounds + + if widthForLinearBar == 0 || widthForLinearBar == self.screenSize.height { + widthForLinearBar = self.screenSize.width + } + + if (UIDeviceOrientationIsLandscape(UIDevice.current.orientation)) { + self.frame = CGRect(origin: CGPoint(x: self.frame.origin.x,y :self.frame.origin.y), size: CGSize(width: widthForLinearBar, height: self.frame.height)) + } + + if (UIDeviceOrientationIsPortrait(UIDevice.current.orientation)) { + self.frame = CGRect(origin: CGPoint(x: self.frame.origin.x,y :self.frame.origin.y), size: CGSize(width: widthForLinearBar, height: self.frame.height)) + } + } + + //MARK: PUBLIC FUNCTIONS ------------------------------------------------------------------------------------------ + + //Start the animation + open func startAnimation(viewToAddto: UIView, viewToAlignToBottomOf: UIView, bottom_margin: Int ){ + + self.configureColors() + + self.show(viewToAddto: viewToAddto, viewToAlignToBottomOf: viewToAlignToBottomOf, bottom_margin: bottom_margin) + + if !isAnimationRunning { + self.isAnimationRunning = true + + UIView.animate(withDuration: 0.5, delay:0, options: [], animations: { + self.frame = CGRect(x: 0, y: self.frame.origin.y, width: self.widthForLinearBar, height: self.heightForLinearBar) + }, completion: { animationFinished in + self.addSubview(self.progressBarIndicator) + self.configureAnimation() + }) + } + } + + //Start the animation + open func stopAnimation() { + + self.isAnimationRunning = false + + UIView.animate(withDuration: 0.5, animations: { + self.progressBarIndicator.frame = CGRect(x: 0, y: 0, width: self.widthForLinearBar, height: 0) + self.frame = CGRect(x: 0, y: self.frame.origin.y, width: self.widthForLinearBar, height: 0) + }) + } + + //MARK: PRIVATE FUNCTIONS ------------------------------------------------------------------------------------------ + + fileprivate func show(viewToAddto: UIView, viewToAlignToBottomOf: UIView, bottom_margin: Int ) { + + // Only show once + if self.superview != nil { + return + } + + // Find current top viewcontroller + if let topController = getTopViewController() { + // let superView: UIView = topController.view + viewToAddto.addSubview(self) + + // update: show progressbar in the vertical center of the screen + self.snp.makeConstraints { make in + make.leading.trailing.equalToSuperview() + make.top.equalTo(viewToAlignToBottomOf.snp.bottom).offset(bottom_margin) + } + } + } + + fileprivate func configureColors(){ + + self.backgroundColor = self.backgroundProgressBarColor + self.progressBarIndicator.backgroundColor = self.progressBarColor + self.layoutIfNeeded() + } + + fileprivate func configureAnimation() { + + guard let superview = self.superview else { + stopAnimation() + return + } + + self.progressBarIndicator.frame = CGRect(origin: CGPoint(x: 0, y :0), size: CGSize(width: 0, height: heightForLinearBar)) + + UIView.animateKeyframes(withDuration: 1.0, delay: 0, options: [], animations: { + + UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.5, animations: { + self.progressBarIndicator.frame = CGRect(x: 0, y: 0, width: self.widthForLinearBar*0.7, height: self.heightForLinearBar) + }) + + UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: 0.5, animations: { + self.progressBarIndicator.frame = CGRect(x: superview.frame.width, y: 0, width: 0, height: self.heightForLinearBar) + + }) + + }) { (completed) in + if (self.isAnimationRunning){ + self.configureAnimation() + } + } + } + + // ----------------------------------------------------- + //MARK: UTILS --------------------------------------- + // ----------------------------------------------------- + + fileprivate func getTopViewController() -> UIViewController? { + var topController: UIViewController? = UIApplication.shared.keyWindow?.rootViewController + while topController?.presentedViewController != nil { + topController = topController?.presentedViewController + } + return topController + } +} diff --git a/Antidote/LoadingImageView.swift b/Antidote/LoadingImageView.swift new file mode 100644 index 0000000..0e05276 --- /dev/null +++ b/Antidote/LoadingImageView.swift @@ -0,0 +1,199 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation +import MobileCoreServices + +class LoadingImageView: UIView { + struct Constants { + static let ImageButtonSize: CGFloat = 180.0 + static let LabelHorizontalOffset = 12.0 + static let LabelBottomOffset = -6.0 + static let CenterImageSize = 50.0 + static let ProgressViewSize = 70.0 + } + + var imageButton: UIButton! + var progressView: ProgressCircleView! + var centerImageView: UIImageView! + var topLabel: UILabel! + var bottomLabel: UILabel! + + var pressedHandle: (() -> Void)? + + override init(frame: CGRect) { + super.init(frame: frame) + + backgroundColor = .clear + createViews() + installConstraints() + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func setCancelledImage() { + centerImageView.image = UIImage.templateNamed("chat-file-type-canceled") + } + + func setImageWithUti(_ uti: String?, fileExtension: String?) { + let imageName = imageNameWithUti(uti, fileExtension: fileExtension) + centerImageView.image = UIImage.templateNamed(imageName) + } +} + +extension LoadingImageView { + @objc func imageButtonPressed() { + pressedHandle?() + } +} + +private extension LoadingImageView { + func createViews() { + imageButton = UIButton() + imageButton.layer.cornerRadius = 12.0 + imageButton.clipsToBounds = true + imageButton.addTarget(self, action: #selector(LoadingImageView.imageButtonPressed), for: .touchUpInside) + addSubview(imageButton) + + centerImageView = UIImageView() + centerImageView.contentMode = .center + addSubview(centerImageView) + + progressView = ProgressCircleView() + progressView.isUserInteractionEnabled = false + addSubview(progressView) + + topLabel = UILabel() + topLabel.font = UIFont.systemFont(ofSize: 14.0) + addSubview(topLabel) + + bottomLabel = UILabel() + bottomLabel.font = UIFont.systemFont(ofSize: 14.0) + addSubview(bottomLabel) + } + + func installConstraints() { + snp.makeConstraints { + $0.size.equalTo(Constants.ImageButtonSize) + } + + imageButton.snp.makeConstraints { + $0.edges.equalTo(self) + } + + centerImageView.snp.makeConstraints { + $0.center.equalTo(self) + $0.size.equalTo(Constants.CenterImageSize) + } + + progressView.snp.makeConstraints { + $0.center.equalTo(self) + $0.size.equalTo(Constants.ProgressViewSize) + } + + topLabel.snp.makeConstraints { + $0.leading.equalTo(self).offset(Constants.LabelHorizontalOffset) + $0.trailing.lessThanOrEqualTo(self).offset(-Constants.LabelHorizontalOffset) + $0.bottom.equalTo(bottomLabel.snp.top) + } + + bottomLabel.snp.makeConstraints { + $0.leading.equalTo(self).offset(Constants.LabelHorizontalOffset) + $0.trailing.lessThanOrEqualTo(self).offset(-Constants.LabelHorizontalOffset) + $0.bottom.equalTo(self).offset(Constants.LabelBottomOffset) + } + } + + func imageNameWithUti(_ uti: String?, fileExtension: String?) -> String { + guard let uti = uti else { + return "chat-file-type-basic" + } + + if UTTypeEqual(uti as CFString, kUTTypeGIF) { + return "chat-file-type-gif" + } + else if UTTypeEqual(uti as CFString, kUTTypeHTML) { + return "chat-file-type-html" + } + else if UTTypeEqual(uti as CFString, kUTTypeJPEG) { + return "chat-file-type-jpg" + } + else if UTTypeEqual(uti as CFString, kUTTypeMP3) { + return "chat-file-type-mp3" + } + else if UTTypeEqual(uti as CFString, kUTTypeMPEG) { + return "chat-file-type-mpg" + } + else if UTTypeEqual(uti as CFString, kUTTypeMPEG4) { + return "chat-file-type-mpg" + } + else if UTTypeEqual(uti as CFString, kUTTypePDF) { + return "chat-file-type-pdf" + } + else if UTTypeEqual(uti as CFString, kUTTypePNG) { + return "chat-file-type-png" + } + else if UTTypeEqual(uti as CFString, kUTTypeTIFF) { + return "chat-file-type-tif" + } + else if UTTypeEqual(uti as CFString, kUTTypePlainText) { + return "chat-file-type-txt" + } + + guard let fileExtension = fileExtension else { + return "chat-file-type-basic" + } + + switch fileExtension { + case "7z": + return "chat-file-type-7zip" + case "aac": + return "chat-file-type-aac" + case "avi": + return "chat-file-type-avi" + case "css": + return "chat-file-type-css" + case "csv": + return "chat-file-type-csv" + case "doc": + return "chat-file-type-doc" + case "ebup": + return "chat-file-type-ebup" + case "exe": + return "chat-file-type-exe" + case "fb2": + return "chat-file-type-fb2" + case "flv": + return "chat-file-type-flv" + case "mov": + return "chat-file-type-mov" + case "ogg": + return "chat-file-type-ogg" + case "otf": + return "chat-file-type-otf" + case "ppt": + return "chat-file-type-ppt" + case "psd": + return "chat-file-type-psd" + case "rar": + return "chat-file-type-rar" + case "tar": + return "chat-file-type-tar" + case "ttf": + return "chat-file-type-ttf" + case "wav": + return "chat-file-type-wav" + case "wma": + return "chat-file-type-wma" + case "xls": + return "chat-file-type-xls" + case "zip": + return "chat-file-type-zip" + default: + return "chat-file-type-basic" + } + } +} diff --git a/Antidote/LocationManager.swift b/Antidote/LocationManager.swift new file mode 100644 index 0000000..722d3fa --- /dev/null +++ b/Antidote/LocationManager.swift @@ -0,0 +1,193 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// +// LocationManager.swift +// CLBackgroundAccess +// +// Created by Samer Murad on 10.04.21. +// + +import Foundation +import CoreLocation +import UIKit + +// MARK: Declarations +class LocationManager: NSObject { + /// Alias to CLAuthorizationStatus, makes accessable throughout the project + /// without importing the CoreLocation kit. + typealias LocationAuthStatus = CLAuthorizationStatus + enum State { + case Idle, Monitoring + } + + /// Singleton Object + static let shared = LocationManager() + + private var _state: State = .Idle { + didSet { + /// Disptach State Change event + Bus.shared.post(event: .LocationManagerStateChange, userInfo: ["state": _state ]) + } + } + public var state: State { + get { return _state } + } + private var manager: CLLocationManager! + + private override init() { + super.init() + self.setup() + } + + // cleanup + deinit { + self.teardown() + print("Location Manager Killed") + } +} + +// MARK: - Life Cycle Setup +private extension LocationManager { + func setup() { + manager = CLLocationManager() + if #available(iOS 14.0, *) { + manager.desiredAccuracy = kCLLocationAccuracyReduced + } else { + // Fallback on earlier versions + manager.desiredAccuracy = kCLLocationAccuracyBest + } + manager?.delegate = self + manager?.allowsBackgroundLocationUpdates = true + manager?.pausesLocationUpdatesAutomatically = false + manager?.distanceFilter = kCLDistanceFilterNone + } + + func teardown() { + self.stopMonitoring() + self.manager.delegate = nil + self.manager = nil + } +} +// MARK: - Main BL +extension LocationManager { + + func isHasAccess() -> Bool { + var isHas = true + if #available(iOS 14.0, *) { + if let authStatus = self.manager?.authorizationStatus { + if authStatus == .notDetermined || authStatus == .denied || authStatus == .restricted { + isHas = false + } + return isHas + } + } else { + // Fallback on earlier versions + } + return false + } + + func requestAccess() { + // manager?.requestAlwaysAuthorization() + manager?.requestWhenInUseAuthorization() + } + + func startMonitoring() { + guard self.isHasAccess() else { + print("WARN: App Doesnt have access to CoreLocation, please call LocationManager.shared.isHasAccess() first") + return + } + guard self.state == .Idle else { + print("WARN: LocationManager already running") + return + } + + // sned to global queue + DispatchQueue.global().async { + // Guard has location services + guard CLLocationManager.locationServicesEnabled() else { + DispatchQueue.main.async { + AppDelegate + .shared + .alert("Error", "Location Services Must be enbaled, got to Settings -> Privacy -> Location Services to enable") + } + return + } + self._state = .Monitoring + self.manager?.startUpdatingLocation() + /// Optional: + /// Only work if app has .authorizedAlways access, + /// shows the blue indicator in the status bar, + /// if app has .authorizedWhenInUse, the blue indicator on by default + /// so we manually turn it on in any case to inform + /// the user that we are working in the background + self.manager.showsBackgroundLocationIndicator = true + } + } + + func stopMonitoring() { + guard self.state != .Idle else { + print("WARN: LocationManager already stopped") + return + } + self.manager?.stopUpdatingLocation() + self._state = .Idle + /// turn off blue indicator + self.manager.showsBackgroundLocationIndicator = false + } +} + +// MARK: - CLLocationManagerDelegate +extension LocationManager: CLLocationManagerDelegate { + func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) { + if #available(iOS 14.0, *) { + print("locationManagerDidChangeAuthorization" , manager.authorizationStatus) + } else { + // Fallback on earlier versions + } + if #available(iOS 14.0, *) { + Bus.shared.post(event: .LocationAuthUpdate, userInfo: ["status": manager.authorizationStatus, "state": self.state]) + } else { + // Fallback on earlier versions + } + } + + + func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { + Bus.shared.post(event: .LocationUpdate, userInfo: ["locations": locations, "state": self.state]) + } + + func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) { + if let clError = error as? CLError { + switch clError.code { + case CLError.Code.denied: + + fallthrough + default: + print("locationManager: didFailWithError", clError) + } + // reset state + self._state = .Idle + } + } +} + + +// MARK: CLAutorizationStatus pretty print +extension LocationManager.LocationAuthStatus: CustomStringConvertible { + public var description: String { + get { + switch self { + case .notDetermined: return "NotDetermined" + case .denied: return "Denied" + case .restricted: return "Restricted" + case .authorizedAlways: return "AuthorizedAlways" + case .authorizedWhenInUse: return "AuthorizedWhenInUse" + default: return "CLAuthorizationStatus" + } + } + } + +} + diff --git a/Antidote/Logger.swift b/Antidote/Logger.swift new file mode 100644 index 0000000..c8a1c59 --- /dev/null +++ b/Antidote/Logger.swift @@ -0,0 +1,10 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +func log (_ string: String, filename: NSString = #file) { + NSLog("\(filename.lastPathComponent): \(string)") +} + diff --git a/Antidote/LoginBaseController.swift b/Antidote/LoginBaseController.swift new file mode 100644 index 0000000..f398c46 --- /dev/null +++ b/Antidote/LoginBaseController.swift @@ -0,0 +1,63 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit +import SnapKit + +class LoginBaseController: KeyboardNotificationController { + struct Constants { + static let HorizontalOffset = 40.0 + static let VerticalOffset = 40.0 + static let SmallVerticalOffset = 8.0 + + static let TextFieldHeight: CGFloat = 40.0 + + static let MaxFormWidth = 350.0 + + static let GradientHeightPercentage: CGFloat = 0.4 + } + + let theme: Theme + + fileprivate var gradientLayer: CAGradientLayer! + + init(theme: Theme) { + self.theme = theme + + super.init() + + edgesForExtendedLayout = UIRectEdge() + } + + required convenience init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func loadView() { + loadViewWithBackgroundColor(theme.colorForType(.LoginBackground)) + + createGradientLayer() + } + + override var prefersStatusBarHidden : Bool { + return true + } + + override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + + gradientLayer.frame.size.width = view.frame.size.width + gradientLayer.frame.size.height = view.frame.size.height * Constants.GradientHeightPercentage + gradientLayer.frame.origin.x = 0 + gradientLayer.frame.origin.y = view.frame.size.height - gradientLayer.frame.size.height + } +} + +private extension LoginBaseController { + func createGradientLayer() { + gradientLayer = CAGradientLayer() + gradientLayer.colors = [theme.colorForType(.LoginBackground).cgColor, theme.colorForType(.LoginGradient).cgColor] + view.layer.insertSublayer(gradientLayer, at: 0) + } +} diff --git a/Antidote/LoginChoiceController.swift b/Antidote/LoginChoiceController.swift new file mode 100644 index 0000000..f4896a7 --- /dev/null +++ b/Antidote/LoginChoiceController.swift @@ -0,0 +1,95 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit +import SnapKit + +protocol LoginChoiceControllerDelegate: class { + func loginChoiceControllerCreateAccount(_ controller: LoginChoiceController) + func loginChoiceControllerImportProfile(_ controller: LoginChoiceController) +} + +class LoginChoiceController: LoginLogoController { + weak var delegate: LoginChoiceControllerDelegate? + + fileprivate var incompressibleContainer: IncompressibleView! + fileprivate var createAccountButton: RoundedButton! + fileprivate var importProfileButton: RoundedButton! + + override func loadView() { + super.loadView() + + createContainer() + createButtons() + + installConstraints() + } +} + +// MARK: Actions +extension LoginChoiceController { + @objc func createAccountButtonPressed() { + delegate?.loginChoiceControllerCreateAccount(self) + } + + @objc func importProfileButtonPressed() { + delegate?.loginChoiceControllerImportProfile(self) + } +} + +private extension LoginChoiceController { + func createContainer() { + incompressibleContainer = IncompressibleView() + incompressibleContainer.backgroundColor = .clear + contentContainerView.addSubview(incompressibleContainer) + } + + func createButtons() { + createAccountButton = createButtonWithTitle(String(localized:"create_account"), action: #selector(LoginChoiceController.createAccountButtonPressed)) + importProfileButton = createButtonWithTitle(String(localized:"import_profile"), action: #selector(LoginChoiceController.importProfileButtonPressed)) + } + + func installConstraints() { + incompressibleContainer.customIntrinsicContentSize.width = CGFloat(Constants.MaxFormWidth) + incompressibleContainer.snp.makeConstraints { + $0.top.equalTo(contentContainerView) + $0.centerX.equalTo(contentContainerView) + $0.width.lessThanOrEqualTo(Constants.MaxFormWidth) + $0.width.lessThanOrEqualTo(contentContainerView).offset(-2 * Constants.HorizontalOffset) + $0.height.equalTo(contentContainerView) + } + + createAccountButton.snp.makeConstraints { + $0.top.equalTo(incompressibleContainer).offset(Constants.VerticalOffset) + $0.leading.trailing.equalTo(incompressibleContainer) + } + + importProfileButton.snp.makeConstraints { + $0.top.equalTo(createAccountButton.snp.bottom).offset(Constants.VerticalOffset) + $0.leading.trailing.equalTo(incompressibleContainer) + } + } + + func createLabelWithText(_ text: String) -> UILabel { + let label = UILabel() + label.text = text + label.textColor = theme.colorForType(.LoginDescriptionLabel) + label.textAlignment = .center + label.backgroundColor = .clear + + incompressibleContainer.addSubview(label) + + return label + } + + func createButtonWithTitle(_ title: String, action: Selector) -> RoundedButton { + let button = RoundedButton(theme: theme, type: .login) + button.setTitle(title, for: UIControlState()) + button.addTarget(self, action: action, for: .touchUpInside) + + incompressibleContainer.addSubview(button) + + return button + } +} diff --git a/Antidote/LoginCoordinator.swift b/Antidote/LoginCoordinator.swift new file mode 100644 index 0000000..a37c072 --- /dev/null +++ b/Antidote/LoginCoordinator.swift @@ -0,0 +1,313 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit + +protocol LoginCoordinatorDelegate: class { + func loginCoordinatorDidLogin(_ coordinator: LoginCoordinator, manager: OCTManager, password: String) +} + +private enum UserInfoKey: String { + case ImportURL + case LoginProfile + case LoginConfigurationClosure + case LoginErrorClosure +} + +class LoginCoordinator { + weak var delegate: LoginCoordinatorDelegate? + + fileprivate let window: UIWindow + fileprivate let theme: Theme + fileprivate let navigationController: UINavigationController + + fileprivate var createAccountCoordinator: LoginCreateAccountCoordinator? + + init(theme: Theme, window: UIWindow) { + self.window = window + self.theme = theme + + switch InterfaceIdiom.current() { + case .iPhone: + self.navigationController = PortraitNavigationController() + case .iPad: + self.navigationController = UINavigationController() + } + + navigationController.navigationBar.tintColor = theme.colorForType(.LoginButtonBackground) + navigationController.navigationBar.titleTextAttributes = [ + NSAttributedStringKey.foregroundColor: theme.colorForType(.LoginButtonText) + ] + } +} + +// MARK: TopCoordinatorProtocol +extension LoginCoordinator: TopCoordinatorProtocol { + func startWithOptions(_ options: CoordinatorOptions?) { + let profileNames = ProfileManager().allProfileNames + + let controller: UIViewController = (profileNames.count > 0) ? createFormController() : createChoiceController() + + navigationController.pushViewController(controller, animated: false) + window.rootViewController = navigationController + } + + func handleLocalNotification(_ notification: UILocalNotification) { + // nop + } + + func handleInboxURL(_ url: URL) { + guard url.isToxURL() else { + return + } + + let fileName = url.lastPathComponent + let style: UIAlertControllerStyle + + switch InterfaceIdiom.current() { + case .iPhone: + style = .actionSheet + case .iPad: + style = .alert + } + + let alert = UIAlertController(title: nil, message: fileName, preferredStyle: style) + + alert.addAction(UIAlertAction(title: String(localized: "create_profile"), style: .default) { [unowned self] _ -> Void in + self.importToxProfileFromURL(url) + }) + + alert.addAction(UIAlertAction(title: String(localized: "alert_cancel"), style: .cancel, handler: nil)) + + navigationController.present(alert, animated: true, completion: nil) + } +} + +extension LoginCoordinator: LoginFormControllerDelegate { + func loginFormControllerLogin(_ controller: LoginFormController, profileName: String, password: String?) { + loginWithProfile(profileName, password: password, errorClosure: { error in + handleErrorWithType(.createOCTManager, error: error) + }) + } + + func loginFormControllerCreateAccount(_ controller: LoginFormController) { + showCreateAccountController() + } + + func loginFormControllerImportProfile(_ controller: LoginFormController) { + showImportProfileController() + } + + func loginFormController(_ controller: LoginFormController, isProfileEncrypted profile: String) -> Bool { + return isProfileEncrypted(profile) + } +} + +extension LoginCoordinator: LoginChoiceControllerDelegate { + func loginChoiceControllerCreateAccount(_ controller: LoginChoiceController) { + showCreateAccountController() + } + + func loginChoiceControllerImportProfile(_ controller: LoginChoiceController) { + showImportProfileController() + } +} + +extension LoginCoordinator: LoginCreateAccountCoordinatorDelegate { + func loginCreateAccountCoordinator(_ coordinator: LoginCreateAccountCoordinator, + didCreateAccountWithProfileName profileName: String, + username: String, + password: String) { + createProfileWithProfileName(profileName, username: username, copyFromURL: nil, password: password) + } + + func loginCreateAccountCoordinator(_ coordinator: LoginCreateAccountCoordinator, + didImportProfileWithProfileName profileName: String) { + guard let url = coordinator.userInfo[UserInfoKey.ImportURL.rawValue] as? URL else { + fatalError("URL should be non-nil when importing profile") + } + + createProfileWithProfileName(profileName, username: nil, copyFromURL: url, password: nil) + } + + func loginCreateAccountCoordinator(_ coordinator: LoginCreateAccountCoordinator, didCreatePassword password: String) { + guard let profile = coordinator.userInfo[UserInfoKey.LoginProfile.rawValue] as? String else { + fatalError("Profile should be non-nil on login") + } + + let configurationClosure = coordinator.userInfo[UserInfoKey.LoginConfigurationClosure.rawValue] as? ((_ manager: OCTManager) -> Void) + let errorClosure = coordinator.userInfo[UserInfoKey.LoginErrorClosure.rawValue] as? ((NSError) -> Void) + + loginWithProfile(profile, password: password, configurationClosure: configurationClosure, errorClosure: errorClosure) + } +} + +private extension LoginCoordinator { + func createFormController() -> LoginFormController { + let profileNames = ProfileManager().allProfileNames + var selectedIndex = 0 + + if let activeProfile = UserDefaultsManager().lastActiveProfile { + selectedIndex = profileNames.index(of: activeProfile) ?? 0 + } + + let controller = LoginFormController(theme: theme, profileNames: profileNames, selectedIndex: selectedIndex) + controller.delegate = self + + return controller + } + + func createChoiceController() -> LoginChoiceController { + let controller = LoginChoiceController(theme: theme) + controller.delegate = self + + return controller + } + + func showCreateAccountController() { + let coordinator = LoginCreateAccountCoordinator(theme: theme, + navigationController: navigationController, + type: .createAccountAndPassword) + coordinator.delegate = self + coordinator.startWithOptions(nil) + + createAccountCoordinator = coordinator + } + + func showImportProfileController() { + let controller = TextViewController( + resourceName: "import-profile", + backgroundColor: theme.colorForType(.LoginBackground), + titleColor: theme.colorForType(.NormalText), + textColor: theme.colorForType(.NormalText)) + + navigationController.pushViewController(controller, animated: true) + } + + /** + * @param profile The name of profile. + * @param password Password to decrypt profile. + * @param configurationClosure Closure called after login to configure profile. + * @param errorClosure Closure called if any error occured during login. + */ + func loginWithProfile( + _ profile: String, + password: String?, + configurationClosure: ((_ manager: OCTManager) -> Void)? = nil, + errorClosure: ((NSError) -> Void)? = nil) + { + guard let password = password else { + if isProfileEncrypted(profile) { + // Profile is encrypted, password is required. No error is needed, password placeholder + // should be quite obvious. + + // However we should show error message for accessibility users. + if UIAccessibilityIsVoiceOverRunning() { + handleErrorWithType(.passwordIsEmpty) + } + return + } + + let coordinator = LoginCreateAccountCoordinator(theme: theme, + navigationController: navigationController, + type: .createPassword) + coordinator.delegate = self + coordinator.userInfo[UserInfoKey.LoginProfile.rawValue] = profile + coordinator.userInfo[UserInfoKey.LoginConfigurationClosure.rawValue] = configurationClosure + coordinator.userInfo[UserInfoKey.LoginErrorClosure.rawValue] = errorClosure + coordinator.startWithOptions(nil) + + createAccountCoordinator = coordinator + return + } + + let path = ProfileManager().pathForProfileWithName(profile) + let configuration = OCTManagerConfiguration.configurationWithBaseDirectory(path)! + + let hud = JGProgressHUD(style: .dark)! + hud.show(in: self.navigationController.view) + + ToxFactory.createToxWithConfiguration(configuration, encryptPassword: password, successBlock: { [weak self] manager -> Void in + hud.dismiss() + + configurationClosure?(manager) + + let userDefaults = UserDefaultsManager() + userDefaults.lastActiveProfile = profile + + self?.delegate?.loginCoordinatorDidLogin(self!, manager: manager, password: password) + + }, failureBlock: { error -> Void in + hud.dismiss() + errorClosure?(error as NSError) + }) + } + + func importToxProfileFromURL(_ url: URL) { + let coordinator = LoginCreateAccountCoordinator(theme: theme, + navigationController: navigationController, + type: .importProfile) + coordinator.userInfo[UserInfoKey.ImportURL.rawValue] = url + coordinator.delegate = self + coordinator.startWithOptions(nil) + + createAccountCoordinator = coordinator + } + + func createProfileWithProfileName(_ profileName: String, username: String?, copyFromURL: URL?, password: String?) { + if profileName.isEmpty { + UIAlertController.showWithTitle("", message: String(localized: "login_enter_username_and_profile"), retryBlock: nil) + return + } + + let profileManager = ProfileManager() + + do { + try profileManager.createProfileWithName(profileName, copyFromURL: copyFromURL) + } + catch let error as NSError { + UIAlertController.showErrorWithMessage(String(localized: error.localizedDescription), retryBlock: nil) + return + } + + if isProfileEncrypted(profileName) && password == nil { + // Cannot login without password, just opening login screen. + UserDefaultsManager().lastActiveProfile = profileName + + let controller = self.createFormController() + let root = self.navigationController.viewControllers[0] + + self.navigationController.setViewControllers([root, controller], animated: true) + + return + } + + loginWithProfile(profileName, password: password, configurationClosure: { + if let name = username { + _ = try? $0.user.setUserName(name) + _ = try? $0.user.setUserStatusMessage("Antidote is Tox") + } + }, errorClosure: { error in + handleErrorWithType(.createOCTManager, error: error) + _ = try? profileManager.deleteProfileWithName(profileName) + }) + } + + func isProfileEncrypted(_ profile: String) -> Bool { + let profilePath = ProfileManager().pathForProfileWithName(profile) + + let configuration = OCTManagerConfiguration.configurationWithBaseDirectory(profilePath)! + let dataPath = configuration.fileStorage.pathForToxSaveFile + + guard FileManager.default.fileExists(atPath: dataPath) else { + return false + } + + guard let data = try? Data(contentsOf: URL(fileURLWithPath: dataPath)) else { + return false + } + + return OCTToxEncryptSave.isDataEncrypted(data) + } +} diff --git a/Antidote/LoginCreateAccountController.swift b/Antidote/LoginCreateAccountController.swift new file mode 100644 index 0000000..d169435 --- /dev/null +++ b/Antidote/LoginCreateAccountController.swift @@ -0,0 +1,80 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit + +protocol LoginCreateAccountControllerDelegate: class { + func loginCreateAccountControllerCreate(_ controller: LoginCreateAccountController, name: String, profile: String) + func loginCreateAccountControllerImport(_ controller: LoginCreateAccountController, profile: String) +} + +class LoginCreateAccountController: LoginGenericCreateController { + enum ControllerType { + case createAccount + case importProfile + } + + weak var delegate: LoginCreateAccountControllerDelegate? + + fileprivate let type: ControllerType + + init(theme: Theme, type: ControllerType) { + self.type = type + + super.init(theme: theme) + } + + required convenience init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func configureViews() { + firstTextField.title = String(localized: "create_account_username_title") + firstTextField.placeholder = String(localized: "create_account_username_placeholder") + firstTextField.maxTextUTF8Length = Int(kOCTToxMaxNameLength) + + secondTextField.title = String(localized: "create_account_profile_title") + secondTextField.placeholder = String(localized: "create_account_profile_placeholder") + secondTextField.hint = String(localized: "create_account_profile_hint") + secondTextField.returnKeyType = .next + + bottomButton.setTitle(String(localized: "create_account_next_button"), for: UIControlState()) + + switch type { + case .createAccount: + titleLabel.text = String(localized: "create_profile") + case .importProfile: + titleLabel.text = String(localized: "import_profile") + firstTextField.isHidden = true + } + } + + override func bottomButtonPressed() { + let profile = secondTextField.text ?? "" + + guard !profile.isEmpty else { + UIAlertController.showWithTitle(String(localized: "login_enter_username_and_profile"), message: nil, retryBlock: nil) + return + } + + guard !ProfileManager().allProfileNames.contains(profile) else { + UIAlertController.showWithTitle(String(localized: "login_profile_already_exists"), message: nil, retryBlock: nil) + return + } + + + switch type { + case .createAccount: + let name = firstTextField.text ?? "" + guard !name.isEmpty else { + UIAlertController.showWithTitle(String(localized: "login_enter_username_and_profile"), message: nil, retryBlock: nil) + return + } + + delegate?.loginCreateAccountControllerCreate(self, name: name, profile: profile) + case .importProfile: + delegate?.loginCreateAccountControllerImport(self, profile: profile) + } + } +} diff --git a/Antidote/LoginCreateAccountCoordinator.swift b/Antidote/LoginCreateAccountCoordinator.swift new file mode 100644 index 0000000..ec4562e --- /dev/null +++ b/Antidote/LoginCreateAccountCoordinator.swift @@ -0,0 +1,98 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +protocol LoginCreateAccountCoordinatorDelegate: class { + func loginCreateAccountCoordinator(_ coordinator: LoginCreateAccountCoordinator, + didCreateAccountWithProfileName profileName: String, + username: String, + password: String) + func loginCreateAccountCoordinator(_ coordinator: LoginCreateAccountCoordinator, + didImportProfileWithProfileName profileName: String) + func loginCreateAccountCoordinator(_ coordinator: LoginCreateAccountCoordinator, didCreatePassword password: String) +} + +class LoginCreateAccountCoordinator { + enum CoordinatorType { + /// Create new account and new password. + case createAccountAndPassword + /// Import existing profile. + case importProfile + /// Create new password. + case createPassword + } + + weak var delegate: LoginCreateAccountCoordinatorDelegate? + + var userInfo = [String: Any]() + + fileprivate let theme: Theme + fileprivate let navigationController: UINavigationController + fileprivate let type: CoordinatorType + + fileprivate var enteredUsername: String? + fileprivate var enteredProfile: String? + + init(theme: Theme, navigationController: UINavigationController, type: CoordinatorType) { + self.theme = theme + self.navigationController = navigationController + self.type = type + } +} + +extension LoginCreateAccountCoordinator: CoordinatorProtocol { + func startWithOptions(_ options: CoordinatorOptions?) { + switch type { + case .createAccountAndPassword: + let controller = LoginCreateAccountController(theme: theme, type: .createAccount) + controller.delegate = self + navigationController.pushViewController(controller, animated: true) + case .importProfile: + let controller = LoginCreateAccountController(theme: theme, type: .importProfile) + controller.delegate = self + navigationController.pushViewController(controller, animated: true) + case .createPassword: + let controller = LoginCreatePasswordController(theme: theme) + controller.delegate = self + navigationController.pushViewController(controller, animated: true) + } + } +} + +extension LoginCreateAccountCoordinator: LoginCreateAccountControllerDelegate { + func loginCreateAccountControllerCreate(_ controller: LoginCreateAccountController, name: String, profile: String) { + enteredUsername = name + enteredProfile = profile + + let controller = LoginCreatePasswordController(theme: theme) + controller.delegate = self + navigationController.pushViewController(controller, animated: true) + } + + func loginCreateAccountControllerImport(_ controller: LoginCreateAccountController, profile: String) { + delegate?.loginCreateAccountCoordinator(self, didImportProfileWithProfileName: profile) + } +} + +extension LoginCreateAccountCoordinator: LoginCreatePasswordControllerDelegate { + func loginCreatePasswordController(_ controller: LoginCreatePasswordController, password: String) { + switch type { + case .createAccountAndPassword: + guard let profile = enteredProfile, + let username = enteredUsername else { + fatalError("LoginCreateAccountCoordinator: unexpected state") + } + + delegate?.loginCreateAccountCoordinator(self, + didCreateAccountWithProfileName: profile, + username: username, + password: password) + case .importProfile: + fatalError("LoginCreateAccountCoordinator: unexpected state") + case .createPassword: + delegate?.loginCreateAccountCoordinator(self, didCreatePassword: password) + } + } +} diff --git a/Antidote/LoginCreatePasswordController.swift b/Antidote/LoginCreatePasswordController.swift new file mode 100644 index 0000000..52185b9 --- /dev/null +++ b/Antidote/LoginCreatePasswordController.swift @@ -0,0 +1,46 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +protocol LoginCreatePasswordControllerDelegate: class { + func loginCreatePasswordController(_ controller: LoginCreatePasswordController, password: String) +} + +class LoginCreatePasswordController: LoginGenericCreateController { + weak var delegate: LoginCreatePasswordControllerDelegate? + + override func configureViews() { + titleLabel.text = String(localized: "set_password_title") + + firstTextField.placeholder = String(localized: "password") + firstTextField.secureTextEntry = true + firstTextField.hint = String(localized: "set_password_hint") + + secondTextField.placeholder = String(localized: "repeat_password") + secondTextField.secureTextEntry = true + + bottomButton.setTitle(String(localized: "create_account_go_button"), for: UIControlState()) + } + + override func bottomButtonPressed() { + guard let first = firstTextField.text, + let second = secondTextField.text else { + handleErrorWithType(.passwordIsEmpty) + return + } + + guard !first.isEmpty && !second.isEmpty else { + handleErrorWithType(.passwordIsEmpty) + return + } + + guard first == second else { + handleErrorWithType(.passwordsDoNotMatch) + return + } + + delegate?.loginCreatePasswordController(self, password: first) + } +} diff --git a/Antidote/LoginFormController.swift b/Antidote/LoginFormController.swift new file mode 100644 index 0000000..23f440a --- /dev/null +++ b/Antidote/LoginFormController.swift @@ -0,0 +1,339 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit +import SnapKit + +protocol LoginFormControllerDelegate: class { + func loginFormControllerLogin(_ controller: LoginFormController, profileName: String, password: String?) + func loginFormControllerCreateAccount(_ controller: LoginFormController) + func loginFormControllerImportProfile(_ controller: LoginFormController) + + func loginFormController(_ controller: LoginFormController, isProfileEncrypted profile: String) -> Bool +} + +class LoginFormController: LoginLogoController { + fileprivate struct PrivateConstants { + static let IconContainerWidth: CGFloat = Constants.TextFieldHeight - 15.0 + static let IconContainerHeight: CGFloat = Constants.TextFieldHeight + + static let FormOffset = 20.0 + static let FormSmallOffset = 10.0 + + static let AnimationDuration = 0.3 + } + + weak var delegate: LoginFormControllerDelegate? + + fileprivate var formView: IncompressibleView! + fileprivate var profileFakeTextField: UITextField! + fileprivate var profileButton: UIButton! + fileprivate var passwordField: UITextField! + + fileprivate var loginButton: RoundedButton! + + fileprivate var bottomButtonsContainer: UIView! + fileprivate var createAccountButton: UIButton! + fileprivate var orLabel: UILabel! + fileprivate var importProfileButton: UIButton! + + fileprivate var profileButtonBottomToFormConstraint: Constraint! + fileprivate var passwordFieldBottomToFormConstraint: Constraint! + + fileprivate let profileNames: [String] + fileprivate var selectedIndex: Int + + init(theme: Theme, profileNames: [String], selectedIndex: Int) { + self.profileNames = profileNames + self.selectedIndex = selectedIndex + + super.init(theme: theme) + } + + required convenience init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func loadView() { + super.loadView() + + createGestureRecognizers() + createFormViews() + createLoginButton() + createBottomButtons() + + installConstraints() + + updateFormAnimated(false) + } + + override func keyboardWillShowAnimated(keyboardFrame frame: CGRect) { + guard navigationController?.topViewController == self else { + return + } + let underLoginHeight = + mainContainerView.frame.size.height - + contentContainerView.frame.origin.y - + loginButton.frame.maxY + + let offset = min(0.0, underLoginHeight - frame.height) + + mainContainerViewTopConstraint?.update(offset: offset) + view.layoutIfNeeded() + } + + override func keyboardWillHideAnimated(keyboardFrame frame: CGRect) { + mainContainerViewTopConstraint?.update(offset: 0.0) + view.layoutIfNeeded() + } +} + +// MARK: Actions +extension LoginFormController { + @objc func profileButtonPressed() { + view.endEditing(true) + + let picker = FullscreenPicker(theme: theme, strings: profileNames, selectedIndex: selectedIndex) + picker.delegate = self + + contentContainerView.accessibilityElementsHidden = true + picker.showAnimatedInView(view) +} + + @objc func loginButtonPressed() { + let isEmpty = (passwordField.text == nil) || passwordField.text!.isEmpty + let password = isEmpty ? nil : passwordField.text + + delegate?.loginFormControllerLogin(self, profileName: profileNames[selectedIndex], password: password) + } + + @objc func createAccountButtonPressed() { + delegate?.loginFormControllerCreateAccount(self) + } + + @objc func importProfileButtonPressed() { + delegate?.loginFormControllerImportProfile(self) + } + + @objc func tapOnView() { + view.endEditing(true) + } +} + +extension LoginFormController: UITextFieldDelegate { + func textFieldShouldReturn(_ textField: UITextField) -> Bool { + loginButtonPressed() + return true + } +} + +extension LoginFormController: FullscreenPickerDelegate { + func fullscreenPicker(_ picker: FullscreenPicker, willDismissWithSelectedIndex index: Int) { + contentContainerView.accessibilityElementsHidden = false + UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, self.profileButton); + + if index == selectedIndex { + return + } + selectedIndex = index + + updateFormAnimated(true) + } +} + +private extension LoginFormController { + func createGestureRecognizers() { + let tapGR = UITapGestureRecognizer(target: self, action: #selector(LoginFormController.tapOnView)) + view.addGestureRecognizer(tapGR) + } + + func createFormViews() { + formView = IncompressibleView() + formView.backgroundColor = .clear + formView.layer.cornerRadius = 5.0 + formView.layer.masksToBounds = true + contentContainerView.addSubview(formView) + + profileFakeTextField = UITextField() + profileFakeTextField.leftViewMode = .always + profileFakeTextField.leftView = iconContainerWithImageName("login-profile-icon") + profileFakeTextField.borderStyle = .roundedRect + profileFakeTextField.layer.borderColor = theme.colorForType(.LoginButtonBackground).cgColor + profileFakeTextField.layer.borderWidth = 0.5 + profileFakeTextField.layer.masksToBounds = true + profileFakeTextField.layer.cornerRadius = 6.0 + profileFakeTextField.isAccessibilityElement = false + profileFakeTextField.accessibilityElementsHidden = true + formView.addSubview(profileFakeTextField) + + profileButton = UIButton() + profileButton.addTarget(self, action: #selector(LoginFormController.profileButtonPressed), for:.touchUpInside) + profileButton.accessibilityLabel = String(localized: "profile_title") + formView.addSubview(profileButton) + + passwordField = UITextField() + passwordField.delegate = self + passwordField.placeholder = String(localized:"password") + passwordField.isSecureTextEntry = true + passwordField.returnKeyType = .go + passwordField.borderStyle = .roundedRect + passwordField.leftViewMode = .always + passwordField.leftView = iconContainerWithImageName("login-password-icon") + passwordField.layer.borderColor = theme.colorForType(.LoginButtonBackground).cgColor + passwordField.layer.borderWidth = 0.5 + passwordField.layer.masksToBounds = true + passwordField.layer.cornerRadius = 6.0 + formView.addSubview(passwordField) + } + + func createLoginButton() { + loginButton = RoundedButton(theme: theme, type: .login) + loginButton.setTitle(String(localized:"log_in"), for: UIControlState()) + loginButton.addTarget(self, action: #selector(LoginFormController.loginButtonPressed), for: .touchUpInside) + contentContainerView.addSubview(loginButton) + } + + func createBottomButtons() { + bottomButtonsContainer = UIView() + bottomButtonsContainer.backgroundColor = .clear + contentContainerView.addSubview(bottomButtonsContainer) + + createAccountButton = createDescriptionButtonWithTitle( + String(localized: "create_profile"), + action: #selector(LoginFormController.createAccountButtonPressed)) + bottomButtonsContainer.addSubview(createAccountButton) + + orLabel = UILabel() + orLabel.text = String(localized: "login_or_label") + orLabel.textColor = theme.colorForType(.LoginButtonBackground) + orLabel.backgroundColor = .clear + bottomButtonsContainer.addSubview(orLabel) + + importProfileButton = createDescriptionButtonWithTitle( + String(localized:"import_to_antidote"), + action: #selector(LoginFormController.importProfileButtonPressed)) + bottomButtonsContainer.addSubview(importProfileButton) + } + + func installConstraints() { + formView.customIntrinsicContentSize.width = CGFloat(Constants.MaxFormWidth) + formView.snp.makeConstraints { + $0.top.equalTo(contentContainerView) + $0.centerX.equalTo(contentContainerView) + $0.width.lessThanOrEqualTo(Constants.MaxFormWidth) + $0.width.lessThanOrEqualTo(contentContainerView).offset(-2 * Constants.HorizontalOffset) + } + + profileFakeTextField.snp.makeConstraints { + $0.edges.equalTo(profileButton) + } + + profileButton.snp.makeConstraints { + $0.top.equalTo(formView).offset(PrivateConstants.FormOffset) + $0.leading.equalTo(formView) + $0.trailing.equalTo(formView) + profileButtonBottomToFormConstraint = $0.bottom.equalTo(formView).offset(-PrivateConstants.FormOffset).constraint + + $0.height.equalTo(Constants.TextFieldHeight) + } + + passwordField.snp.makeConstraints { + $0.top.equalTo(profileButton.snp.bottom).offset(PrivateConstants.FormSmallOffset) + $0.leading.trailing.equalTo(profileButton) + passwordFieldBottomToFormConstraint = $0.bottom.equalTo(formView).offset(-PrivateConstants.FormOffset).constraint + + $0.height.equalTo(Constants.TextFieldHeight) + } + + loginButton.snp.makeConstraints { + $0.top.equalTo(formView.snp.bottom).offset(PrivateConstants.FormSmallOffset) + $0.leading.trailing.equalTo(formView) + } + + bottomButtonsContainer.snp.makeConstraints { + $0.top.greaterThanOrEqualTo(loginButton.snp.bottom).offset(PrivateConstants.FormOffset) + $0.centerX.equalTo(view) + $0.bottom.equalTo(view).offset(-PrivateConstants.FormOffset) + } + + createAccountButton.snp.makeConstraints { + $0.top.leading.bottom.equalTo(bottomButtonsContainer) + } + + orLabel.snp.makeConstraints { + $0.centerY.equalTo(bottomButtonsContainer) + $0.leading.equalTo(createAccountButton.snp.trailing).offset(PrivateConstants.FormSmallOffset) + $0.trailing.equalTo(importProfileButton.snp.leading).offset(-PrivateConstants.FormSmallOffset) + } + + importProfileButton.snp.makeConstraints { + $0.top.trailing.bottom.equalTo(bottomButtonsContainer) + } + } + + func iconContainerWithImageName(_ imageName: String) -> UIView { + let image = UIImage.templateNamed(imageName) + + let imageView = UIImageView(image: image) + imageView.tintColor = UIColor(white: 200.0/255.0, alpha:1.0) + + let container = UIView() + container.backgroundColor = .clear + container.addSubview(imageView) + + container.frame.size.width = PrivateConstants.IconContainerWidth + container.frame.size.height = PrivateConstants.IconContainerHeight + + imageView.frame.origin.x = PrivateConstants.IconContainerWidth - imageView.frame.size.width + imageView.frame.origin.y = (PrivateConstants.IconContainerHeight - imageView.frame.size.height) / 2 - 1.0 + + return container + } + + func createDescriptionButtonWithTitle(_ title: String, action: Selector) -> UIButton { + let button = UIButton() + button.setTitle(title, for: UIControlState()) + button.setTitleColor(theme.colorForType(.LoginLinkColor), for: UIControlState()) + button.titleLabel?.font = UIFont.systemFont(ofSize: 16.0) + button.addTarget(self, action: action, for: .touchUpInside) + + return button + } + + func updateFormAnimated(_ animated: Bool) { + let profileName = profileNames[selectedIndex] + + profileFakeTextField.text = profileName + profileButton.accessibilityValue = profileName + passwordField.text = nil + + let isEncrypted = delegate?.loginFormController(self, isProfileEncrypted: profileName) ?? false + + showPasswordField(isEncrypted, animated: animated) + } + + func showPasswordField(_ show: Bool, animated: Bool) { + func updateForm() { + if (show) { + profileButtonBottomToFormConstraint.deactivate() + passwordFieldBottomToFormConstraint.activate() + passwordField.alpha = 1.0 + } + else { + profileButtonBottomToFormConstraint.activate() + passwordFieldBottomToFormConstraint.deactivate() + passwordField.alpha = 0.0 + } + + view.layoutIfNeeded() + } + + if animated { + UIView.animate(withDuration: PrivateConstants.AnimationDuration, animations: updateForm) + } + else { + updateForm() + } + } +} diff --git a/Antidote/LoginGenericCreateController.swift b/Antidote/LoginGenericCreateController.swift new file mode 100644 index 0000000..e44ebf4 --- /dev/null +++ b/Antidote/LoginGenericCreateController.swift @@ -0,0 +1,154 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation +import SnapKit + +private struct PrivateConstants { + static let FieldsOffset = 20.0 + static let VerticalOffset = 30.0 +} + +class LoginGenericCreateController: LoginBaseController { + fileprivate var containerView: IncompressibleView! + fileprivate var containerViewTopConstraint: Constraint! + + var titleLabel: UILabel! + var firstTextField: ExtendedTextField! + var secondTextField: ExtendedTextField! + var bottomButton: RoundedButton! + + override func loadView() { + super.loadView() + + createGestureRecognizers() + createContainerView() + createTitleLabel() + createExtendedTextFields() + createGoButton() + + configureViews() + installConstraints() + } + + override func keyboardWillShowAnimated(keyboardFrame frame: CGRect) { + if containerView.frame.isEmpty { + return + } + let underFormHeight = containerView.frame.size.height - secondTextField.frame.maxY + + let offset = min(0.0, underFormHeight - frame.height) + + containerViewTopConstraint.update(offset: offset) + view.layoutIfNeeded() + } + + override func keyboardWillHideAnimated(keyboardFrame frame: CGRect) { + containerViewTopConstraint.update(offset: 0.0) + view.layoutIfNeeded() + } + + func configureViews() { + fatalError("override in subclass") + } +} + +extension LoginGenericCreateController { + @objc func tapOnView() { + view.endEditing(true) + } + + @objc func bottomButtonPressed() { + fatalError("override in subclass") + } +} + +extension LoginGenericCreateController: ExtendedTextFieldDelegate { + func loginExtendedTextFieldReturnKeyPressed(_ field: ExtendedTextField) { + if field == firstTextField { + _ = secondTextField.becomeFirstResponder() + } + else if field == secondTextField { + view.endEditing(true) + bottomButtonPressed() + } + } +} + +private extension LoginGenericCreateController { + func createGestureRecognizers() { + let tapGR = UITapGestureRecognizer(target: self, action: #selector(LoginCreateAccountController.tapOnView)) + view.addGestureRecognizer(tapGR) + } + + func createContainerView() { + containerView = IncompressibleView() + containerView.backgroundColor = .clear + view.addSubview(containerView) + } + + func createTitleLabel() { + titleLabel = UILabel() + titleLabel.textColor = theme.colorForType(.LoginButtonBackground) + titleLabel.font = UIFont.antidoteFontWithSize(26.0, weight: .light) + titleLabel.backgroundColor = .clear + containerView.addSubview(titleLabel) + } + + func createExtendedTextFields() { + firstTextField = ExtendedTextField(theme: theme, type: .login) + firstTextField.delegate = self + firstTextField.returnKeyType = .next + containerView.addSubview(firstTextField) + + secondTextField = ExtendedTextField(theme: theme, type: .login) + secondTextField.delegate = self + secondTextField.returnKeyType = .go + containerView.addSubview(secondTextField) + } + + func createGoButton() { + bottomButton = RoundedButton(theme: theme, type: .login) + bottomButton.addTarget(self, action: #selector(LoginCreateAccountController.bottomButtonPressed), for: .touchUpInside) + containerView.addSubview(bottomButton) + } + + func installConstraints() { + containerView.customIntrinsicContentSize.width = CGFloat(Constants.MaxFormWidth) + containerView.snp.makeConstraints { + containerViewTopConstraint = $0.top.equalTo(view).constraint + $0.centerX.equalTo(view) + $0.width.lessThanOrEqualTo(Constants.MaxFormWidth) + $0.width.lessThanOrEqualTo(view).offset(-2 * Constants.HorizontalOffset) + $0.height.equalTo(view) + } + + titleLabel.snp.makeConstraints { + $0.top.equalTo(containerView).offset(PrivateConstants.VerticalOffset) + $0.centerX.equalTo(containerView) + } + + firstTextField.snp.makeConstraints { + $0.top.equalTo(titleLabel.snp.bottom).offset(PrivateConstants.FieldsOffset) + $0.leading.equalTo(containerView) + $0.trailing.equalTo(containerView) + } + + secondTextField.snp.makeConstraints { + $0.leading.trailing.equalTo(firstTextField) + + if firstTextField.isHidden { + $0.top.equalTo(titleLabel.snp.bottom).offset(PrivateConstants.FieldsOffset) + } + else { + $0.top.equalTo(firstTextField.snp.bottom).offset(PrivateConstants.FieldsOffset) + } + } + + bottomButton.snp.makeConstraints { + $0.top.equalTo(secondTextField.snp.bottom).offset(PrivateConstants.VerticalOffset) + $0.leading.trailing.equalTo(firstTextField) + } + } +} diff --git a/Antidote/LoginLogoController.swift b/Antidote/LoginLogoController.swift new file mode 100644 index 0000000..f12c3bc --- /dev/null +++ b/Antidote/LoginLogoController.swift @@ -0,0 +1,89 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit +import SnapKit + +private struct PrivateConstants { + static let LogoTopOffset = -200.0 + static let LogoHeight = 100.0 +} + +class LoginLogoController: LoginBaseController { + /** + * Main view, which is used as container for all subviews. + */ + var mainContainerView: UIView! + var mainContainerViewTopConstraint: Constraint? + + var logoImageView: UIImageView! + + /** + * Use this container to add subviews in subclasses. + * Is placed under logo. + */ + var contentContainerView: UIView! + + override func loadView() { + super.loadView() + + createMainContainerView() + createLogoImageView() + createContainerView() + + installConstraints() + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + navigationController?.setNavigationBarHidden(true, animated:animated) + } + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + navigationController?.setNavigationBarHidden(false, animated:animated) + } +} + +private extension LoginLogoController { + func createMainContainerView() { + mainContainerView = UIView() + mainContainerView.backgroundColor = .clear + view.addSubview(mainContainerView) + } + + func createLogoImageView() { + let image = UIImage(named: "login-logo") + + logoImageView = UIImageView(image: image) + logoImageView.contentMode = .scaleAspectFit + mainContainerView.addSubview(logoImageView) + } + + func createContainerView() { + contentContainerView = UIView() + contentContainerView.backgroundColor = .clear + mainContainerView.addSubview(contentContainerView) + } + + func installConstraints() { + mainContainerView.snp.makeConstraints { + mainContainerViewTopConstraint = $0.top.equalTo(view).constraint + $0.leading.trailing.equalTo(view) + $0.height.equalTo(view) + } + + logoImageView.snp.makeConstraints { + $0.centerX.equalTo(mainContainerView) + $0.top.equalTo(mainContainerView.snp.centerY).offset(PrivateConstants.LogoTopOffset) + $0.height.equalTo(PrivateConstants.LogoHeight) + } + + contentContainerView.snp.makeConstraints { + $0.top.equalTo(logoImageView.snp.bottom).offset(Constants.VerticalOffset) + $0.bottom.equalTo(mainContainerView) + $0.leading.trailing.equalTo(mainContainerView) + } + } +} diff --git a/Antidote/NSDateFormatterExtension.swift b/Antidote/NSDateFormatterExtension.swift new file mode 100644 index 0000000..42e52a4 --- /dev/null +++ b/Antidote/NSDateFormatterExtension.swift @@ -0,0 +1,35 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +extension DateFormatter { + enum FormatterType { + case time + case dateAndTime + case relativeDate + case relativeDateAndTime + } + + convenience init(type: FormatterType) { + self.init() + + switch type { + case .time: + dateFormat = "H:mm" + case .dateAndTime: + dateStyle = .short + timeStyle = .short + doesRelativeDateFormatting = false + case .relativeDate: + dateStyle = .short + timeStyle = .none + doesRelativeDateFormatting = true + case .relativeDateAndTime: + dateStyle = .short + timeStyle = .short + doesRelativeDateFormatting = true + } + } +} diff --git a/Antidote/NSTimerExtension.swift b/Antidote/NSTimerExtension.swift new file mode 100644 index 0000000..f0d98b5 --- /dev/null +++ b/Antidote/NSTimerExtension.swift @@ -0,0 +1,30 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +private class ClosureWrapper { + let closure: T + + init(closure: T) { + self.closure = closure + } +} + +extension Timer { + static func scheduledTimer(timeInterval interval: TimeInterval,closure:@escaping(Timer) -> Void, repeats: Bool) -> Timer { + // TODO: check if escaping is actually correct here + let userInfo = ClosureWrapper(closure: closure) + + return scheduledTimer(timeInterval: interval, target: self, selector: #selector(Timer.executeBlock(_:)), userInfo: userInfo, repeats: repeats) + } + + @objc static func executeBlock(_ timer: Timer) { + guard let wrapper = timer.userInfo as? ClosureWrapper<(Timer) -> Void> else { + return + } + + wrapper.closure(timer) + } +} diff --git a/Antidote/NSURLExtension.swift b/Antidote/NSURLExtension.swift new file mode 100644 index 0000000..10ce0be --- /dev/null +++ b/Antidote/NSURLExtension.swift @@ -0,0 +1,29 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation +import MobileCoreServices + +extension URL { + func isToxURL() -> Bool { + guard isFileURL else { + return false + } + + let request = URLRequest(url: self, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 0.1) + var response: URLResponse? = nil + + _ = try? NSURLConnection.sendSynchronousRequest(request, returning: &response) + + guard let mimeType = response?.mimeType else { + return false + } + + guard let identifier = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, mimeType as CFString, nil)?.takeRetainedValue() else { + return false + } + + return UTTypeEqual(identifier, kUTTypeData) + } +} diff --git a/Antidote/NotificationCoordinator.swift b/Antidote/NotificationCoordinator.swift new file mode 100644 index 0000000..fbff789 --- /dev/null +++ b/Antidote/NotificationCoordinator.swift @@ -0,0 +1,398 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +private enum NotificationType { + case newMessage(OCTMessageAbstract) + case friendRequest(OCTFriendRequest) +} + +private struct Constants { + static let NotificationVisibleDuration = 3.0 +} + +protocol NotificationCoordinatorDelegate: class { + func notificationCoordinator(_ coordinator: NotificationCoordinator, showChat chat: OCTChat) + func notificationCoordinatorShowFriendRequest(_ coordinator: NotificationCoordinator, showRequest request: OCTFriendRequest) + func notificationCoordinatorAnswerIncomingCall(_ coordinator: NotificationCoordinator, userInfo: String) + + func notificationCoordinator(_ coordinator: NotificationCoordinator, updateFriendsBadge badge: Int) + func notificationCoordinator(_ coordinator: NotificationCoordinator, updateChatsBadge badge: Int) +} + +class NotificationCoordinator: NSObject { + weak var delegate: NotificationCoordinatorDelegate? + + fileprivate let theme: Theme + fileprivate let userDefaults = UserDefaultsManager() + + fileprivate let notificationWindow: NotificationWindow + + fileprivate weak var submanagerObjects: OCTSubmanagerObjects! + + fileprivate var messagesToken: RLMNotificationToken? + fileprivate var chats: Results + fileprivate var chatsToken: RLMNotificationToken? + fileprivate var requests: Results + fileprivate var requestsToken: RLMNotificationToken? + + fileprivate let avatarManager: AvatarManager + fileprivate let audioPlayer = AlertAudioPlayer() + + fileprivate var notificationQueue = [NotificationType]() + fileprivate var inAppNotificationAppIdsRegistered = [String: Bool]() + fileprivate var bannedChatIdentifiers = Set() + + init(theme: Theme, submanagerObjects: OCTSubmanagerObjects) { + self.theme = theme + self.notificationWindow = NotificationWindow(theme: theme) + + self.submanagerObjects = submanagerObjects + self.avatarManager = AvatarManager(theme: theme) + + let predicate = NSPredicate(format: "lastMessage.dateInterval > lastReadDateInterval") + self.chats = submanagerObjects.chats(predicate: predicate) + self.requests = submanagerObjects.friendRequests() + + super.init() + + addNotificationBlocks() + + NotificationCenter.default.addObserver(self, selector: #selector(NotificationCoordinator.applicationDidBecomeActive), name: NSNotification.Name.UIApplicationDidBecomeActive, object: nil) + } + + deinit { + NotificationCenter.default.removeObserver(self) + + messagesToken?.invalidate() + chatsToken?.invalidate() + requestsToken?.invalidate() + } + + /** + Show or hide connnecting view. + */ + func toggleConnectingView(show: Bool, animated: Bool) { + notificationWindow.showConnectingView(show, animated: animated) + } + + /** + Stops showing notifications for given chat. + Also removes all related to that chat notifications from queue. + */ + func banNotificationsForChat(_ chat: OCTChat) { + bannedChatIdentifiers.insert(chat.uniqueIdentifier) + + notificationQueue = notificationQueue.filter { + switch $0 { + case .newMessage(let messageAbstract): + return messageAbstract.chatUniqueIdentifier != chat.uniqueIdentifier + case .friendRequest: + return true + } + } + + LNNotificationCenter.default().clearPendingNotifications(forApplicationIdentifier: chat.uniqueIdentifier); + } + + /** + Unban notifications for given chat (if they were banned before). + */ + func unbanNotificationsForChat(_ chat: OCTChat) { + bannedChatIdentifiers.remove(chat.uniqueIdentifier) + } + + func handleLocalNotification(_ notification: UILocalNotification) { + guard let userInfo = notification.userInfo as? [String: String] else { + return + } + + guard let action = NotificationAction(dictionary: userInfo) else { + return + } + + performAction(action) + } + + func showCallNotificationWithCaller(_ caller: String, userInfo: String) { + let object = NotificationObject( + title: caller, + body: String(localized: "notification_is_calling"), + action: .answerIncomingCall(userInfo: userInfo), + soundName: "isotoxin_Ringtone.aac") + + showLocalNotificationObject(object) + } + + func registerInAppNotificationAppId(_ appId: String) { + if inAppNotificationAppIdsRegistered[appId] == nil { + LNNotificationCenter.default().registerApplication(withIdentifier: appId, name: Bundle.main.infoDictionary?["CFBundleDisplayName"] as? String, icon: UIImage(named: "notification-app-icon"), defaultSettings: LNNotificationAppSettings.default()) + inAppNotificationAppIdsRegistered[appId] = true + } + } +} + +extension NotificationCoordinator: CoordinatorProtocol { + func startWithOptions(_ options: CoordinatorOptions?) { + let settings = UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil) + + let application = UIApplication.shared + application.registerUserNotificationSettings(settings) + application.cancelAllLocalNotifications() + + updateBadges() + } +} + +// MARK: Notifications +extension NotificationCoordinator { + @objc func applicationDidBecomeActive() { + UIApplication.shared.cancelAllLocalNotifications() + } +} + +private extension NotificationCoordinator { + func addNotificationBlocks() { + let messages = submanagerObjects.messages().sortedResultsUsingProperty("dateInterval", ascending: false) + messagesToken = messages.addNotificationBlock { [unowned self] change in + switch change { + case .initial: + break + case .update(let messages, _, let insertions, _): + guard let messages = messages else { + break + } + if insertions.contains(0) { + let message = messages[0] + + self.playSoundForMessageIfNeeded(message) + + if self.shouldEnqueueMessage(message) { + self.enqueueNotification(.newMessage(message)) + } + } + case .error(let error): + fatalError("\(error)") + } + } + + chatsToken = chats.addNotificationBlock { [unowned self] change in + switch change { + case .initial: + break + case .update: + self.updateBadges() + case .error(let error): + fatalError("\(error)") + } + } + + requestsToken = requests.addNotificationBlock { [unowned self] change in + switch change { + case .initial: + break + case .update(let requests, _, let insertions, _): + guard let requests = requests else { + break + } + for index in insertions { + let request = requests[index] + + self.audioPlayer.playSound(.NewMessage) + self.enqueueNotification(.friendRequest(request)) + } + self.updateBadges() + case .error(let error): + fatalError("\(error)") + } + } + } + + func playSoundForMessageIfNeeded(_ message: OCTMessageAbstract) { + if message.isOutgoing() { + return + } + + if message.messageText != nil || message.messageFile != nil { + audioPlayer.playSound(.NewMessage) + } + } + + func shouldEnqueueMessage(_ message: OCTMessageAbstract) -> Bool { + if message.isOutgoing() { + return false + } + + if UIApplication.isActive && bannedChatIdentifiers.contains(message.chatUniqueIdentifier) { + return false + } + + if message.messageText != nil || message.messageFile != nil { + return true + } + + return false + } + + func enqueueNotification(_ notification: NotificationType) { + notificationQueue.append(notification) + + showNextNotification() + } + + func showNextNotification() { + if notificationQueue.isEmpty { + return + } + + let notification = notificationQueue.removeFirst() + let object = notificationObjectFromNotification(notification) + + if UIApplication.isActive { + switch notification { + case .newMessage(let messageAbstract): + showInAppNotificationObject(object, chatUniqueIdentifier: messageAbstract.chatUniqueIdentifier) + default: + showInAppNotificationObject(object, chatUniqueIdentifier: nil) + } + } + else { + showLocalNotificationObject(object) + } + } + + func showInAppNotificationObject(_ object: NotificationObject, chatUniqueIdentifier: String?) { + var appId:String + + if chatUniqueIdentifier != nil { + appId = chatUniqueIdentifier! + } else { + appId = Bundle.main.bundleIdentifier! + } + + registerInAppNotificationAppId(appId); + + let notification = LNNotification.init(message: object.body, title: object.title) + notification?.defaultAction = LNNotificationAction.init(title: nil, handler: { [weak self] _ in + self?.performAction(object.action) + }) + + LNNotificationCenter.default().present(notification, forApplicationIdentifier: appId) + + showNextNotification() + } + + func showLocalNotificationObject(_ object: NotificationObject) { + let local = UILocalNotification() + local.alertBody = "\(object.title): \(object.body)" + local.userInfo = object.action.archive() + local.soundName = object.soundName + + UIApplication.shared.presentLocalNotificationNow(local) + + showNextNotification() + } + + func notificationObjectFromNotification(_ notification: NotificationType) -> NotificationObject { + switch notification { + case .friendRequest(let request): + return notificationObjectFromRequest(request) + case .newMessage(let message): + return notificationObjectFromMessage(message) + } + } + + func notificationObjectFromRequest(_ request: OCTFriendRequest) -> NotificationObject { + let title = String(localized: "notification_incoming_contact_request") + let body = request.message ?? "" + let action = NotificationAction.openRequest(requestUniqueIdentifier: request.uniqueIdentifier) + + return NotificationObject(title: title, body: body, action: action, soundName: "isotoxin_NewMessage.aac") + } + + func notificationObjectFromMessage(_ message: OCTMessageAbstract) -> NotificationObject { + let title: String + + if let friend = submanagerObjects.object(withUniqueIdentifier: message.senderUniqueIdentifier, for: .friend) as? OCTFriend { + title = friend.nickname + } + else { + title = "" + } + + var body: String = "" + let action = NotificationAction.openChat(chatUniqueIdentifier: message.chatUniqueIdentifier) + + if let messageText = message.messageText { + let defaultString = String(localized: "notification_new_message") + + if userDefaults.showNotificationPreview { + body = messageText.text ?? defaultString + } + else { + body = defaultString + } + } + else if let messageFile = message.messageFile { + let defaultString = String(localized: "notification_incoming_file") + + if userDefaults.showNotificationPreview { + body = messageFile.fileName ?? defaultString + } + else { + body = defaultString + } + } + + return NotificationObject(title: title, body: body, action: action, soundName: "isotoxin_NewMessage.aac") + } + + func performAction(_ action: NotificationAction) { + switch action { + case .openChat(let identifier): + guard let chat = submanagerObjects.object(withUniqueIdentifier: identifier, for: .chat) as? OCTChat else { + return + } + + delegate?.notificationCoordinator(self, showChat: chat) + banNotificationsForChat(chat) + case .openRequest(let identifier): + guard let request = submanagerObjects.object(withUniqueIdentifier: identifier, for: .friendRequest) as? OCTFriendRequest else { + return + } + + delegate?.notificationCoordinatorShowFriendRequest(self, showRequest: request) + case .answerIncomingCall(let userInfo): + delegate?.notificationCoordinatorAnswerIncomingCall(self, userInfo: userInfo) + } + } + + func updateBadges() { + let chatsCount = chats.count + let requestsCount = requests.count + + delegate?.notificationCoordinator(self, updateChatsBadge: chatsCount) + delegate?.notificationCoordinator(self, updateFriendsBadge: requestsCount) + + UIApplication.shared.applicationIconBadgeNumber = chatsCount + requestsCount + } + + // func chatsBadge() -> Int { + // // TODO update to new Realm and filter unread chats with predicate "lastMessage.dateInterval > lastReadDateInterval" + // var badge = 0 + + // for index in 0.. [String: String] { + switch self { + case .openChat(let identifier): + return [ + Constants.ValueKey: Constants.OpenChatValue, + Constants.ArgumentKey: identifier, + ] + case .openRequest(let identifier): + return [ + Constants.ValueKey: Constants.OpenRequestValue, + Constants.ArgumentKey: identifier, + ] + case .answerIncomingCall(let userInfo): + return [ + Constants.ValueKey: Constants.AnswerIncomingCallValue, + Constants.ArgumentKey: userInfo, + ] + } + } +} + +struct NotificationObject { + /// Title of notification + let title: String + + /// Body text of notification + let body: String + + /// Action to be fired when user interacts with notification + let action: NotificationAction + + /// Sound to play when notification is fired. Valid only for local notifications. + let soundName: String +} diff --git a/Antidote/NotificationWindow.swift b/Antidote/NotificationWindow.swift new file mode 100644 index 0000000..6f1de7a --- /dev/null +++ b/Antidote/NotificationWindow.swift @@ -0,0 +1,133 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit +import SnapKit + +private struct Constants { + static let AnimationDuration = 0.3 + static let ConnectingBlinkPeriod = 1.0 +} + +class NotificationWindow: UIWindow { + fileprivate let theme: Theme + + fileprivate var connectingView: UIView! + fileprivate var connectingViewLabel: UILabel! + fileprivate var connectingViewTopConstraint: Constraint! + + init(theme: Theme) { + self.theme = theme + + super.init(frame: UIScreen.main.bounds) + + windowLevel = UIWindowLevelStatusBar + 500 + backgroundColor = .clear + isHidden = false + + createRootViewController() + createConnectingView() + startConnectingViewAnimation() + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func point(inside point: CGPoint, with event: UIEvent?) -> Bool { + for subview in subviews { + let converted = convert(point, to: subview) + + if subview.hitTest(converted, with: event) != nil { + return true + } + } + + return false + } + + func showConnectingView(_ show: Bool, animated: Bool) { + let showPreparation = { [unowned self] in + self.connectingView.isHidden = false + } + + let showBlock = { [unowned self] in + self.connectingViewTopConstraint.update(offset: 0.0) + self.layoutIfNeeded() + + self.startConnectingViewAnimation() + } + + let showCompletion = {} + + let hidePreparation = {} + + let hideBlock = { [unowned self] in + self.connectingViewTopConstraint.update(offset: -self.connectingView.frame.size.height) + self.layoutIfNeeded() + self.connectingViewLabel.layer.removeAllAnimations() + } + + let hideCompletion = { [unowned self] in + self.connectingView.isHidden = true + } + + show ? showPreparation() : hidePreparation() + + if animated { + UIView.animate(withDuration: Constants.AnimationDuration, animations: { + show ? showBlock() : hideBlock() + }, completion: { finished in + show ? showCompletion() : hideCompletion() + }) + } + else { + show ? showBlock() : hideBlock() + show ? showCompletion() : hideCompletion() + } + } +} + +private extension NotificationWindow { + func createRootViewController() { + rootViewController = UIViewController() + rootViewController!.view = ViewPassingGestures() + rootViewController!.view.backgroundColor = .clear + } + + func createConnectingView() { + connectingView = UIView() + connectingView.backgroundColor = theme.colorForType(.ConnectingBackground) + addSubview(connectingView) + + connectingViewLabel = UILabel() + connectingViewLabel.textColor = theme.colorForType(.ConnectingText) + connectingViewLabel.backgroundColor = .clear + connectingViewLabel.text = String(localized: "connecting_label") + connectingViewLabel.textAlignment = .center + connectingViewLabel.font = UIFont.antidoteFontWithSize(12.0, weight: .light) + connectingView.addSubview(connectingViewLabel) + + connectingView.snp.makeConstraints { + connectingViewTopConstraint = $0.top.equalTo(self).constraint + $0.leading.trailing.equalTo(self) + $0.height.equalTo(UIApplication.shared.statusBarFrame.size.height) + } + + connectingViewLabel.snp.makeConstraints { + $0.edges.equalTo(connectingView) + } + } + + func startConnectingViewAnimation() { + connectingViewLabel.alpha = 0.0 + UIView.animate(withDuration: Constants.ConnectingBlinkPeriod, delay: 0.0, options: [.repeat, .autoreverse], animations: { + self.connectingViewLabel.alpha = 1.0 + }, completion: nil) + } + + func stopConnectingViewAnimation() { + stopConnectingViewAnimation() + } +} diff --git a/Antidote/OCTManagerConfigurationExtension.swift b/Antidote/OCTManagerConfigurationExtension.swift new file mode 100644 index 0000000..d229131 --- /dev/null +++ b/Antidote/OCTManagerConfigurationExtension.swift @@ -0,0 +1,25 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +extension OCTManagerConfiguration { + static func configurationWithBaseDirectory(_ baseDirectory: String) -> OCTManagerConfiguration? { + var isDirectory: ObjCBool = false + let exists = FileManager.default.fileExists(atPath: baseDirectory, isDirectory:&isDirectory) + + guard exists && isDirectory.boolValue else { + return nil + } + + let configuration = OCTManagerConfiguration.default() + + let userDefaultsManager = UserDefaultsManager() + + configuration.options.ipv6Enabled = true + configuration.options.udpEnabled = userDefaultsManager.UDPEnabled + + configuration.fileStorage = OCTDefaultFileStorage(baseDirectory: baseDirectory, temporaryDirectory: NSTemporaryDirectory()) + + return configuration + } +} diff --git a/Antidote/OCTManagerMock.swift b/Antidote/OCTManagerMock.swift new file mode 100644 index 0000000..167d8f8 --- /dev/null +++ b/Antidote/OCTManagerMock.swift @@ -0,0 +1,198 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation +import MobileCoreServices + +private enum Gender { + case male + case female +} + +class OCTManagerMock: NSObject, OCTManager { + var bootstrap: OCTSubmanagerBootstrap + var calls: OCTSubmanagerCalls + var chats: OCTSubmanagerChats + var files: OCTSubmanagerFiles + var friends: OCTSubmanagerFriends + var objects: OCTSubmanagerObjects + var user: OCTSubmanagerUser + + var realm: RLMRealm + + override init() { + let configuration = RLMRealmConfiguration.default() + configuration.inMemoryIdentifier = "test realm" + realm = try! RLMRealm(configuration: configuration) + + bootstrap = OCTSubmanagerBootstrapMock() + calls = OCTSubmanagerCallsMock() + chats = OCTSubmanagerChatsMock() + files = OCTSubmanagerFilesMock() + friends = OCTSubmanagerFriendsMock() + objects = OCTSubmanagerObjectsMock(realm: realm) + user = OCTSubmanagerUserMock() + + super.init() + + populateRealm() + } + + func configuration() -> OCTManagerConfiguration { + return OCTManagerConfiguration() + } + + func exportToxSaveFile() throws -> String { + return "123" + } + + func changeEncryptPassword(_ newPassword: String, oldPassword: String) -> Bool { + return true + } + + func isManagerEncrypted(withPassword password: String) -> Bool { + return true + } +} + +private extension OCTManagerMock { + func populateRealm() { + realm.beginWriteTransaction() + + let f1 = addFriend(gender: .female, number: 1, connectionStatus: .TCP, status: .none) + let f2 = addFriend(gender: .male, number: 1, connectionStatus: .TCP, status: .busy) + let f3 = addFriend(gender: .female, number: 2, connectionStatus: .none, status: .none) + let f4 = addFriend(gender: .male, number: 2, connectionStatus: .TCP, status: .away) + let f5 = addFriend(gender: .male, number: 3, connectionStatus: .TCP, status: .none) + let f6 = addFriend(gender: .female, number: 3, connectionStatus: .TCP, status: .away) + let f7 = addFriend(gender: .male, number: 4, connectionStatus: .TCP, status: .away) + let f8 = addFriend(gender: .female, number: 4, connectionStatus: .none, status: .none) + let f9 = addFriend(gender: .female, number: 5, connectionStatus: .TCP, status: .none) + let f10 = addFriend(gender: .male, number: 5, connectionStatus: .none, status: .none) + + let c1 = addChat(friend: f1) + let c2 = addChat(friend: f2) + let c3 = addChat(friend: f3) + let c4 = addChat(friend: f4) + let c5 = addChat(friend: f5) + let c6 = addChat(friend: f6) + let c7 = addChat(friend: f7) + let c8 = addChat(friend: f8) + let c9 = addChat(friend: f9) + let c10 = addChat(friend: f10) + + addDemoConversationToChat(c1) + addCallMessage(chat: c2, outgoing: false, answered: false, duration: 0.0) + addTextMessage(chat: c3, outgoing: false, text: String(localized: "app_store_screenshot_chat_message_1")) + addCallMessage(chat: c4, outgoing: true, answered: true, duration: 1473.0) + addTextMessage(chat: c5, outgoing: false, text: String(localized: "app_store_screenshot_chat_message_2")) + addFileMessage(chat: c6, outgoing: false, fileName: "party.png") + addTextMessage(chat: c7, outgoing: true, text: String(localized: "app_store_screenshot_chat_message_3")) + addTextMessage(chat: c8, outgoing: true, text: String(localized: "app_store_screenshot_chat_message_4")) + addFileMessage(chat: c9, outgoing: true, fileName: "presentation_2016.pdf") + addTextMessage(chat: c10, outgoing: false, text: String(localized: "app_store_screenshot_chat_message_5")) + + c1.lastReadDateInterval = Date().timeIntervalSince1970 + // unread message + // c2.lastReadDateInterval = NSDate().timeIntervalSince1970 + c3.lastReadDateInterval = Date().timeIntervalSince1970 + c4.lastReadDateInterval = Date().timeIntervalSince1970 + c5.lastReadDateInterval = Date().timeIntervalSince1970 + c6.lastReadDateInterval = Date().timeIntervalSince1970 + c7.lastReadDateInterval = Date().timeIntervalSince1970 + c8.lastReadDateInterval = Date().timeIntervalSince1970 + c9.lastReadDateInterval = Date().timeIntervalSince1970 + c10.lastReadDateInterval = Date().timeIntervalSince1970 + + try! realm.commitWriteTransaction() + } + + func addFriend(gender: Gender, + number: Int, + connectionStatus: OCTToxConnectionStatus, + status: OCTToxUserStatus) -> OCTFriend { + let friend = OCTFriend() + friend.publicKey = "123" + friend.connectionStatus = connectionStatus + friend.isConnected = connectionStatus != .none + friend.status = status + + switch gender { + case .male: + friend.nickname = String(localized: "app_store_screenshot_friend_male_\(number)") + friend.avatarData = UIImagePNGRepresentation(UIImage(named: "male-\(number)")!) + case .female: + friend.nickname = String(localized: "app_store_screenshot_friend_female_\(number)") + friend.avatarData = UIImagePNGRepresentation(UIImage(named: "female-\(number)")!) + } + + realm.add(friend) + + return friend + } + + func addChat(friend: OCTFriend) -> OCTChat { + let chat = OCTChat() + + realm.add(chat) + chat.friends.add(friend) + + return chat + } + + func addDemoConversationToChat(_ chat: OCTChat) { + addFileMessage(chat: chat, outgoing: false, fileName: "party.png") + addTextMessage(chat: chat, outgoing: true, text: String(localized: "app_store_screenshot_conversation_1")) + addTextMessage(chat: chat, outgoing: false, text: String(localized: "app_store_screenshot_conversation_2")) + addTextMessage(chat: chat, outgoing: true, text: String(localized: "app_store_screenshot_conversation_3")) + addTextMessage(chat: chat, outgoing: false, text: String(localized: "app_store_screenshot_conversation_4")) + addTextMessage(chat: chat, outgoing: false, text: String(localized: "app_store_screenshot_conversation_5")) + addTextMessage(chat: chat, outgoing: true, text: String(localized: "app_store_screenshot_conversation_6")) + addTextMessage(chat: chat, outgoing: true, text: String(localized: "app_store_screenshot_conversation_7")) + } + + func addTextMessage(chat: OCTChat, outgoing: Bool, text: String) { + let messageText = OCTMessageText() + messageText.text = text + messageText.isDelivered = outgoing + + let message = addMessageAbstract(chat: chat, outgoing: outgoing) + message.messageText = messageText + } + + func addFileMessage(chat: OCTChat, outgoing: Bool, fileName: String) { + let messageFile = OCTMessageFile() + messageFile.fileName = fileName + messageFile.internalFilePath = Bundle.main.path(forResource: "dummy-photo", ofType: "jpg") + messageFile.fileType = .ready + messageFile.fileUTI = kUTTypeImage as String + + let message = addMessageAbstract(chat: chat, outgoing: outgoing) + message.messageFile = messageFile + } + + func addCallMessage(chat: OCTChat, outgoing: Bool, answered: Bool, duration: TimeInterval) { + let messageCall = OCTMessageCall() + messageCall.callDuration = duration + messageCall.callEvent = answered ? .answered : .unanswered + + let message = addMessageAbstract(chat: chat, outgoing: outgoing) + message.messageCall = messageCall + } + + func addMessageAbstract(chat: OCTChat, outgoing: Bool) -> OCTMessageAbstract { + let message = OCTMessageAbstract() + if !outgoing { + let friend = chat.friends.firstObject() as! OCTFriend + message.senderUniqueIdentifier = friend.uniqueIdentifier + } + message.chatUniqueIdentifier = chat.uniqueIdentifier + message.dateInterval = Date().timeIntervalSince1970 + + realm.add(message) + chat.lastMessage = message + + return message + } +} diff --git a/Antidote/OCTSubmanagerBootstrapMock.swift b/Antidote/OCTSubmanagerBootstrapMock.swift new file mode 100644 index 0000000..3f6f943 --- /dev/null +++ b/Antidote/OCTSubmanagerBootstrapMock.swift @@ -0,0 +1,19 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +class OCTSubmanagerBootstrapMock: NSObject, OCTSubmanagerBootstrap { + func addNode(withIpv4Host ipv4Host: String?, ipv6Host: String?, udpPort: OCTToxPort, tcpPorts: [NSNumber], publicKey: String) { + // nop + } + + func addPredefinedNodes() { + // nop + } + + func bootstrap() { + // nop + } +} diff --git a/Antidote/OCTSubmanagerCallsMock.swift b/Antidote/OCTSubmanagerCallsMock.swift new file mode 100644 index 0000000..75fad15 --- /dev/null +++ b/Antidote/OCTSubmanagerCallsMock.swift @@ -0,0 +1,50 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +class OCTSubmanagerCallsMock: NSObject, OCTSubmanagerCalls { + weak var delegate: OCTSubmanagerCallDelegate? = nil + var enableMicrophone: Bool = false + + func setup() throws { + // nop + } + + func call(to chat: OCTChat, enableAudio: Bool, enableVideo: Bool) throws -> OCTCall { + return OCTCall() + } + + func enableVideoSending(_ enable: Bool, for call: OCTCall) throws { + // nop + } + + func answer(_ call: OCTCall, enableAudio: Bool, enableVideo: Bool) throws { + // nop + } + + func send(_ control: OCTToxAVCallControl, to call: OCTCall) throws { + // nop + } + + func videoFeed() -> UIView? { + return nil + } + + func getVideoCallPreview(_ completionBlock: @escaping (CALayer?) -> Void) { + // nop + } + + func setAudioBitrate(_ bitrate: Int32, for call: OCTCall) throws { + // nop + } + + func routeAudio(toSpeaker speaker: Bool) throws { + // nop + } + + func `switch`(toCameraFront front: Bool) throws { + // nop + } +} diff --git a/Antidote/OCTSubmanagerCallsSnapshotMock.swift b/Antidote/OCTSubmanagerCallsSnapshotMock.swift new file mode 100644 index 0000000..f487783 --- /dev/null +++ b/Antidote/OCTSubmanagerCallsSnapshotMock.swift @@ -0,0 +1,50 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +class OCTSubmanagerCallsScreenshotsMock: NSObject, OCTSubmanagerCalls { + weak var delegate: OCTSubmanagerCallDelegate? = nil + var enableMicrophone: Bool = false + + func setup() throws { + // nop + } + + func callToChat(chat: OCTChat, enableAudio: Bool, enableVideo: Bool) throws -> OCTCall { + return OCTCall() + } + + func enableVideoSending(enable: Bool, forCall call: OCTCall) throws { + // nop + } + + func answerCall(call: OCTCall, enableAudio: Bool, enableVideo: Bool) throws { + // nop + } + + func sendCallControl(control: OCTToxAVCallControl, toCall call: OCTCall) throws { + // nop + } + + func videoFeed() -> UIView? { + return nil + } + + func getVideoCallPreview(completionBlock: (CALayer?) -> Void) { + // nop + } + + func setAudioBitrate(bitrate: Int32, forCall call: OCTCall) throws { + // nop + } + + func routeAudioToSpeaker(speaker: Bool) throws { + // nop + } + + func switchToCameraFront(front: Bool) throws { + // nop + } +} diff --git a/Antidote/OCTSubmanagerChatsMock.swift b/Antidote/OCTSubmanagerChatsMock.swift new file mode 100644 index 0000000..b9c9cdd --- /dev/null +++ b/Antidote/OCTSubmanagerChatsMock.swift @@ -0,0 +1,40 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +class OCTSubmanagerChatsMock: NSObject, OCTSubmanagerChats { + func getOrCreateChat(with friend: OCTFriend!) -> OCTChat! { + return OCTChat() + } + + func sendOwnPush() { + // nop + } + + func removeMessages(_ messages: [OCTMessageAbstract]!) { + // nop + } + + func removeAllMessages(in chat: OCTChat!, removeChat: Bool) { + // nop + } + + public func sendMessagePush(to chat: OCTChat!) + { + // nop + } + + public func sendMessage(to chat: OCTChat!, + text: String!, + type: OCTToxMessageType, + successBlock userSuccessBlock: ((OCTMessageAbstract?) -> Void)!, + failureBlock userFailureBlock: ((Error?) -> Void)!) { + // nop + } + + func setIsTyping(_ isTyping: Bool, in chat: OCTChat!) throws { + // nop + } +} diff --git a/Antidote/OCTSubmanagerFilesMock.swift b/Antidote/OCTSubmanagerFilesMock.swift new file mode 100644 index 0000000..373edd1 --- /dev/null +++ b/Antidote/OCTSubmanagerFilesMock.swift @@ -0,0 +1,39 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +class OCTSubmanagerFilesMock: NSObject, OCTSubmanagerFiles { + func send(_ data: Data, withFileName fileName: String, to chat: OCTChat, failureBlock: ((Error) -> Void)? = nil) { + // nop + } + + func sendFile(atPath filePath: String, moveToUploads: Bool, to chat: OCTChat, failureBlock: ((Error) -> Void)? = nil) { + // nop + } + + func acceptFileTransfer(_ message: OCTMessageAbstract, failureBlock: ((Error) -> Void)? = nil) { + // nop + } + + func cancelFileTransfer(_ message: OCTMessageAbstract) throws { + // nop + } + + func retrySendingFile(_ message: OCTMessageAbstract, failureBlock: ((Error) -> Void)? = nil) { + // nop + } + + func pauseFileTransfer(_ pause: Bool, message: OCTMessageAbstract) throws { + // nop + } + + func add(_ subscriber: OCTSubmanagerFilesProgressSubscriber, forFileTransfer message: OCTMessageAbstract) throws { + // nop + } + + func remove(_ subscriber: OCTSubmanagerFilesProgressSubscriber, forFileTransfer message: OCTMessageAbstract) throws { + // nop + } +} diff --git a/Antidote/OCTSubmanagerFriendsMock.swift b/Antidote/OCTSubmanagerFriendsMock.swift new file mode 100644 index 0000000..c598d7e --- /dev/null +++ b/Antidote/OCTSubmanagerFriendsMock.swift @@ -0,0 +1,23 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +class OCTSubmanagerFriendsMock: NSObject, OCTSubmanagerFriends { + func sendFriendRequest(toAddress address: String!, message: String!) throws { + // nop + } + + func approve(_ friendRequest: OCTFriendRequest!) throws { + // nop + } + + func remove(_ friendRequest: OCTFriendRequest!) { + // nop + } + + func remove(_ friend: OCTFriend!) throws { + // nop + } +} diff --git a/Antidote/OCTSubmanagerObjectsExtension.swift b/Antidote/OCTSubmanagerObjectsExtension.swift new file mode 100644 index 0000000..987d574 --- /dev/null +++ b/Antidote/OCTSubmanagerObjectsExtension.swift @@ -0,0 +1,77 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +extension OCTSubmanagerObjects { + func friends(predicate: NSPredicate? = nil) -> Results { + let rlmResults = objects(for: .friend, predicate: predicate)! + return Results(results: rlmResults) + } + + func friendRequests(predicate: NSPredicate? = nil) -> Results { + let rlmResults = objects(for: .friendRequest, predicate: predicate)! + return Results(results: rlmResults) + } + + func chats(predicate: NSPredicate? = nil) -> Results { + let rlmResults = objects(for: .chat, predicate: predicate)! + return Results(results: rlmResults) + } + + func calls(predicate: NSPredicate? = nil) -> Results { + let rlmResults = objects(for: .call, predicate: predicate)! + return Results(results: rlmResults) + } + + func messages(predicate: NSPredicate? = nil) -> Results { + let rlmResults = objects(for: .messageAbstract, predicate: predicate)! + return Results(results: rlmResults) + } + + func getProfileSettings() -> ProfileSettings { + guard let data = self.genericSettingsData else { + return ProfileSettings() + } + + let unarchiver = NSKeyedUnarchiver(forReadingWith: data) + let settings = ProfileSettings(coder: unarchiver) + unarchiver.finishDecoding() + + return settings + } + + func saveProfileSettings(_ settings: ProfileSettings) { + let data = NSMutableData() + let archiver = NSKeyedArchiver(forWritingWith: data) + + settings.encode(with: archiver) + archiver.finishEncoding() + + self.genericSettingsData = data.copy() as! Data + } + + func notificationBlock(for object: T, + _ block: @escaping (ResultsChange) -> Void) -> RLMNotificationToken { + let predicate = NSPredicate(format: "uniqueIdentifier == %@", object.uniqueIdentifier) + let results: Results + + switch object { + case is OCTFriend: + results = Results(results: objects(for: .friend, predicate: predicate)!) + case is OCTFriendRequest: + results = Results(results: objects(for: .friendRequest, predicate: predicate)!) + case is OCTChat: + results = Results(results: objects(for: .chat, predicate: predicate)!) + case is OCTCall: + results = Results(results: objects(for: .call, predicate: predicate)!) + case is OCTMessageAbstract: + results = Results(results: objects(for: .messageAbstract, predicate: predicate)!) + default: + fatalError("OCT type not handled properly") + } + + return results.addNotificationBlock(block) + } +} diff --git a/Antidote/OCTSubmanagerObjectsMock.swift b/Antidote/OCTSubmanagerObjectsMock.swift new file mode 100644 index 0000000..72039a5 --- /dev/null +++ b/Antidote/OCTSubmanagerObjectsMock.swift @@ -0,0 +1,58 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +class OCTSubmanagerObjectsMock: NSObject, OCTSubmanagerObjects { + var genericSettingsData: Data? = nil + let realm: RLMRealm + + init(realm: RLMRealm) { + self.realm = realm + + super.init() + } + + func objects(for type: OCTFetchRequestType, predicate: NSPredicate!) -> RLMResults! { + switch type { + case .friend: + return OCTFriend.objects(in: realm, with: predicate) + case .friendRequest: + return OCTFriendRequest.objects(in: realm, with: predicate) + case .chat: + return OCTChat.objects(in: realm, with: predicate) + case .call: + return OCTCall.objects(in: realm, with: predicate) + case .messageAbstract: + return OCTMessageAbstract.objects(in: realm, with: predicate) + } + } + + func object(withUniqueIdentifier uniqueIdentifier: String!, for type: OCTFetchRequestType) -> OCTObject! { + switch type { + case .friend: + return OCTFriend.object(in: realm, forPrimaryKey: uniqueIdentifier) + case .friendRequest: + return OCTFriendRequest.object(in: realm, forPrimaryKey: uniqueIdentifier) + case .chat: + return OCTChat.object(in: realm, forPrimaryKey: uniqueIdentifier) + case .call: + return OCTCall.object(in: realm, forPrimaryKey: uniqueIdentifier) + case .messageAbstract: + return OCTMessageAbstract.object(in: realm, forPrimaryKey: uniqueIdentifier) + } + } + + func change(_ friend: OCTFriend!, nickname: String!) { + // nop + } + + func change(_ chat: OCTChat!, enteredText: String!) { + // nop + } + + func change(_ chat: OCTChat!, lastReadDateInterval: TimeInterval) { + // nop + } +} diff --git a/Antidote/OCTSubmanagerUserMock.swift b/Antidote/OCTSubmanagerUserMock.swift new file mode 100644 index 0000000..5fd26de --- /dev/null +++ b/Antidote/OCTSubmanagerUserMock.swift @@ -0,0 +1,48 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +class OCTSubmanagerUserMock: NSObject, OCTSubmanagerUser { + weak var delegate: OCTSubmanagerUserDelegate? = nil + var connectionStatus: OCTToxConnectionStatus = .TCP + var userAddress: String = "123" + var publicKey: String = "123" + var nospam: OCTToxNoSpam = 123 + var userStatus: OCTToxUserStatus = .none + var capabilities: OCTToxCapabilities = 0 + + override init() { + super.init() + + let delayTime = DispatchTime.now() + Double(Int64(2.0 * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC) + DispatchQueue.main.asyncAfter(deadline: delayTime) { [weak self] in + self?.delegate?.submanagerUser(self!, connectionStatusUpdate: self!.connectionStatus) + } + } + + func setUserName(_ name: String?) throws { + // nop + } + + func userName() -> String? { + return nil + } + + func setUserStatusMessage(_ statusMessage: String?) throws { + // nop + } + + func userStatusMessage() -> String? { + return nil + } + + func setUserAvatar(_ avatar: Data?) throws { + // nop + } + + func userAvatar() -> Data? { + return nil + } +} diff --git a/Antidote/PinAuthorizationCoordinator.swift b/Antidote/PinAuthorizationCoordinator.swift new file mode 100644 index 0000000..4a2239d --- /dev/null +++ b/Antidote/PinAuthorizationCoordinator.swift @@ -0,0 +1,241 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation +import AudioToolbox +import LocalAuthentication + +fileprivate struct Constants { + static let pinAttemptsNumber = 10 +} + +protocol PinAuthorizationCoordinatorDelegate: class { + func pinAuthorizationCoordinatorDidLogout(_ coordinator: PinAuthorizationCoordinator) +} + +class PinAuthorizationCoordinator: NSObject { + weak var delegate: PinAuthorizationCoordinatorDelegate? + + fileprivate enum State { + case unlocked + case locked(lockTime: CFTimeInterval) + case validatingPin + } + + fileprivate let theme: Theme + fileprivate let window: UIWindow + + fileprivate weak var submanagerObjects: OCTSubmanagerObjects! + + fileprivate var state: State + + var preventFromLocking: Bool = false { + didSet { + if !preventFromLocking && UIApplication.shared.applicationState != .active { + // In case if locking option change in background we want to lock app when user comes back. + lockIfNeeded(CACurrentMediaTime()) + } + } + } + + init(theme: Theme, submanagerObjects: OCTSubmanagerObjects, lockOnStartup: Bool) { + self.theme = theme + self.window = UIWindow(frame: UIScreen.main.bounds) + self.submanagerObjects = submanagerObjects + self.state = .unlocked + + super.init() + + // Showing window on top of all other windows. + window.windowLevel = UIWindowLevelStatusBar + 1000 + + if lockOnStartup { + lockIfNeeded(0) + } + + NotificationCenter.default.addObserver(self, + selector: #selector(PinAuthorizationCoordinator.appWillResignActiveNotification), + name: NSNotification.Name.UIApplicationWillResignActive, + object: nil) + + NotificationCenter.default.addObserver(self, + selector: #selector(PinAuthorizationCoordinator.appDidBecomeActiveNotification), + name: NSNotification.Name.UIApplicationDidBecomeActive, + object: nil) + } + + deinit { + NotificationCenter.default.removeObserver(self) + } + + @objc func appWillResignActiveNotification() { + lockIfNeeded(CACurrentMediaTime()) + } + + @objc func appDidBecomeActiveNotification() { + switch state { + case .unlocked: + // unlocked, nothing to do here + break + case .locked(let lockTime): + isPinDateExpired(lockTime) ? challengeUserToAuthorize(lockTime) : unlock() + case .validatingPin: + // checking pin, no action required + break + } + } +} + +extension PinAuthorizationCoordinator: CoordinatorProtocol { + func startWithOptions(_ options: CoordinatorOptions?) { + switch state { + case .locked(let lockTime): + challengeUserToAuthorize(lockTime) + case .unlocked: + // ignore + break + case .validatingPin: + // ignore + break + } + } +} + +extension PinAuthorizationCoordinator: EnterPinControllerDelegate { + func enterPinController(_ controller: EnterPinController, successWithPin pin: String) { + unlock() + } + + func enterPinControllerFailure(_ controller: EnterPinController) { + let keychainManager = KeychainManager() + + var failedAttempts = keychainManager.failedPinAttemptsNumber ?? 0 + failedAttempts += 1 + + keychainManager.failedPinAttemptsNumber = failedAttempts + + guard failedAttempts < Constants.pinAttemptsNumber else { + keychainManager.failedPinAttemptsNumber = nil + handleErrorWithType(.pinLogOut) + + delegate?.pinAuthorizationCoordinatorDidLogout(self) + return + } + + controller.resetEnteredPin() + controller.topText = String(localized: "pin_incorrect") + controller.descriptionText = String(localized: "pin_failed_attempts", "\(failedAttempts)") + AudioServicesPlayAlertSound(SystemSoundID(kSystemSoundID_Vibrate)) + } +} + +private extension PinAuthorizationCoordinator { + func lockIfNeeded(_ lockTime: CFTimeInterval) { + guard submanagerObjects.getProfileSettings().unlockPinCode != nil else { + return + } + + if preventFromLocking { + return + } + + for window in UIApplication.shared.windows { + window.endEditing(true) + } + + let storyboard = UIStoryboard(name: "LaunchPlaceholderBoard", bundle: Bundle.main) + window.rootViewController = storyboard.instantiateViewController(withIdentifier: "LaunchPlaceholderController") + window.isHidden = false + + switch state { + case .unlocked: + state = .locked(lockTime: lockTime) + case .locked: + // In case of Locked state don't want to update lockTime. + break + case .validatingPin: + // In case of ValidatingPin state we also don't want to do anything. + break + } + } + + func unlock() { + KeychainManager().failedPinAttemptsNumber = nil + + state = .unlocked + window.isHidden = true + } + + func challengeUserToAuthorize(_ lockTime: CFTimeInterval) { + if window.rootViewController is EnterPinController { + // already showing pin controller + return + } + + if shouldUseTouchID() { + state = .validatingPin + + LAContext().evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, + localizedReason: String(localized: "pin_touch_id_description"), + reply: { [weak self] success, error in + DispatchQueue.main.async { + self?.state = .locked(lockTime: lockTime) + + success ? self?.unlock() : self?.showValidatePinController() + } + }) + } + else { + showValidatePinController() + } + } + + func showValidatePinController() { + let settings = submanagerObjects.getProfileSettings() + guard let pin = settings.unlockPinCode else { + fatalError("pin shouldn't be nil") + } + + let failedAttempts = KeychainManager().failedPinAttemptsNumber ?? 0 + + let controller = EnterPinController(theme: theme, state: .validatePin(validPin: pin)) + controller.topText = String(localized: "pin_enter_to_unlock") + controller.descriptionText = + failedAttempts > 0 ? + String(localized: "pin_failed_attempts", "\(failedAttempts)") : + nil + controller.delegate = self + window.rootViewController = controller + } + + func isPinDateExpired(_ lockTime: CFTimeInterval) -> Bool { + let settings = submanagerObjects.getProfileSettings() + let delta = CACurrentMediaTime() - lockTime + + switch settings.lockTimeout { + case .Immediately: + return true + case .Seconds30: + return delta > 30 + case .Minute1: + return delta > 60 + case .Minute2: + return delta > (60 * 2) + case .Minute5: + return delta > (60 * 5) + } + } + + func shouldUseTouchID() -> Bool { + guard submanagerObjects.getProfileSettings().useTouchID else { + return false + } + + guard LAContext().canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: nil) else { + return false + } + + return true + } +} diff --git a/Antidote/PinInputView.swift b/Antidote/PinInputView.swift new file mode 100644 index 0000000..0a2c772 --- /dev/null +++ b/Antidote/PinInputView.swift @@ -0,0 +1,353 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +private struct Constants { + static let DotsSize: CGFloat = 16 + static let ButtonSize: CGFloat = 75 + static let VerticalOffsetSmall: CGFloat = 12 + static let VerticalOffsetBig: CGFloat = 17 + static let HorizontalOffset: CGFloat = 17 +} + +protocol PinInputViewDelegate: class { + func pinInputView(_ view: PinInputView, numericButtonPressed i: Int) + func pinInputViewDeleteButtonPressed(_ view: PinInputView) +} + +class PinInputView: UIView { + weak var delegate: PinInputViewDelegate? + + /// Entered numbers. Must be in 0...pinLength range. + var enteredNumbersCount: Int = 0 { + didSet { + enteredNumbersCount = max(enteredNumbersCount, 0) + enteredNumbersCount = min(enteredNumbersCount, pinLength) + + updateDotsImages() + } + } + + var topText: String { + get { + return topLabel.text! + } + set { + topLabel.text = newValue + } + } + + var descriptionText: String? { + get { + return descriptionLabel.text + } + set { + descriptionLabel.text = newValue + } + } + + fileprivate let pinLength: Int + + fileprivate let topColorComponents: (red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) + fileprivate let bottomColorComponents: (red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) + + fileprivate var topLabel: UILabel! + fileprivate var descriptionLabel: UILabel! + fileprivate var dotsContainer: UIView! + fileprivate var dotsImageViews = [UIImageView]() + fileprivate var numericButtons = [UIButton]() + fileprivate var deleteButton: UIButton! + + init(pinLength: Int, topColor: UIColor, bottomColor: UIColor) { + self.pinLength = pinLength + self.topColorComponents = topColor.components() + self.bottomColorComponents = bottomColor.components() + + super.init(frame: CGRect.zero) + + createLabels() + createDotsImageViews() + createNumericButtons() + createDeleteButton() + + installConstraints() + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + /** + Applies gradient colors to all subviews. + Call this method after adding PinInputView to superview. + */ + func applyColors() { + guard superview != nil else { + fatalError("superview shouldn't be nil") + } + + layoutIfNeeded() + updateButtonColors() + updateOtherColors() + + updateDotsImages() + } +} + +extension PinInputView { + @objc func numericButtonPressed(_ button: UIButton) { + guard let i = numericButtons.index(of: button) else { + return + } + + delegate?.pinInputView(self, numericButtonPressed: i) + } + + @objc func deleteButtonPressed(_ button: UIButton) { + delegate?.pinInputViewDeleteButtonPressed(self) + } +} + +private extension PinInputView { + func createLabels() { + topLabel = UILabel() + topLabel.font = UIFont.antidoteFontWithSize(18.0, weight: .medium) + addSubview(topLabel) + + descriptionLabel = UILabel() + descriptionLabel.font = UIFont.antidoteFontWithSize(16.0, weight: .light) + addSubview(descriptionLabel) + } + + func createDotsImageViews() { + for _ in 0.. UIColor { + guard self.frame.size.height > 0 else { + log("PinInputView should not be nil") + return .clear + } + + guard y >= 0 && y <= self.frame.size.height else { + log("Point y \(y) is outside of view") + return .clear + } + + let percent = y / self.frame.size.height + + let red = topColorComponents.red + percent * (bottomColorComponents.red - topColorComponents.red) + let green = topColorComponents.green + percent * (bottomColorComponents.green - topColorComponents.green) + let blue = topColorComponents.blue + percent * (bottomColorComponents.blue - topColorComponents.blue) + let alpha = topColorComponents.alpha + percent * (bottomColorComponents.alpha - topColorComponents.alpha) + + return UIColor(red: red, green: green, blue: blue, alpha: alpha) + } + + func gradientCircleImage(topColor: UIColor, bottomColor: UIColor, size: CGFloat, filled: Bool) -> UIImage { + let radius = size * UIScreen.main.scale / 2 + + let gradientLayer = CAGradientLayer() + gradientLayer.frame.size.width = 2 * radius + gradientLayer.frame.size.height = 2 * radius + gradientLayer.colors = [topColor.cgColor, bottomColor.cgColor] + gradientLayer.masksToBounds = true + gradientLayer.cornerRadius = radius + + if !filled { + // apply mask + let lineWidth: CGFloat = 2.0 + + let path = UIBezierPath() + path.addArc(withCenter: CGPoint(x: radius, y: radius), + radius: radius - lineWidth, + startAngle: 0.0, + endAngle: CGFloat(2 * Double.pi), + clockwise: true) + + let mask = CAShapeLayer() + mask.frame = gradientLayer.frame + mask.path = path.cgPath + mask.lineWidth = lineWidth + mask.fillColor = UIColor.clear.cgColor + mask.strokeColor = UIColor.black.cgColor + + gradientLayer.mask = mask + } + + UIGraphicsBeginImageContext(gradientLayer.bounds.size) + gradientLayer.render(in: UIGraphicsGetCurrentContext()!) + let image = UIGraphicsGetImageFromCurrentImageContext() + UIGraphicsEndImageContext() + return image! + } +} diff --git a/Antidote/PortraitNavigationController.swift b/Antidote/PortraitNavigationController.swift new file mode 100644 index 0000000..0552bd2 --- /dev/null +++ b/Antidote/PortraitNavigationController.swift @@ -0,0 +1,15 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit + +class PortraitNavigationController: UINavigationController { + override var shouldAutorotate : Bool { + return false + } + + override var supportedInterfaceOrientations : UIInterfaceOrientationMask { + return UIInterfaceOrientationMask.portrait + } +} diff --git a/Antidote/PrimaryIpadController.swift b/Antidote/PrimaryIpadController.swift new file mode 100644 index 0000000..0aaa1a7 --- /dev/null +++ b/Antidote/PrimaryIpadController.swift @@ -0,0 +1,160 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +protocol PrimaryIpadControllerDelegate: class { + func primaryIpadController(_ controller: PrimaryIpadController, didSelectChat chat: OCTChat) + func primaryIpadControllerShowFriends(_ controller: PrimaryIpadController) + func primaryIpadControllerShowSettings(_ controller: PrimaryIpadController) + func primaryIpadControllerShowProfile(_ controller: PrimaryIpadController) +} + +/** + Controller for the iPad that is displayed as primary split controller + */ +class PrimaryIpadController: UIViewController { + weak var delegate: PrimaryIpadControllerDelegate? + + var userStatus: UserStatus = .offline { + didSet { + navigationView.avatarView.userStatusView.userStatus = userStatus + } + } + + var userAvatar: UIImage? { + didSet { + if let image = userAvatar { + navigationView.avatarView.imageView.image = image + } + else { + navigationView.avatarView.imageView.image = UIImage.templateNamed("tab-bar-profile") + } + } + } + + var userName: String? { + didSet { + navigationView.label.text = userName + } + } + + var friendsBadgeText: String? { + didSet { + friendsButton.badgeText = friendsBadgeText + } + } + + fileprivate let theme: Theme + fileprivate weak var submanagerChats: OCTSubmanagerChats! + fileprivate weak var submanagerObjects: OCTSubmanagerObjects! + + fileprivate var navigationView: iPadNavigationView! + fileprivate var friendsButton: iPadFriendsButton! + + fileprivate var tableManager: ChatListTableManager! + + init(theme: Theme, submanagerChats: OCTSubmanagerChats, submanagerObjects: OCTSubmanagerObjects) { + self.theme = theme + self.submanagerChats = submanagerChats + self.submanagerObjects = submanagerObjects + + super.init(nibName: nil, bundle: nil) + + addNavigationButtons() + + edgesForExtendedLayout = UIRectEdge() + friendsButton = iPadFriendsButton(theme: theme) + } + + required convenience init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func loadView() { + loadViewWithBackgroundColor(theme.colorForType(.NormalBackground)) + + setupButtons() + createTableView() + installConstraints() + } +} + +// MARK: Actions +extension PrimaryIpadController { + func friendsButtonPressed() { + delegate?.primaryIpadControllerShowFriends(self) + } + + @objc func settingsButtonPressed() { + delegate?.primaryIpadControllerShowSettings(self) + } + + func profileButtonPressed() { + delegate?.primaryIpadControllerShowProfile(self) + } +} + +extension PrimaryIpadController: ChatListTableManagerDelegate { + func chatListTableManager(_ manager: ChatListTableManager, didSelectChat chat: OCTChat) { + delegate?.primaryIpadController(self, didSelectChat: chat) + } + + func chatListTableManager(_ manager: ChatListTableManager, presentAlertController controller: UIAlertController) { + present(controller, animated: true, completion: nil) + } + + func chatListTableManagerWasUpdated(_ manager: ChatListTableManager) { + // nope + } +} + +private extension PrimaryIpadController { + func addNavigationButtons() { + // none for now + navigationView = iPadNavigationView(theme: theme) + navigationView.didTapHandler = profileButtonPressed + navigationItem.leftBarButtonItem = UIBarButtonItem(customView: navigationView) + + navigationItem.rightBarButtonItem = UIBarButtonItem( + image: UIImage(named: "tab-bar-settings"), + style: .plain, + target: self, + action: #selector(PrimaryIpadController.settingsButtonPressed)) + } + + func setupButtons() { + friendsButton.didTapHandler = friendsButtonPressed + view.addSubview(friendsButton) + } + + func createTableView() { + let tableView = UITableView() + tableView.estimatedRowHeight = 44.0 + tableView.backgroundColor = theme.colorForType(.NormalBackground) + tableView.sectionIndexColor = theme.colorForType(.LinkText) + // removing separators on empty lines + tableView.tableFooterView = UIView() + + view.addSubview(tableView) + + tableView.register(ChatListCell.self, forCellReuseIdentifier: ChatListCell.staticReuseIdentifier) + + tableManager = ChatListTableManager(theme: theme, tableView: tableView, submanagerChats: submanagerChats, submanagerObjects: submanagerObjects) + tableManager.delegate = self + } + + func installConstraints() { + friendsButton.snp.makeConstraints { + $0.top.equalTo(view) + $0.leading.trailing.equalTo(view) + $0.height.equalTo(60.0) + } + + tableManager.tableView.snp.makeConstraints { + $0.top.equalTo(friendsButton.snp.bottom) + $0.leading.trailing.bottom.equalTo(view) + } + } +} diff --git a/Antidote/ProfileDetailsController.swift b/Antidote/ProfileDetailsController.swift new file mode 100644 index 0000000..6b03507 --- /dev/null +++ b/Antidote/ProfileDetailsController.swift @@ -0,0 +1,200 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit +import LocalAuthentication + +protocol ProfileDetailsControllerDelegate: class { + func profileDetailsControllerSetPin(_ controller: ProfileDetailsController) + func profileDetailsControllerChangeLockTimeout(_ controller: ProfileDetailsController) + func profileDetailsControllerChangePassword(_ controller: ProfileDetailsController) + func profileDetailsControllerDeleteProfile(_ controller: ProfileDetailsController) +} + +class ProfileDetailsController: StaticTableController { + weak var delegate: ProfileDetailsControllerDelegate? + + fileprivate weak var toxManager: OCTManager! + + fileprivate let pinEnabledModel = StaticTableSwitchCellModel() + fileprivate let lockTimeoutModel = StaticTableInfoCellModel() + fileprivate let touchIdEnabledModel = StaticTableSwitchCellModel() + + fileprivate let changePasswordModel = StaticTableButtonCellModel() + fileprivate let exportProfileModel = StaticTableButtonCellModel() + fileprivate let deleteProfileModel = StaticTableButtonCellModel() + + fileprivate var documentInteractionController: UIDocumentInteractionController? + + init(theme: Theme, toxManager: OCTManager) { + self.toxManager = toxManager + + var model = [[StaticTableBaseCellModel]]() + var footers = [String?]() + + model.append([pinEnabledModel, lockTimeoutModel]) + footers.append(String(localized: "pin_description")) + + if LAContext().canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: nil) { + model.append([touchIdEnabledModel]) + footers.append(String(localized: "pin_touch_id_description")) + } + + model.append([changePasswordModel]) + footers.append(nil) + + model.append([exportProfileModel, deleteProfileModel]) + footers.append(nil) + + super.init(theme: theme, style: .grouped, model: model, footers: footers) + + updateModel() + + title = String(localized: "profile_details") + } + + required convenience init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + updateModel() + reloadTableView() + } +} + +extension ProfileDetailsController: UIDocumentInteractionControllerDelegate { + func documentInteractionControllerViewControllerForPreview(_ controller: UIDocumentInteractionController) -> UIViewController { + return self + } + + func documentInteractionControllerViewForPreview(_ controller: UIDocumentInteractionController) -> UIView? { + return view + } + + func documentInteractionControllerRectForPreview(_ controller: UIDocumentInteractionController) -> CGRect { + return view.frame + } +} + +private extension ProfileDetailsController { + func updateModel() { + let settings = toxManager.objects.getProfileSettings() + let isPinEnabled = settings.unlockPinCode != nil + + pinEnabledModel.title = String(localized: "pin_enabled") + pinEnabledModel.on = isPinEnabled + pinEnabledModel.valueChangedHandler = pinEnabledValueChanged + + lockTimeoutModel.title = String(localized: "pin_lock_timeout") + lockTimeoutModel.showArrow = true + lockTimeoutModel.didSelectHandler = changeLockTimeout + + switch settings.lockTimeout { + case .Immediately: + lockTimeoutModel.value = String(localized: "pin_lock_immediately") + case .Seconds30: + lockTimeoutModel.value = String(localized: "pin_lock_30_seconds") + case .Minute1: + lockTimeoutModel.value = String(localized: "pin_lock_1_minute") + case .Minute2: + lockTimeoutModel.value = String(localized: "pin_lock_2_minutes") + case .Minute5: + lockTimeoutModel.value = String(localized: "pin_lock_5_minutes") + } + + touchIdEnabledModel.enabled = isPinEnabled + touchIdEnabledModel.title = String(localized: "pin_touch_id_enabled") + touchIdEnabledModel.on = settings.useTouchID + touchIdEnabledModel.valueChangedHandler = touchIdEnabledValueChanged + + changePasswordModel.title = String(localized: "change_password") + changePasswordModel.didSelectHandler = changePassword + + exportProfileModel.title = String(localized: "export_profile") + exportProfileModel.didSelectHandler = exportProfile + + deleteProfileModel.title = String(localized: "delete_profile") + deleteProfileModel.didSelectHandler = deleteProfile + } + + func pinEnabledValueChanged(_ on: Bool) { + if on { + delegate?.profileDetailsControllerSetPin(self) + } + else { + let settings = toxManager.objects.getProfileSettings() + settings.unlockPinCode = nil + toxManager.objects.saveProfileSettings(settings) + } + + updateModel() + reloadTableView() + } + + func changeLockTimeout(_: StaticTableBaseCell) { + delegate?.profileDetailsControllerChangeLockTimeout(self) + } + + func touchIdEnabledValueChanged(_ on: Bool) { + let settings = toxManager.objects.getProfileSettings() + settings.useTouchID = on + toxManager.objects.saveProfileSettings(settings) + } + + func changePassword(_: StaticTableBaseCell) { + delegate?.profileDetailsControllerChangePassword(self) + } + + func exportProfile(_: StaticTableBaseCell) { + do { + let path = try toxManager.exportToxSaveFile() + + let name = UserDefaultsManager().lastActiveProfile ?? "profile" + + documentInteractionController = UIDocumentInteractionController(url: URL(fileURLWithPath: path)) + documentInteractionController!.delegate = self + documentInteractionController!.name = "\(name).tox" + documentInteractionController!.presentOptionsMenu(from: view.frame, in:view, animated: true) + } + catch let error as NSError { + handleErrorWithType(.exportProfile, error: error) + } + } + + func deleteProfile(_ cell: StaticTableBaseCell) { + let title1 = String(localized: "delete_profile_confirmation_title_1") + let title2 = String(localized: "delete_profile_confirmation_title_2") + let message = String(localized: "delete_profile_confirmation_message") + let yes = String(localized: "alert_delete") + let cancel = String(localized: "alert_cancel") + + let alert1 = UIAlertController(title: title1, message: message, preferredStyle: .actionSheet) + alert1.popoverPresentationController?.sourceView = cell + alert1.popoverPresentationController?.sourceRect = CGRect(x: cell.frame.size.width / 2, y: cell.frame.size.height / 2, width: 1.0, height: 1.0) + + alert1.addAction(UIAlertAction(title: yes, style: .destructive) { [unowned self] _ -> Void in + let alert2 = UIAlertController(title: title2, message: nil, preferredStyle: .actionSheet) + alert2.popoverPresentationController?.sourceView = cell + alert2.popoverPresentationController?.sourceRect = CGRect(x: cell.frame.size.width / 2, y: cell.frame.size.height / 2, width: 1.0, height: 1.0) + + alert2.addAction(UIAlertAction(title: yes, style: .destructive) { [unowned self] _ -> Void in + self.reallyDeleteProfile() + }) + alert2.addAction(UIAlertAction(title: cancel, style: .cancel, handler: nil)) + + self.present(alert2, animated: true, completion: nil) + }) + + alert1.addAction(UIAlertAction(title: cancel, style: .cancel, handler: nil)) + + present(alert1, animated: true, completion: nil) + } + + func reallyDeleteProfile() { + delegate?.profileDetailsControllerDeleteProfile(self) + } +} diff --git a/Antidote/ProfileMainController.swift b/Antidote/ProfileMainController.swift new file mode 100644 index 0000000..44e2377 --- /dev/null +++ b/Antidote/ProfileMainController.swift @@ -0,0 +1,322 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit +import Firebase + +protocol ProfileMainControllerDelegate: class { + func profileMainControllerLogout(_ controller: ProfileMainController) + func profileMainControllerChangeUserName(_ controller: ProfileMainController) + func profileMainControllerChangeUserStatus(_ controller: ProfileMainController) + func profileMainControllerChangeStatusMessage(_ controller: ProfileMainController) + func profileMainController(_ controller: ProfileMainController, showQRCodeWithText text: String) + func profileMainControllerShowProfileDetails(_ controller: ProfileMainController) + func profileMainControllerDidChangeAvatar(_ controller: ProfileMainController) +} + +class ProfileMainController: StaticTableController { + weak var delegate: ProfileMainControllerDelegate? + + fileprivate weak var submanagerUser: OCTSubmanagerUser! + fileprivate let avatarManager: AvatarManager + + fileprivate let avatarModel = StaticTableAvatarCellModel() + fileprivate let userNameModel = StaticTableDefaultCellModel() + fileprivate let statusMessageModel = StaticTableDefaultCellModel() + // fileprivate let userStatusModel = StaticTableDefaultCellModel() + fileprivate let toxIdModel = StaticTableDefaultCellModel() + fileprivate let pushurlModel = StaticTableDefaultCellModel() + fileprivate let capabilitiesModel = StaticTableDefaultCellModel() + fileprivate let profileDetailsModel = StaticTableDefaultCellModel() + fileprivate let logoutModel = StaticTableButtonCellModel() + + init(theme: Theme, submanagerUser: OCTSubmanagerUser) { + self.submanagerUser = submanagerUser + + avatarManager = AvatarManager(theme: theme) + + super.init(theme: theme, style: .plain, model: [ + [ + avatarModel, + ], + [ + userNameModel, + statusMessageModel, + ], + //[ + // userStatusModel, + //], + [ + toxIdModel, + ], + [ + pushurlModel, + ], + [ + capabilitiesModel, + ], + [ + profileDetailsModel, + ], + [ + logoutModel, + ], + ]) + + updateModels() + + title = String(localized: "profile_title") + } + + required convenience init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + updateModels() + reloadTableView() + } +} + +extension ProfileMainController: UIImagePickerControllerDelegate { + func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) { + dismiss(animated: true, completion: nil) + + guard var image = info[UIImagePickerControllerOriginalImage] as? UIImage else { + return + } + + if image.size.width != image.size.height { + let side = min(image.size.width, image.size.height) + let x = (image.size.width - side) / 2 + let y = (image.size.height - side) / 2 + let rect = CGRect(x: x, y: y, width: side, height: side) + + image = image.cropWithRect(rect) + } + + let data: Data + + do { + data = try pngDataFromImage(image) + } + catch { + handleErrorWithType(.convertImageToPNG, error: nil) + return + } + + do { + try submanagerUser.setUserAvatar(data) + updateModels() + reloadTableView() + + delegate?.profileMainControllerDidChangeAvatar(self) + } + catch let error as NSError { + handleErrorWithType(.changeAvatar, error: error) + } + } + + func imagePickerControllerDidCancel(_ picker: UIImagePickerController) { + dismiss(animated: true, completion: nil) + } +} + +extension ProfileMainController: UINavigationControllerDelegate {} + +private extension ProfileMainController { + struct PNGFromDataError: Error {} + + func updateModels() { + if let avatarData = submanagerUser.userAvatar() { + avatarModel.avatar = UIImage(data: avatarData) + } + else { + avatarModel.avatar = avatarManager.avatarFromString( + submanagerUser.userName() ?? "?", + diameter: StaticTableAvatarCellModel.Constants.AvatarImageSize) + } + avatarModel.didTapOnAvatar = performAvatarAction + + userNameModel.title = String(localized: "name") + userNameModel.value = submanagerUser.userName() + userNameModel.rightImageType = .arrow + userNameModel.didSelectHandler = changeUserName + + // Hardcoding any connected status to show only online/away/busy statuses here. + let userStatus = UserStatus(connectionStatus: OCTToxConnectionStatus.TCP, userStatus: submanagerUser.userStatus) + + // userStatusModel.userStatus = userStatus + // userStatusModel.value = userStatus.toString() + // userStatusModel.rightImageType = .arrow + // userStatusModel.didSelectHandler = changeUserStatus + + statusMessageModel.title = String(localized: "status_message") + statusMessageModel.value = submanagerUser.userStatusMessage() + statusMessageModel.rightImageType = .arrow + statusMessageModel.didSelectHandler = changeStatusMessage + + toxIdModel.title = String(localized: "my_tox_id") + toxIdModel.value = submanagerUser.userAddress + toxIdModel.rightButton = String(localized: "show_qr") + toxIdModel.rightButtonHandler = showToxIdQR + toxIdModel.userInteractionEnabled = false + toxIdModel.canCopyValue = true + // for debugging print own ToxID ---------------- + // print("TOXID: \(submanagerUser.userAddress)") + // for debugging print own ToxID ---------------- + + pushurlModel.title = "Push URL" + let pushtoken = Messaging.messaging().fcmToken ?? "" + if (pushtoken.count > 0) { + pushurlModel.value = "https://tox.zoff.xyz/toxfcm/fcm.php?id=" + pushtoken + "&type=1" + } else { + pushurlModel.value = "" + } + pushurlModel.userInteractionEnabled = false + + capabilitiesModel.title = "Tox Capabilities" + capabilitiesModel.value = capabilitiesToString(submanagerUser.capabilities as NSNumber) + capabilitiesModel.userInteractionEnabled = false + + profileDetailsModel.value = String(localized: "profile_details") + profileDetailsModel.didSelectHandler = showProfileDetails + profileDetailsModel.rightImageType = .arrow + + logoutModel.title = String(localized: "logout_button") + logoutModel.didSelectHandler = logout + } + + func capabilitiesToString(_ cap: NSNumber) -> String { + var ret: String = "BASIC" + if ((UInt(cap) & 1) > 0) { + ret = ret + " CAPABILITIES" + } + if ((UInt(cap) & 2) > 0) { + ret = ret + " MSGV2" + } + if ((UInt(cap) & 4) > 0) { + ret = ret + " H264" + } + if ((UInt(cap) & 8) > 0) { + ret = ret + " MSGV3" + } + if ((UInt(cap) & 16) > 0) { + ret = ret + " FTV2" + } + return ret; + } + + func logout(_: StaticTableBaseCell) { + delegate?.profileMainControllerLogout(self) + } + + func performAvatarAction(_ cell: StaticTableAvatarCell) { + let alert = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) + alert.popoverPresentationController?.sourceView = cell + alert.popoverPresentationController?.sourceRect = CGRect(x: cell.frame.size.width / 2, y: cell.frame.size.height / 2, width: 1.0, height: 1.0) + + if UIImagePickerController.isSourceTypeAvailable(.camera) { + alert.addAction(UIAlertAction(title: String(localized: "photo_from_camera"), style: .default) { [unowned self] _ -> Void in + let controller = UIImagePickerController() + controller.sourceType = .camera + controller.delegate = self + + if (UIImagePickerController.isCameraDeviceAvailable(.front)) { + controller.cameraDevice = .front + } + + self.present(controller, animated: true, completion: nil) + }) + } + + if UIImagePickerController.isSourceTypeAvailable(.photoLibrary) { + alert.addAction(UIAlertAction(title: String(localized: "photo_from_photo_library"), style: .default) { [unowned self] _ -> Void in + let controller = UIImagePickerController() + controller.sourceType = .photoLibrary + controller.delegate = self + self.present(controller, animated: true, completion: nil) + }) + } + + if submanagerUser.userAvatar() != nil { + alert.addAction(UIAlertAction(title: String(localized: "alert_delete"), style: .destructive) { [unowned self] _ -> Void in + self.removeAvatar() + }) + } + + alert.addAction(UIAlertAction(title: String(localized: "alert_cancel"), style: .cancel, handler: nil)) + + present(alert, animated: true, completion: nil) + } + + func removeAvatar() { + do { + try submanagerUser.setUserAvatar(nil) + updateModels() + reloadTableView() + + delegate?.profileMainControllerDidChangeAvatar(self) + } + catch let error as NSError { + handleErrorWithType(.changeAvatar, error: error) + } + } + + func pngDataFromImage(_ image: UIImage) throws -> Data { + var imageSize = image.size + + // Maximum png size will be (4 * width * height) + // * 1.5 to get as big avatar size as possible + while OCTToxFileSize(4 * imageSize.width * imageSize.height) > OCTToxFileSize(1.5 * Double(kOCTManagerMaxAvatarSize)) { + imageSize.width *= 0.9 + imageSize.height *= 0.9 + } + + imageSize.width = ceil(imageSize.width) + imageSize.height = ceil(imageSize.height) + + var data: Data + var tempImage = image + + repeat { + UIGraphicsBeginImageContext(imageSize) + tempImage.draw(in: CGRect(origin: CGPoint.zero, size: imageSize)) + tempImage = UIGraphicsGetImageFromCurrentImageContext()! + UIGraphicsEndImageContext() + + guard let theData = UIImagePNGRepresentation(tempImage) else { + throw PNGFromDataError() + } + data = theData + + imageSize.width *= 0.9 + imageSize.height *= 0.9 + } while (OCTToxFileSize(data.count) > kOCTManagerMaxAvatarSize) + + return data + } + + func changeUserName(_: StaticTableBaseCell) { + delegate?.profileMainControllerChangeUserName(self) + } + + func changeUserStatus(_: StaticTableBaseCell) { + delegate?.profileMainControllerChangeUserStatus(self) + } + + func changeStatusMessage(_: StaticTableBaseCell) { + delegate?.profileMainControllerChangeStatusMessage(self) + } + + func showToxIdQR() { + delegate?.profileMainController(self, showQRCodeWithText: submanagerUser.userAddress) + } + + func showProfileDetails(_: StaticTableBaseCell) { + delegate?.profileMainControllerShowProfileDetails(self) + } +} diff --git a/Antidote/ProfileManager.swift b/Antidote/ProfileManager.swift new file mode 100644 index 0000000..450b7ed --- /dev/null +++ b/Antidote/ProfileManager.swift @@ -0,0 +1,85 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +private struct Constants { + static let SaveDirectoryPath = "saves" + + // TODO get this constant from objcTox OCTDefaultFileStorage + static let ToxFileName = "save.tox" +} + +class ProfileManager { + fileprivate(set) var allProfileNames: [String] + + init() { + allProfileNames = [] + + reloadProfileNames() + } + + func createProfileWithName(_ name: String, copyFromURL: URL? = nil) throws { + let path = pathFromName(name) + let fileManager = FileManager.default + + try fileManager.createDirectory(atPath: path, withIntermediateDirectories: true, attributes: nil) + + if let url = copyFromURL { + let saveURL = URL(fileURLWithPath: path).appendingPathComponent(Constants.ToxFileName) + try fileManager.moveItem(at: url, to: saveURL) + } + + reloadProfileNames() + } + + func deleteProfileWithName(_ name: String) throws { + let path = pathFromName(name) + + try FileManager.default.removeItem(atPath: path) + + reloadProfileNames() + } + + func renameProfileWithName(_ fromName: String, toName: String) throws { + let fromPath = pathFromName(fromName) + let toPath = pathFromName(toName) + + try FileManager.default.moveItem(atPath: fromPath, toPath: toPath) + + reloadProfileNames() + } + + func pathForProfileWithName(_ name: String) -> String { + return pathFromName(name) + } +} + +private extension ProfileManager { + func saveDirectoryPath() -> String { + let path: NSString = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first! as NSString + return path.appendingPathComponent(Constants.SaveDirectoryPath) + } + + func pathFromName(_ name: String) -> String { + let directoryPath: NSString = saveDirectoryPath() as NSString + return directoryPath.appendingPathComponent(name) + } + + func reloadProfileNames() { + let fileManager = FileManager.default + let savePath = saveDirectoryPath() + + let contents = try? fileManager.contentsOfDirectory(atPath: savePath) + + allProfileNames = contents?.filter { + let path = (savePath as NSString).appendingPathComponent($0) + + var isDirectory: ObjCBool = false + fileManager.fileExists(atPath: path, isDirectory:&isDirectory) + + return isDirectory.boolValue + } ?? [String]() + } +} diff --git a/Antidote/ProfileSettings.swift b/Antidote/ProfileSettings.swift new file mode 100644 index 0000000..5390198 --- /dev/null +++ b/Antidote/ProfileSettings.swift @@ -0,0 +1,58 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +private struct Constants { + static let UnlockPinCodeKey = "UnlockPinCodeKey" + static let UseTouchIDKey = "UseTouchIDKey" + static let LockTimeoutKey = "LockTimeoutKey" +} + +class ProfileSettings: NSObject, NSCoding { + enum LockTimeout: String { + case Immediately + case Seconds30 + case Minute1 + case Minute2 + case Minute5 + } + + /// Pin code used to unlock device. + var unlockPinCode: String? + + /// Whether use Touch ID for unlocking Antidote. + var useTouchID: Bool + + /// Time after which Antidote will be blocked in background. + var lockTimeout: LockTimeout + + required override init() { + unlockPinCode = nil + useTouchID = false + lockTimeout = .Immediately + + super.init() + } + + required init(coder aDecoder: NSCoder) { + unlockPinCode = aDecoder.decodeObject(forKey: Constants.UnlockPinCodeKey) as? String + useTouchID = aDecoder.decodeBool(forKey: Constants.UseTouchIDKey) + + if let rawTimeout = aDecoder.decodeObject(forKey: Constants.LockTimeoutKey) as? String { + lockTimeout = LockTimeout(rawValue: rawTimeout) ?? .Immediately + } + else { + lockTimeout = .Immediately + } + + super.init() + } + + func encode(with aCoder: NSCoder) { + aCoder.encode(unlockPinCode, forKey: Constants.UnlockPinCodeKey) + aCoder.encode(useTouchID, forKey: Constants.UseTouchIDKey) + aCoder.encode(lockTimeout.rawValue, forKey: Constants.LockTimeoutKey) + } +} diff --git a/Antidote/ProfileTabCoordinator.swift b/Antidote/ProfileTabCoordinator.swift new file mode 100644 index 0000000..78bb584 --- /dev/null +++ b/Antidote/ProfileTabCoordinator.swift @@ -0,0 +1,202 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit +import AudioToolbox + +protocol ProfileTabCoordinatorDelegate: class { + func profileTabCoordinatorDelegateLogout(_ coordinator: ProfileTabCoordinator) + func profileTabCoordinatorDelegateDeleteProfile(_ coordinator: ProfileTabCoordinator) + func profileTabCoordinatorDelegateDidChangeUserStatus(_ coordinator: ProfileTabCoordinator) + func profileTabCoordinatorDelegateDidChangeAvatar(_ coordinator: ProfileTabCoordinator) + func profileTabCoordinatorDelegateDidChangeUserName(_ coordinator: ProfileTabCoordinator) +} + +class ProfileTabCoordinator: ActiveSessionNavigationCoordinator { + weak var delegate: ProfileTabCoordinatorDelegate? + + fileprivate weak var toxManager: OCTManager! + + init(theme: Theme, toxManager: OCTManager) { + self.toxManager = toxManager + + super.init(theme: theme) + } + + override func startWithOptions(_ options: CoordinatorOptions?) { + let controller = ProfileMainController(theme: theme, submanagerUser: toxManager.user) + controller.delegate = self + navigationController.pushViewController(controller, animated: false) + } +} + +extension OCTToxErrorSetInfoCode: Error { + +} + +extension ProfileTabCoordinator: ProfileMainControllerDelegate { + func profileMainControllerLogout(_ controller: ProfileMainController) { + delegate?.profileTabCoordinatorDelegateLogout(self) + } + + func profileMainControllerChangeUserName(_ controller: ProfileMainController) { + showTextEditController(title: String(localized: "name"), defaultValue: toxManager.user.userName() ?? "") { + [unowned self] newName -> Void in + + do { + try self.toxManager.user.setUserName(newName) + self.delegate?.profileTabCoordinatorDelegateDidChangeUserName(self) + } + catch let error as NSError { + handleErrorWithType(.toxSetInfoCodeName, error: error) + } + } + } + + func profileMainControllerChangeUserStatus(_ controller: ProfileMainController) { + let controller = ChangeUserStatusController(theme: theme, selectedStatus: toxManager.user.userStatus) + controller.delegate = self + navigationController.pushViewController(controller, animated: true) + } + + func profileMainControllerChangeStatusMessage(_ controller: ProfileMainController) { + showTextEditController(title: String(localized: "status_message"), defaultValue: toxManager.user.userStatusMessage() ?? "") { + newStatusMessage -> Void in + + do { + try self.toxManager.user.setUserStatusMessage(newStatusMessage) + } + catch let error as NSError { + handleErrorWithType(.toxSetInfoCodeStatusMessage, error: error) + } + } + } + + func profileMainController(_ controller: ProfileMainController, showQRCodeWithText text: String) { + let controller = QRViewerController(theme: theme, text: text) + controller.delegate = self + + let toPresent = UINavigationController(rootViewController: controller) + + navigationController.present(toPresent, animated: true, completion: nil) + } + + func profileMainControllerShowProfileDetails(_ controller: ProfileMainController) { + let controller = ProfileDetailsController(theme: theme, toxManager: toxManager) + controller.delegate = self + navigationController.pushViewController(controller, animated: true) + } + + func profileMainControllerDidChangeAvatar(_ controller: ProfileMainController) { + delegate?.profileTabCoordinatorDelegateDidChangeAvatar(self) + } +} + +extension ProfileTabCoordinator: ChangeUserStatusControllerDelegate { + func changeUserStatusController(_ controller: ChangeUserStatusController, selectedStatus: OCTToxUserStatus) { + toxManager.user.userStatus = selectedStatus + navigationController.popViewController(animated: true) + + delegate?.profileTabCoordinatorDelegateDidChangeUserStatus(self) + } +} + +extension ProfileTabCoordinator: QRViewerControllerDelegate { + func qrViewerControllerDidFinishPresenting() { + navigationController.dismiss(animated: true, completion: nil) + } +} + +extension ProfileTabCoordinator: ChangePasswordControllerDelegate { + func changePasswordControllerDidFinishPresenting(_ controller: ChangePasswordController) { + navigationController.dismiss(animated: true, completion: nil) + } +} + +extension ProfileTabCoordinator: ProfileDetailsControllerDelegate { + func profileDetailsControllerSetPin(_ controller: ProfileDetailsController) { + let controller = EnterPinController(theme: theme, state: .setPin) + controller.topText = String(localized: "pin_set") + controller.delegate = self + + let toPresent = PortraitNavigationController(rootViewController: controller) + toPresent.isNavigationBarHidden = true + navigationController.present(toPresent, animated: true, completion: nil) + } + + func profileDetailsControllerChangeLockTimeout(_ controller: ProfileDetailsController) { + let controller = ChangePinTimeoutController(theme: theme, submanagerObjects: toxManager.objects) + controller.delegate = self + navigationController.pushViewController(controller, animated: true) + } + + func profileDetailsControllerChangePassword(_ controller: ProfileDetailsController) { + let controller = ChangePasswordController(theme: theme, toxManager: toxManager) + controller.delegate = self + + let toPresent = UINavigationController(rootViewController: controller) + navigationController.present(toPresent, animated: true, completion: nil) + } + + func profileDetailsControllerDeleteProfile(_ controller: ProfileDetailsController) { + delegate?.profileTabCoordinatorDelegateDeleteProfile(self) + } +} + +extension ProfileTabCoordinator: EnterPinControllerDelegate { + func enterPinController(_ controller: EnterPinController, successWithPin pin: String) { + switch controller.state { + case .validatePin: + let settings = toxManager.objects.getProfileSettings() + settings.unlockPinCode = pin + toxManager.objects.saveProfileSettings(settings) + + navigationController.dismiss(animated: true, completion: nil) + case .setPin: + guard let presentedNavigation = controller.navigationController else { + fatalError("wrong state") + } + + let validate = EnterPinController(theme: theme, state: .validatePin(validPin: pin)) + validate.topText = String(localized: "pin_confirm") + validate.delegate = self + + presentedNavigation.viewControllers = [validate] + } + } + + func enterPinControllerFailure(_ controller: EnterPinController) { + guard let presentedNavigation = controller.navigationController else { + fatalError("wrong state") + } + + AudioServicesPlayAlertSound(SystemSoundID(kSystemSoundID_Vibrate)) + + let setPin = EnterPinController(theme: theme, state: .setPin) + setPin.topText = String(localized: "pin_do_not_match") + setPin.delegate = self + + presentedNavigation.viewControllers = [setPin] + } +} + +extension ProfileTabCoordinator: ChangePinTimeoutControllerDelegate { + func changePinTimeoutControllerDone(_ controller: ChangePinTimeoutController) { + navigationController.popViewController(animated: true) + } +} + +private extension ProfileTabCoordinator { + func showTextEditController(title: String, defaultValue: String, setValueClosure: @escaping (String) -> Void) { + let controller = TextEditController(theme: theme, title: title, defaultValue: defaultValue, changeTextHandler: { + newName -> Void in + + setValueClosure(newName) + }, userFinishedEditing: { [unowned self] in + self.navigationController.popViewController(animated: true) + }) + + navigationController.pushViewController(controller, animated: true) + } +} diff --git a/Antidote/ProgressCircleView.swift b/Antidote/ProgressCircleView.swift new file mode 100644 index 0000000..dd189c3 --- /dev/null +++ b/Antidote/ProgressCircleView.swift @@ -0,0 +1,71 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit + +private struct Constants { + static let LineWidth: CGFloat = 6.0 + static let AnimationDuration = 1.0 +} + +class ProgressCircleView: UIView { + fileprivate let backgroundLayer: CAShapeLayer + fileprivate let progressLayer: CAShapeLayer + + var backgroundLineColor: UIColor? { + didSet { + backgroundLayer.strokeColor = backgroundLineColor?.cgColor + } + } + + var lineColor: UIColor? { + didSet { + progressLayer.strokeColor = lineColor?.cgColor + } + } + + /// From 0.0 to 1.0 + var progress: CGFloat = 0.0 { + didSet { + progressLayer.strokeEnd = progress + } + } + + override init(frame: CGRect) { + backgroundLayer = CAShapeLayer() + progressLayer = CAShapeLayer() + + super.init(frame: frame) + + backgroundLayer.fillColor = UIColor.clear.cgColor + backgroundLayer.lineWidth = Constants.LineWidth + layer.addSublayer(backgroundLayer) + + progressLayer.strokeEnd = progress + progressLayer.fillColor = UIColor.clear.cgColor + progressLayer.lineWidth = Constants.LineWidth + layer.addSublayer(progressLayer) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func layoutSubviews() { + super.layoutSubviews() + + let bezierPath = UIBezierPath() + bezierPath.addArc( + withCenter: CGPoint(x: bounds.size.width / 2, y: bounds.size.height / 2), + radius: bounds.size.width / 2, + startAngle: CGFloat(-Double.pi / 2), + endAngle: CGFloat(1.5 * Double.pi), + clockwise: true) + + backgroundLayer.path = bezierPath.cgPath + backgroundLayer.frame = bounds + progressLayer.path = bezierPath.cgPath + progressLayer.frame = bounds + } +} diff --git a/Antidote/QRScannerAimView.swift b/Antidote/QRScannerAimView.swift new file mode 100644 index 0000000..81b45c4 --- /dev/null +++ b/Antidote/QRScannerAimView.swift @@ -0,0 +1,38 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit + +class QRScannerAimView: UIView { + fileprivate let dashLayer: CAShapeLayer + + init(theme: Theme) { + dashLayer = CAShapeLayer() + + super.init(frame: CGRect.zero) + + configureDashLayer(theme) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override var frame: CGRect { + didSet { + dashLayer.path = UIBezierPath(rect: bounds).cgPath + dashLayer.frame = bounds + } + } +} + +private extension QRScannerAimView { + func configureDashLayer(_ theme: Theme) { + dashLayer.strokeColor = theme.colorForType(.LinkText).cgColor + dashLayer.fillColor = UIColor.clear.cgColor + dashLayer.lineDashPattern = [20, 5] + dashLayer.lineWidth = 2.0 + layer.addSublayer(dashLayer) + } +} diff --git a/Antidote/QRScannerController.swift b/Antidote/QRScannerController.swift new file mode 100644 index 0000000..8f06351 --- /dev/null +++ b/Antidote/QRScannerController.swift @@ -0,0 +1,179 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit +import AVFoundation + +class QRScannerController: UIViewController { + var didScanStringsBlock: (([String]) -> Void)? + var cancelBlock: (() -> Void)? + + fileprivate let theme: Theme + + fileprivate var previewLayer: AVCaptureVideoPreviewLayer! + fileprivate var captureSession: AVCaptureSession! + + fileprivate var aimView: QRScannerAimView! + + var pauseScanning: Bool = false { + didSet { + pauseScanning ? captureSession.stopRunning() : captureSession.startRunning() + + if !pauseScanning { + aimView.frame = CGRect.zero + } + } + } + + init(theme: Theme) { + self.theme = theme + + super.init(nibName: nil, bundle: nil) + + createCaptureSession() + createBarButtonItems() + + NotificationCenter.default.addObserver( + self, + selector: #selector(QRScannerController.applicationDidEnterBackground), + name: NSNotification.Name.UIApplicationDidEnterBackground, + object: nil) + + NotificationCenter.default.addObserver( + self, + selector: #selector(QRScannerController.applicationWillEnterForeground), + name: NSNotification.Name.UIApplicationWillEnterForeground, + object: nil) + } + + deinit { + NotificationCenter.default.removeObserver(self) + } + + required convenience init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func loadView() { + loadViewWithBackgroundColor(theme.colorForType(.NormalBackground)) + + createViewsAndLayers() + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + captureSession.startRunning() + } + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + + captureSession.stopRunning() + } + + override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + + previewLayer.frame = view.bounds + } +} + +// MARK: Actions +extension QRScannerController { + @objc func cancelButtonPressed() { + cancelBlock?() + } +} + +// MARK: Notifications +extension QRScannerController { + @objc func applicationDidEnterBackground() { + captureSession.stopRunning() + } + + @objc func applicationWillEnterForeground() { + if !pauseScanning { + captureSession.startRunning() + } + } +} + +extension QRScannerController: AVCaptureMetadataOutputObjectsDelegate { + func metadataOutput(_ captureOutput: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) { + let readableObjects = metadataObjects.filter { + $0 is AVMetadataMachineReadableCodeObject + }.map { + previewLayer.transformedMetadataObject(for: $0 ) as! AVMetadataMachineReadableCodeObject + } + + guard !readableObjects.isEmpty else { + return + } + + aimView.frame = readableObjects[0].bounds + + let strings = readableObjects.map { + $0.stringValue! + } + + didScanStringsBlock?(strings) + } +} + +private extension QRScannerController { + func createCaptureSession() { + captureSession = AVCaptureSession() + + let input = captureSessionInput() + let output = AVCaptureMetadataOutput() + + if (input != nil) && captureSession.canAddInput(input!) { + captureSession.addInput(input!) + } + + if captureSession.canAddOutput(output) { + captureSession.addOutput(output) + + output.setMetadataObjectsDelegate(self, queue: DispatchQueue.main) + + if output.availableMetadataObjectTypes.contains({ AVMetadataObject.ObjectType.qr }()) { + output.metadataObjectTypes = [AVMetadataObject.ObjectType.qr] + } + } + } + + func captureSessionInput() -> AVCaptureDeviceInput? { + guard let device = AVCaptureDevice.default(for: AVMediaType.video) else { + return nil + } + + if device.isAutoFocusRangeRestrictionSupported { + do { + try device.lockForConfiguration() + device.autoFocusRangeRestriction = .near + device.unlockForConfiguration() + } + catch { + // nop + } + } + + return try? AVCaptureDeviceInput(device: device) + } + + func createBarButtonItems() { + navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(QRScannerController.cancelButtonPressed)) + } + + func createViewsAndLayers() { + previewLayer = AVCaptureVideoPreviewLayer(session: captureSession) + previewLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill + view.layer.addSublayer(previewLayer) + + aimView = QRScannerAimView(theme: theme) + view.addSubview(aimView) + view.bringSubview(toFront: aimView) + } +} diff --git a/Antidote/QRViewerController.swift b/Antidote/QRViewerController.swift new file mode 100644 index 0000000..be2e469 --- /dev/null +++ b/Antidote/QRViewerController.swift @@ -0,0 +1,99 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit +import SnapKit + +protocol QRViewerControllerDelegate: class { + func qrViewerControllerDidFinishPresenting() +} + +class QRViewerController: UIViewController { + weak var delegate: QRViewerControllerDelegate? + + fileprivate let theme: Theme + fileprivate let text: String + + fileprivate var previousBrightness: CGFloat = 1.0 + + fileprivate var closeButton: UIButton! + fileprivate var imageView: UIImageView! + + init(theme: Theme, text: String) { + self.theme = theme + self.text = text + + super.init(nibName: nil, bundle: nil) + + edgesForExtendedLayout = UIRectEdge() + } + + required convenience init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func loadView() { + loadViewWithBackgroundColor(theme.colorForType(.NormalBackground)) + + installNavigationItems() + createViews() + installConstraints() + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + previousBrightness = UIScreen.main.brightness + } + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + + UIScreen.main.brightness = previousBrightness + } +} + +extension QRViewerController { + @objc func closeButtonPressed() { + delegate?.qrViewerControllerDidFinishPresenting() + } +} + +private extension QRViewerController { + func installNavigationItems() { + navigationItem.rightBarButtonItem = UIBarButtonItem( + barButtonSystemItem: .done, + target: self, + action: #selector(QRViewerController.closeButtonPressed)) + } + + func createViews() { + imageView = UIImageView(image: qrImageFromText()) + imageView.contentMode = .scaleAspectFit + view.addSubview(imageView) + } + + func installConstraints() { + imageView.snp.makeConstraints { + $0.center.equalTo(view) + $0.width.lessThanOrEqualTo(view.snp.width) + $0.width.lessThanOrEqualTo(view.snp.height) + $0.width.equalTo(imageView.snp.height) + } + } + + func qrImageFromText() -> UIImage { + let filter = CIFilter(name:"CIQRCodeGenerator")! + filter.setDefaults() + filter.setValue(text.data(using: String.Encoding.utf8), forKey: "inputMessage") + + let ciImage = filter.outputImage! + let screenBounds = UIScreen.main.bounds + + let scale = min(screenBounds.size.width / ciImage.extent.size.width, screenBounds.size.height / ciImage.extent.size.height) + let transformedImage = ciImage.transformed(by: CGAffineTransform(scaleX: scale, y: scale)) + + return UIImage(ciImage: transformedImage) + } +} diff --git a/Antidote/QuickLookPreviewController.swift b/Antidote/QuickLookPreviewController.swift new file mode 100644 index 0000000..b712f5a --- /dev/null +++ b/Antidote/QuickLookPreviewController.swift @@ -0,0 +1,14 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation +import QuickLook + +protocol QuickLookPreviewControllerDataSource: QLPreviewControllerDataSource { + var previewController: QuickLookPreviewController? { get set } +} + +class QuickLookPreviewController: QLPreviewController { + var dataSourceStorage: QuickLookPreviewControllerDataSource? +} diff --git a/Antidote/Reach.swift b/Antidote/Reach.swift new file mode 100644 index 0000000..a6eeca7 --- /dev/null +++ b/Antidote/Reach.swift @@ -0,0 +1,119 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// The MIT License (MIT) +// +// Copyright (c) 2015 Isuru Nanayakkara +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + + +import Foundation +import SystemConfiguration + + +let ReachabilityStatusChangedNotification = "ReachabilityStatusChangedNotification" + +enum ReachabilityType: CustomStringConvertible { + case wwan + case wiFi + + var description: String { + switch self { + case .wwan: return "WWAN" + case .wiFi: return "WiFi" + } + } +} + +enum ReachabilityStatus: CustomStringConvertible { + case offline + case online(ReachabilityType) + case unknown + + var description: String { + switch self { + case .offline: return "Offline" + case .online(let type): return "Online (\(type))" + case .unknown: return "Unknown" + } + } +} + +open class Reach { + + func connectionStatus() -> ReachabilityStatus { + var zeroAddress = sockaddr_in() + zeroAddress.sin_len = UInt8(MemoryLayout.size(ofValue: zeroAddress)) + zeroAddress.sin_family = sa_family_t(AF_INET) + + guard let defaultRouteReachability = withUnsafePointer(to: &zeroAddress, { + $0.withMemoryRebound(to: sockaddr.self, capacity: 1) { + SCNetworkReachabilityCreateWithAddress(nil, $0) + } + }) else { + return .unknown + } + + var flags : SCNetworkReachabilityFlags = [] + if !SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) { + return .unknown + } + + return ReachabilityStatus(reachabilityFlags: flags) + } + + + func monitorReachabilityChanges() { + let host = "google.com" + var context = SCNetworkReachabilityContext(version: 0, info: nil, retain: nil, release: nil, copyDescription: nil) + let reachability = SCNetworkReachabilityCreateWithName(nil, host)! + + SCNetworkReachabilitySetCallback(reachability, { (_, flags, _) in + let status = ReachabilityStatus(reachabilityFlags: flags) + + NotificationCenter.default.post(name: Notification.Name(rawValue: ReachabilityStatusChangedNotification), + object: nil, + userInfo: ["Status": status.description]) + + }, &context) + + SCNetworkReachabilityScheduleWithRunLoop(reachability, CFRunLoopGetMain(), CFRunLoopMode.commonModes.rawValue) + } + +} + +extension ReachabilityStatus { + fileprivate init(reachabilityFlags flags: SCNetworkReachabilityFlags) { + let connectionRequired = flags.contains(.connectionRequired) + let isReachable = flags.contains(.reachable) + let isWWAN = flags.contains(.isWWAN) + + if !connectionRequired && isReachable { + if isWWAN { + self = .online(.wwan) + } else { + self = .online(.wiFi) + } + } else { + self = .offline + } + } +} diff --git a/Antidote/Results.swift b/Antidote/Results.swift new file mode 100644 index 0000000..e41e075 --- /dev/null +++ b/Antidote/Results.swift @@ -0,0 +1,82 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +/// Swift wrapper for RLMResults +class Results { + fileprivate let results: RLMResults + + var count: Int { + get { + return Int(results.count) + } + } + + var firstObject: T { + get { + return results.firstObject() as! T + } + } + + var lastObject: T { + get { + return results.lastObject() as! T + } + } + + init(results: RLMResults) { + let name = NSStringFromClass(T.self) + assert(name == results.objectClassName, "Specified wrong generic class") + + self.results = results + } + + func indexOfObject(_ object: T) -> Int { + return Int(results.index(of: object)) + } + + func sortedResultsUsingProperty(_ property: String, ascending: Bool) -> Results { + let sortedResults = results.sortedResults(usingKeyPath: property, ascending: ascending) + return Results(results: sortedResults) + } + + func sortedResultsUsingDescriptors(_ properties: Array) -> Results { + let sortedResults = results.sortedResults(using: properties) + return Results(results: sortedResults) + } + + func addNotificationBlock(_ block: @escaping (ResultsChange) -> Void) -> RLMNotificationToken { + return results.addNotificationBlock { rlmResults, changes, error in + DispatchQueue.main.async { + if let error = error { + block(ResultsChange.error(error as NSError)) + return + } + + let results: Results? = (rlmResults != nil) ? Results(results: rlmResults!) : nil + + if let changes = changes { + block(ResultsChange.update(results, + deletions: changes.deletions as! [Int], + insertions: changes.insertions as! [Int], + modifications: changes.modifications as! [Int])) + return + } + + block(ResultsChange.initial(results)) + } + } + } + + subscript(index: Int) -> T { + return results[UInt(index)] as! T + } + + func objects(with predicate: NSPredicate) -> Results { + let matching = results.objects(with: predicate) + return Results(results: matching) + } +} + diff --git a/Antidote/ResultsChange.swift b/Antidote/ResultsChange.swift new file mode 100644 index 0000000..6103659 --- /dev/null +++ b/Antidote/ResultsChange.swift @@ -0,0 +1,12 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +/// Swift wrapper for RLMResults addNotificationBlock. +enum ResultsChange { + case initial(Results?) + case update(Results?, deletions: [Int], insertions: [Int], modifications: [Int]) + case error(NSError) +} diff --git a/Antidote/ResultsExtension.swift b/Antidote/ResultsExtension.swift new file mode 100644 index 0000000..92b05c4 --- /dev/null +++ b/Antidote/ResultsExtension.swift @@ -0,0 +1,21 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// +// ResultsExtension.swift +// Antidote +// +// Created by Dmytro Vorobiov on 26/04/2017. +// Copyright © 2017 dvor. All rights reserved. +// + +import Foundation + +extension Results where T : OCTMessageAbstract { + func undeliveredMessages() -> Results { + let undeliveredPredicate = NSPredicate(format: "messageText != nil AND messageText.isDelivered == NO AND senderUniqueIdentifier == nil") + return self.objects(with: undeliveredPredicate) + } +} + diff --git a/Antidote/RoundedButton.swift b/Antidote/RoundedButton.swift new file mode 100644 index 0000000..6cb03cd --- /dev/null +++ b/Antidote/RoundedButton.swift @@ -0,0 +1,52 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit + +private struct Constants { + static let Height = 40.0 +} + +class RoundedButton: UIButton { + enum ButtonType { + case login + case runningPositive + case runningNegative + } + + init(theme: Theme, type: ButtonType) { + super.init(frame: CGRect.zero) + + let titleColor: UIColor + let bgColor: UIColor + + switch type { + case .login: + titleColor = theme.colorForType(.LoginButtonText) + bgColor = theme.colorForType(.LoginButtonBackground) + case .runningPositive: + titleColor = theme.colorForType(.RoundedButtonText) + bgColor = theme.colorForType(.RoundedPositiveButtonBackground) + case .runningNegative: + titleColor = theme.colorForType(.RoundedButtonText) + bgColor = theme.colorForType(.RoundedNegativeButtonBackground) + } + + setTitleColor(titleColor, for:UIControlState()) + titleLabel?.font = UIFont.systemFont(ofSize: 18.0) + layer.cornerRadius = 5.0 + layer.masksToBounds = true + + let bgImage = UIImage.imageWithColor(bgColor, size: CGSize(width: 1.0, height: 1.0)) + setBackgroundImage(bgImage, for:UIControlState()) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override var intrinsicContentSize : CGSize { + return CGSize(width: 0.0, height: Constants.Height) + } +} diff --git a/Antidote/RunningCoordinator.swift b/Antidote/RunningCoordinator.swift new file mode 100644 index 0000000..2e3f5e1 --- /dev/null +++ b/Antidote/RunningCoordinator.swift @@ -0,0 +1,92 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +protocol RunningCoordinatorDelegate: class { + func runningCoordinatorDidLogout(_ coordinator: RunningCoordinator, importToxProfileFromURL: URL?) + func runningCoordinatorDeleteProfile(_ coordinator: RunningCoordinator) + func runningCoordinatorRecreateCoordinatorsStack(_ coordinator: RunningCoordinator, options: CoordinatorOptions) +} + +class RunningCoordinator { + weak var delegate: RunningCoordinatorDelegate? + + fileprivate let theme: Theme + fileprivate let window: UIWindow + + fileprivate var toxManager: OCTManager + fileprivate var options: CoordinatorOptions? + + var activeSessionCoordinator: ActiveSessionCoordinator? + fileprivate var pinAuthorizationCoordinator: PinAuthorizationCoordinator + + init(theme: Theme, window: UIWindow, toxManager: OCTManager, skipAuthorizationChallenge: Bool) { + self.theme = theme + self.window = window + self.toxManager = toxManager + self.pinAuthorizationCoordinator = PinAuthorizationCoordinator(theme: theme, + submanagerObjects: toxManager.objects, + lockOnStartup: !skipAuthorizationChallenge) + + pinAuthorizationCoordinator.delegate = self + } +} + +extension RunningCoordinator: TopCoordinatorProtocol { + func startWithOptions(_ options: CoordinatorOptions?) { + self.options = options + + activeSessionCoordinator = ActiveSessionCoordinator(theme: theme, window: window, toxManager: toxManager) + activeSessionCoordinator?.delegate = self + activeSessionCoordinator?.startWithOptions(options) + + pinAuthorizationCoordinator.startWithOptions(nil) + } + + func handleLocalNotification(_ notification: UILocalNotification) { + activeSessionCoordinator?.handleLocalNotification(notification) + } + + func handleInboxURL(_ url: URL) { + activeSessionCoordinator?.handleInboxURL(url) + } +} + +extension RunningCoordinator: ActiveSessionCoordinatorDelegate { + func activeSessionCoordinatorDidLogout(_ coordinator: ActiveSessionCoordinator, importToxProfileFromURL url: URL?) { + logoutUser(importToxProfileFromURL: url) + } + + func activeSessionCoordinatorDeleteProfile(_ coordinator: ActiveSessionCoordinator) { + delegate?.runningCoordinatorDeleteProfile(self) + } + + func activeSessionCoordinatorRecreateCoordinatorsStack(_ coordinator: ActiveSessionCoordinator, options: CoordinatorOptions) { + delegate?.runningCoordinatorRecreateCoordinatorsStack(self, options: options) + } + + func activeSessionCoordinatorDidStartCall(_ coordinator: ActiveSessionCoordinator) { + pinAuthorizationCoordinator.preventFromLocking = true + } + + func activeSessionCoordinatorDidFinishCall(_ coordinator: ActiveSessionCoordinator) { + pinAuthorizationCoordinator.preventFromLocking = false + } +} + +extension RunningCoordinator: PinAuthorizationCoordinatorDelegate { + func pinAuthorizationCoordinatorDidLogout(_ coordinator: PinAuthorizationCoordinator) { + logoutUser() + } +} + +private extension RunningCoordinator { + func logoutUser(importToxProfileFromURL url: URL? = nil) { + let keychainManager = KeychainManager() + keychainManager.deleteActiveAccountData() + + delegate?.runningCoordinatorDidLogout(self, importToxProfileFromURL: url) + } +} diff --git a/Antidote/SettingsAboutController.swift b/Antidote/SettingsAboutController.swift new file mode 100644 index 0000000..7a4c5ff --- /dev/null +++ b/Antidote/SettingsAboutController.swift @@ -0,0 +1,61 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +protocol SettingsAboutControllerDelegate: class { + func settingsAboutControllerShowAcknowledgements(_ controller: SettingsAboutController) +} + +class SettingsAboutController: StaticTableController { + weak var delegate: SettingsAboutControllerDelegate? + + fileprivate let antidoteVersionModel = StaticTableInfoCellModel() + fileprivate let antidoteBuildModel = StaticTableInfoCellModel() + fileprivate let toxcoreVersionModel = StaticTableInfoCellModel() + fileprivate let acknowledgementsModel = StaticTableDefaultCellModel() + + init(theme: Theme) { + super.init(theme: theme, style: .grouped, model: [ + [ + antidoteVersionModel, + antidoteBuildModel, + ], + [ + toxcoreVersionModel, + ], + [ + acknowledgementsModel, + ], + ]) + + title = String(localized: "settings_about") + updateModels() + } + + required convenience init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +private extension SettingsAboutController { + func updateModels() { + antidoteVersionModel.title = String(localized: "settings_antidote_version") + antidoteVersionModel.value = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String + + antidoteBuildModel.title = String(localized: "settings_antidote_build") + antidoteBuildModel.value = Bundle.main.infoDictionary?["CFBundleVersion"] as? String + + toxcoreVersionModel.title = String(localized: "settings_toxcore_version") + toxcoreVersionModel.value = OCTTox.version() + + acknowledgementsModel.value = String(localized: "settings_acknowledgements") + acknowledgementsModel.didSelectHandler = showAcknowledgements + acknowledgementsModel.rightImageType = .arrow + } + + func showAcknowledgements(_: StaticTableBaseCell) { + delegate?.settingsAboutControllerShowAcknowledgements(self) + } +} diff --git a/Antidote/SettingsAdvancedController.swift b/Antidote/SettingsAdvancedController.swift new file mode 100644 index 0000000..6ea0d94 --- /dev/null +++ b/Antidote/SettingsAdvancedController.swift @@ -0,0 +1,60 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +protocol SettingsAdvancedControllerDelegate: class { + func settingsAdvancedControllerToxOptionsChanged(_ controller: SettingsAdvancedController) +} + +class SettingsAdvancedController: StaticTableController { + weak var delegate: SettingsAdvancedControllerDelegate? + + fileprivate let theme: Theme + fileprivate let userDefaults = UserDefaultsManager() + + fileprivate let UDPModel = StaticTableSwitchCellModel() + fileprivate let restoreDefaultsModel = StaticTableButtonCellModel() + + init(theme: Theme) { + self.theme = theme + + super.init(theme: theme, style: .grouped, model: [ + [ + UDPModel, + ], + [ + restoreDefaultsModel, + ], + ]) + + title = String(localized: "settings_advanced_settings") + updateModels() + } + + required convenience init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +private extension SettingsAdvancedController { + func updateModels() { + UDPModel.title = String(localized: "settings_udp_enabled") + UDPModel.on = userDefaults.UDPEnabled + UDPModel.valueChangedHandler = UDPChanged + + restoreDefaultsModel.title = String(localized: "settings_restore_default") + restoreDefaultsModel.didSelectHandler = restoreDefaultsSettings + } + + func UDPChanged(_ on: Bool) { + userDefaults.UDPEnabled = on + delegate?.settingsAdvancedControllerToxOptionsChanged(self) + } + + func restoreDefaultsSettings(_: StaticTableBaseCell) { + userDefaults.resetUDPEnabled() + delegate?.settingsAdvancedControllerToxOptionsChanged(self) + } +} diff --git a/Antidote/SettingsMainController.swift b/Antidote/SettingsMainController.swift new file mode 100644 index 0000000..1a1b384 --- /dev/null +++ b/Antidote/SettingsMainController.swift @@ -0,0 +1,149 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +protocol SettingsMainControllerDelegate: class { + func settingsMainControllerShowAboutScreen(_ controller: SettingsMainController) + func settingsMainControllerShowFaqScreen(_ controller: SettingsMainController) + func settingsMainControllerShowAdvancedSettings(_ controller: SettingsMainController) + func settingsMainControllerChangeAutodownloadImages(_ controller: SettingsMainController) +} + +class SettingsMainController: StaticTableController { + weak var delegate: SettingsMainControllerDelegate? + + fileprivate let theme: Theme + fileprivate let userDefaults = UserDefaultsManager() + + fileprivate let aboutModel = StaticTableDefaultCellModel() + fileprivate let faqModel = StaticTableDefaultCellModel() + fileprivate let autodownloadImagesModel = StaticTableInfoCellModel() + fileprivate let notificationsModel = StaticTableSwitchCellModel() + fileprivate let longerbgModel = StaticTableSwitchCellModel() + fileprivate let debugmodeModel = StaticTableSwitchCellModel() + fileprivate let dateonmessagemodeModel = StaticTableSwitchCellModel() + fileprivate let advancedSettingsModel = StaticTableDefaultCellModel() + + init(theme: Theme) { + self.theme = theme + + super.init(theme: theme, style: .grouped, model: [ + [ + autodownloadImagesModel, + ], + [ + longerbgModel, + ], + [ + notificationsModel, + dateonmessagemodeModel, + debugmodeModel, + ], + [ + advancedSettingsModel, + ], + [ + faqModel, + aboutModel, + ], + ], footers: [ + String(localized: "settings_autodownload_images_description"), + "This will keep the Application running for longer in the background to finish sending messages, but this will also reveal more meta data about you. It will link your IP address and your PUSH token. It's a tradeoff between convenience and metadata privacy.\n\nYou can use ProtonVPN to prevent that.\n\nSee https://protonvpn.com/free-vpn/\n\nand\n\nhttps://apps.apple.com/app/apple-store/id1437005085", + nil, + nil, + nil, + ]) + + title = String(localized: "settings_title") + updateModels() + } + + required convenience init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + updateModels() + reloadTableView() + } +} + +private extension SettingsMainController{ + func updateModels() { + aboutModel.value = String(localized: "settings_about") + aboutModel.didSelectHandler = showAboutScreen + aboutModel.rightImageType = .arrow + + faqModel.value = String(localized: "settings_faq") + faqModel.didSelectHandler = showFaqScreen + faqModel.rightImageType = .arrow + + autodownloadImagesModel.title = String(localized: "settings_autodownload_images") + autodownloadImagesModel.showArrow = true + autodownloadImagesModel.didSelectHandler = changeAutodownloadImages + switch userDefaults.autodownloadImages { + case .Never: + autodownloadImagesModel.value = String(localized: "settings_never") + case .UsingWiFi: + autodownloadImagesModel.value = String(localized: "settings_wifi") + case .Always: + autodownloadImagesModel.value = String(localized: "settings_always") + } + + notificationsModel.title = String(localized: "settings_notifications_message_preview") + notificationsModel.on = userDefaults.showNotificationPreview + notificationsModel.valueChangedHandler = notificationsValueChanged + + longerbgModel.title = "Longer Background Mode" + longerbgModel.on = userDefaults.LongerbgMode + longerbgModel.valueChangedHandler = longerbgValueChanged + + debugmodeModel.title = "Debug Mode" + debugmodeModel.on = userDefaults.DebugMode + debugmodeModel.valueChangedHandler = debugmodeValueChanged + + dateonmessagemodeModel.title = "Always show date on Messages" + dateonmessagemodeModel.on = userDefaults.DateonmessageMode + dateonmessagemodeModel.valueChangedHandler = dateonmessagemodeValueChanged + + advancedSettingsModel.value = String(localized: "settings_advanced_settings") + advancedSettingsModel.didSelectHandler = showAdvancedSettings + advancedSettingsModel.rightImageType = .arrow + } + + func showAboutScreen(_: StaticTableBaseCell) { + delegate?.settingsMainControllerShowAboutScreen(self) + } + + func showFaqScreen(_: StaticTableBaseCell) { + delegate?.settingsMainControllerShowFaqScreen(self) + } + + func notificationsValueChanged(_ on: Bool) { + userDefaults.showNotificationPreview = on + } + + func longerbgValueChanged(_ on: Bool) { + userDefaults.LongerbgMode = on + } + + func debugmodeValueChanged(_ on: Bool) { + userDefaults.DebugMode = on + } + + func dateonmessagemodeValueChanged(_ on: Bool) { + userDefaults.DateonmessageMode = on + } + + func changeAutodownloadImages(_: StaticTableBaseCell) { + delegate?.settingsMainControllerChangeAutodownloadImages(self) + } + + func showAdvancedSettings(_: StaticTableBaseCell) { + delegate?.settingsMainControllerShowAdvancedSettings(self) + } +} diff --git a/Antidote/SettingsTabCoordinator.swift b/Antidote/SettingsTabCoordinator.swift new file mode 100644 index 0000000..763c6a5 --- /dev/null +++ b/Antidote/SettingsTabCoordinator.swift @@ -0,0 +1,95 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit +import SafariServices + +private struct Options { + static let ToShowKey = "ToShowKey" + + enum Controller { + case advancedSettings + } +} + +protocol SettingsTabCoordinatorDelegate: class { + func settingsTabCoordinatorRecreateCoordinatorsStack(_ coordinator: SettingsTabCoordinator, options: CoordinatorOptions) +} + +class SettingsTabCoordinator: ActiveSessionNavigationCoordinator { + weak var delegate: SettingsTabCoordinatorDelegate? + + override func startWithOptions(_ options: CoordinatorOptions?) { + let controller = SettingsMainController(theme: theme) + controller.delegate = self + + navigationController.pushViewController(controller, animated: false) + + if let toShow = options?[Options.ToShowKey] as? Options.Controller { + switch toShow { + case .advancedSettings: + let advanced = SettingsAdvancedController(theme: theme) + advanced.delegate = self + + navigationController.pushViewController(advanced, animated: false) + } + } + } +} + +extension SettingsTabCoordinator: SettingsMainControllerDelegate { + func settingsMainControllerShowAboutScreen(_ controller: SettingsMainController) { + let controller = SettingsAboutController(theme: theme) + controller.delegate = self + + navigationController.pushViewController(controller, animated: true) + } + + func settingsMainControllerShowFaqScreen(_ controller: SettingsMainController) { + let controller = FAQController(theme: theme) + + navigationController.pushViewController(controller, animated: true) + } + + func settingsMainControllerChangeAutodownloadImages(_ controller: SettingsMainController) { + let controller = ChangeAutodownloadImagesController(theme: theme) + controller.delegate = self + + navigationController.pushViewController(controller, animated: true) + } + + func settingsMainControllerShowAdvancedSettings(_ controller: SettingsMainController) { + let controller = SettingsAdvancedController(theme: theme) + controller.delegate = self + + navigationController.pushViewController(controller, animated: true) + } +} + +extension SettingsTabCoordinator: SettingsAboutControllerDelegate { + func settingsAboutControllerShowAcknowledgements(_ controller: SettingsAboutController) { + let controller = TextViewController( + resourceName: "antidote-acknowledgements", + backgroundColor: theme.colorForType(.NormalBackground), + titleColor: theme.colorForType(.NormalText), + textColor: theme.colorForType(.NormalText)) + controller.title = String(localized: "settings_acknowledgements") + + navigationController.pushViewController(controller, animated: true) + } +} + +extension SettingsTabCoordinator: ChangeAutodownloadImagesControllerDelegate { + func changeAutodownloadImagesControllerDidChange(_ controller: ChangeAutodownloadImagesController) { + navigationController.popViewController(animated: true) + } +} + +extension SettingsTabCoordinator: SettingsAdvancedControllerDelegate { + func settingsAdvancedControllerToxOptionsChanged(_ controller: SettingsAdvancedController) { + delegate?.settingsTabCoordinatorRecreateCoordinatorsStack(self, options: [ + Options.ToShowKey: Options.Controller.advancedSettings + ]) + } +} diff --git a/Antidote/StaticBackgroundView.swift b/Antidote/StaticBackgroundView.swift new file mode 100644 index 0000000..76f5713 --- /dev/null +++ b/Antidote/StaticBackgroundView.swift @@ -0,0 +1,21 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit + +/** + View with static background color. Is used to prevent views inside UITableViewCell from blinking on tap. + */ +class StaticBackgroundView: UIView { + override var backgroundColor: UIColor? { + get { + return super.backgroundColor + } + set {} + } + + func setStaticBackgroundColor(_ color: UIColor?) { + super.backgroundColor = color + } +} diff --git a/Antidote/StaticTableAvatarCell.swift b/Antidote/StaticTableAvatarCell.swift new file mode 100644 index 0000000..96246cd --- /dev/null +++ b/Antidote/StaticTableAvatarCell.swift @@ -0,0 +1,95 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit +import SnapKit + +private struct Constants { + static let AvatarVerticalOffset = 10.0 +} + +class StaticTableAvatarCell: StaticTableBaseCell { + fileprivate var didTapOnAvatar: ((StaticTableAvatarCell) -> Void)? + + fileprivate var button: UIButton! + + override func setupWithTheme(_ theme: Theme, model: BaseCellModel) { + super.setupWithTheme(theme, model: model) + + guard let avatarModel = model as? StaticTableAvatarCellModel else { + assert(false, "Wrong model \(model) passed to cell \(self)") + return + } + + selectionStyle = .none + + button.isUserInteractionEnabled = avatarModel.userInteractionEnabled + button.setImage(avatarModel.avatar, for: UIControlState()) + didTapOnAvatar = avatarModel.didTapOnAvatar + } + + override func createViews() { + super.createViews() + + button = UIButton() + button.layer.cornerRadius = StaticTableAvatarCellModel.Constants.AvatarImageSize / 2 + button.layer.masksToBounds = true + button.addTarget(self, action: #selector(StaticTableAvatarCell.buttonPressed), for: .touchUpInside) + customContentView.addSubview(button) + } + + override func installConstraints() { + super.installConstraints() + + button.snp.makeConstraints { + $0.centerX.equalTo(customContentView) + $0.top.equalTo(customContentView).offset(Constants.AvatarVerticalOffset) + $0.bottom.equalTo(customContentView).offset(-Constants.AvatarVerticalOffset) + $0.size.equalTo(StaticTableAvatarCellModel.Constants.AvatarImageSize) + } + } +} + +// Accessibility +extension StaticTableAvatarCell { + override var isAccessibilityElement: Bool { + get { + return true + } + set {} + } + + override var accessibilityLabel: String? { + get { + return String(localized: "accessibility_avatar_button_label") + } + set {} + } + + override var accessibilityHint: String? { + get { + return button.isUserInteractionEnabled ? String(localized: "accessibility_avatar_button_hint") : nil + } + set {} + } + + override var accessibilityTraits: UIAccessibilityTraits { + get { + var traits = UIAccessibilityTraitImage + + if button.isUserInteractionEnabled { + traits |= UIAccessibilityTraitButton + } + + return traits + } + set {} + } +} + +extension StaticTableAvatarCell { + @objc func buttonPressed() { + didTapOnAvatar?(self) + } +} diff --git a/Antidote/StaticTableAvatarCellModel.swift b/Antidote/StaticTableAvatarCellModel.swift new file mode 100644 index 0000000..2fb8d35 --- /dev/null +++ b/Antidote/StaticTableAvatarCellModel.swift @@ -0,0 +1,16 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +class StaticTableAvatarCellModel: StaticTableBaseCellModel { + struct Constants { + static let AvatarImageSize: CGFloat = 120.0 + } + + var avatar: UIImage? + var didTapOnAvatar: ((StaticTableAvatarCell) -> Void)? + + var userInteractionEnabled: Bool = true +} diff --git a/Antidote/StaticTableBaseCell.swift b/Antidote/StaticTableBaseCell.swift new file mode 100644 index 0000000..0af0535 --- /dev/null +++ b/Antidote/StaticTableBaseCell.swift @@ -0,0 +1,68 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit +import SnapKit + +private struct Constants { + static let HorizontalOffset = 20.0 + static let MinHeight = 50.0 +} + +class StaticTableBaseCell: BaseCell { + /** + View to add all content to. + */ + var customContentView: UIView! + + fileprivate var bottomSeparatorView: UIView! + + func setBottomSeparatorHidden(_ hidden: Bool) { + bottomSeparatorView.isHidden = hidden + } + + /** + Override this method in subclass. + */ + override func setupWithTheme(_ theme: Theme, model: BaseCellModel) { + super.setupWithTheme(theme, model: model) + + bottomSeparatorView.backgroundColor = theme.colorForType(.SeparatorsAndBorders) + } + + /** + Override this method in subclass. + */ + override func createViews() { + super.createViews() + + customContentView = UIView() + customContentView.backgroundColor = UIColor.clear + contentView.addSubview(customContentView) + + bottomSeparatorView = UIView() + contentView.addSubview(bottomSeparatorView) + } + + /** + Override this method in subclass. + */ + override func installConstraints() { + super.installConstraints() + + customContentView.snp.makeConstraints { + $0.leading.equalTo(contentView).offset(Constants.HorizontalOffset) + $0.trailing.equalTo(contentView).offset(-Constants.HorizontalOffset) + $0.top.equalTo(contentView) + $0.height.greaterThanOrEqualTo(Constants.MinHeight) + } + + bottomSeparatorView.snp.makeConstraints { + $0.leading.equalTo(customContentView) + $0.top.equalTo(customContentView.snp.bottom) + $0.trailing.bottom.equalTo(contentView) + $0.height.equalTo(0.5) + } + } +} diff --git a/Antidote/StaticTableBaseCellModel.swift b/Antidote/StaticTableBaseCellModel.swift new file mode 100644 index 0000000..dc626ab --- /dev/null +++ b/Antidote/StaticTableBaseCellModel.swift @@ -0,0 +1,9 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +class StaticTableBaseCellModel: BaseCellModel { + +} diff --git a/Antidote/StaticTableButtonCell.swift b/Antidote/StaticTableButtonCell.swift new file mode 100644 index 0000000..171d63c --- /dev/null +++ b/Antidote/StaticTableButtonCell.swift @@ -0,0 +1,66 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit + +private struct Constants { + static let VerticalOffset = 12.0 +} + +class StaticTableButtonCell: StaticTableBaseCell { + fileprivate var label: UILabel! + + override func setupWithTheme(_ theme: Theme, model: BaseCellModel) { + super.setupWithTheme(theme, model: model) + + guard let buttonModel = model as? StaticTableButtonCellModel else { + assert(false, "Wrong model \(model) passed to cell \(self)") + return + } + + label.text = buttonModel.title + label.textColor = theme.colorForType(.LinkText) + } + + override func createViews() { + super.createViews() + + label = UILabel() + customContentView.addSubview(label) + } + + override func installConstraints() { + super.installConstraints() + + label.snp.makeConstraints { + $0.leading.trailing.equalTo(customContentView) + $0.top.equalTo(customContentView).offset(Constants.VerticalOffset) + $0.bottom.equalTo(customContentView).offset(-Constants.VerticalOffset) + } + } +} + +// Accessibility +extension StaticTableButtonCell { + override var isAccessibilityElement: Bool { + get { + return true + } + set {} + } + + override var accessibilityLabel: String? { + get { + return label.text + } + set {} + } + + override var accessibilityTraits: UIAccessibilityTraits { + get { + return UIAccessibilityTraitButton + } + set {} + } +} diff --git a/Antidote/StaticTableButtonCellModel.swift b/Antidote/StaticTableButtonCellModel.swift new file mode 100644 index 0000000..9684b04 --- /dev/null +++ b/Antidote/StaticTableButtonCellModel.swift @@ -0,0 +1,9 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +class StaticTableButtonCellModel: StaticTableSelectableCellModel { + var title: String? +} diff --git a/Antidote/StaticTableChatButtonsCell.swift b/Antidote/StaticTableChatButtonsCell.swift new file mode 100644 index 0000000..d5589aa --- /dev/null +++ b/Antidote/StaticTableChatButtonsCell.swift @@ -0,0 +1,138 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit +import SnapKit + +private struct Constants { + static let ButtonSize = 40.0 + static let VerticalOffset = 8.0 +} + +class StaticTableChatButtonsCell: StaticTableBaseCell { + fileprivate var chatButton: UIButton! + fileprivate var callButton: UIButton! + fileprivate var videoButton: UIButton! + + fileprivate var separators: [UIView]! + + fileprivate var chatButtonHandler: (() -> Void)? + fileprivate var callButtonHandler: (() -> Void)? + fileprivate var videoButtonHandler: (() -> Void)? + + override func setupWithTheme(_ theme: Theme, model: BaseCellModel) { + super.setupWithTheme(theme, model: model) + + guard let buttonsModel = model as? StaticTableChatButtonsCellModel else { + assert(false, "Wrong model \(model) passed to cell \(self)") + return + } + + selectionStyle = .none + + chatButtonHandler = buttonsModel.chatButtonHandler + callButtonHandler = buttonsModel.callButtonHandler + videoButtonHandler = buttonsModel.videoButtonHandler + + chatButton.isEnabled = buttonsModel.chatButtonEnabled + callButton.isEnabled = buttonsModel.callButtonEnabled + videoButton.isEnabled = buttonsModel.videoButtonEnabled + } + + override func createViews() { + super.createViews() + + chatButton = createButtonWithImageName("friend-card-chat", + accessibilityLabel: String(localized: "accessibility_chat_button_label"), + accessibilityHint: String(localized: "accessibility_chat_button_hint"), + action: #selector(StaticTableChatButtonsCell.chatButtonPressed)) + callButton = createButtonWithImageName("start-call", + accessibilityLabel: String(localized: "accessibility_call_button_label"), + accessibilityHint: String(localized: "accessibility_call_button_hint"), + action: #selector(StaticTableChatButtonsCell.callButtonPressed)) + videoButton = createButtonWithImageName("video-call", + accessibilityLabel: String(localized: "accessibility_video_button_label"), + accessibilityHint: String(localized: "accessibility_video_button_hint"), + action: #selector(StaticTableChatButtonsCell.videoButtonPressed)) + + separators = [UIView]() + for _ in 0...3 { + let sep = UIView() + sep.backgroundColor = UIColor.clear + customContentView.addSubview(sep) + separators.append(sep) + } + } + + override func installConstraints() { + super.installConstraints() + + var previous: UIView? = nil + for (index, sep) in separators.enumerated() { + sep.snp.makeConstraints { + if previous != nil { + $0.width.equalTo(previous!.snp.width) + } + + if index == 0 { + $0.leading.equalTo(customContentView) + } + + if index == (separators.count-1) { + $0.trailing.equalTo(customContentView) + } + } + + previous = sep + } + + func installForButton(_ button: UIButton, index: Int) { + button.snp.makeConstraints { + $0.top.equalTo(customContentView).offset(Constants.VerticalOffset) + $0.bottom.equalTo(customContentView).offset(-Constants.VerticalOffset) + + $0.leading.equalTo(separators[index].snp.trailing) + $0.trailing.equalTo(separators[index+1].snp.leading) + + $0.size.equalTo(Constants.ButtonSize) + } + } + + installForButton(chatButton, index: 0) + installForButton(callButton, index: 1) + installForButton(videoButton, index: 2) + } +} + +extension StaticTableChatButtonsCell { + @objc func chatButtonPressed() { + chatButtonHandler?() + } + + @objc func callButtonPressed() { + callButtonHandler?() + } + + @objc func videoButtonPressed() { + videoButtonHandler?() + } +} + +private extension StaticTableChatButtonsCell { + func createButtonWithImageName(_ imageName: String, + accessibilityLabel: String, + accessibilityHint: String, + action: Selector) -> UIButton { + let image = UIImage.templateNamed(imageName) + + let button = UIButton() + button.setImage(image, for: UIControlState()) + button.accessibilityLabel = accessibilityLabel + button.accessibilityHint = accessibilityHint + button.addTarget(self, action: action, for: .touchUpInside) + customContentView.addSubview(button) + + return button + } +} diff --git a/Antidote/StaticTableChatButtonsCellModel.swift b/Antidote/StaticTableChatButtonsCellModel.swift new file mode 100644 index 0000000..9d856cb --- /dev/null +++ b/Antidote/StaticTableChatButtonsCellModel.swift @@ -0,0 +1,15 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +class StaticTableChatButtonsCellModel: StaticTableBaseCellModel { + var chatButtonHandler: (() -> Void)? + var callButtonHandler: (() -> Void)? + var videoButtonHandler: (() -> Void)? + + var chatButtonEnabled: Bool = true + var callButtonEnabled: Bool = true + var videoButtonEnabled: Bool = true +} diff --git a/Antidote/StaticTableController.swift b/Antidote/StaticTableController.swift new file mode 100644 index 0000000..f6d0236 --- /dev/null +++ b/Antidote/StaticTableController.swift @@ -0,0 +1,169 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit +import SnapKit + +class StaticTableController: UIViewController { + fileprivate let theme: Theme + fileprivate let tableViewStyle: UITableViewStyle + fileprivate var modelArray: [[StaticTableBaseCellModel]] + fileprivate let footerArray: [String?]? + + fileprivate var tableView: UITableView? + + init(theme: Theme, style: UITableViewStyle, model: [[StaticTableBaseCellModel]], footers: [String?]? = nil) { + self.theme = theme + self.tableViewStyle = style + self.modelArray = model + self.footerArray = footers + + super.init(nibName: nil, bundle: nil) + + edgesForExtendedLayout = UIRectEdge() + } + + required convenience init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func loadView() { + loadViewWithBackgroundColor(theme.colorForType(.NormalBackground)) + + createTableView() + + installConstraints() + } + + func reloadTableView() { + tableView?.reloadData() + } + + func updateModelArray(_ model: [[StaticTableBaseCellModel]]) { + modelArray = model + reloadTableView() + } +} + +extension StaticTableController: UITableViewDataSource { + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let model = modelArray[indexPath.section][indexPath.row] + let cell: StaticTableBaseCell + + switch model { + case _ as StaticTableButtonCellModel: + cell = dequeueCellForClass(StaticTableButtonCell.staticReuseIdentifier) + case _ as StaticTableAvatarCellModel: + cell = dequeueCellForClass(StaticTableAvatarCell.staticReuseIdentifier) + case _ as StaticTableDefaultCellModel: + cell = dequeueCellForClass(StaticTableDefaultCell.staticReuseIdentifier) + case _ as StaticTableChatButtonsCellModel: + cell = dequeueCellForClass(StaticTableChatButtonsCell.staticReuseIdentifier) + case _ as StaticTableSwitchCellModel: + cell = dequeueCellForClass(StaticTableSwitchCell.staticReuseIdentifier) + case _ as StaticTableInfoCellModel: + cell = dequeueCellForClass(StaticTableInfoCell.staticReuseIdentifier) + case _ as StaticTableMultiChoiceButtonCellModel: + cell = dequeueCellForClass(StaticTableMultiChoiceButtonCell.staticReuseIdentifier) + default: + fatalError("Static model class \(model) has not been implemented") + } + + cell.setupWithTheme(theme, model: model) + + let isLastRow = (indexPath.row == (modelArray[indexPath.section].count - 1)) + let isLastSection = (indexPath.section == (modelArray.count - 1)) + + switch tableViewStyle { + case .plain: + cell.setBottomSeparatorHidden(!isLastRow || isLastSection) + case .grouped: + cell.setBottomSeparatorHidden(isLastRow) + + case .insetGrouped: + print("error") + } + + return cell + } + + func numberOfSections(in tableView: UITableView) -> Int { + return modelArray.count + } + + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return modelArray[section].count + } + + func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? { + guard let array = footerArray else { + return nil + } + + guard section < array.count else { + return nil + } + + return array[section] + } +} + +extension StaticTableController: UITableViewDelegate { + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + tableView.deselectRow(at: indexPath, animated: true) + + guard let cell = tableView.cellForRow(at: indexPath) as? StaticTableBaseCell else { + return + } + + let model = modelArray[indexPath.section][indexPath.row] + + switch model { + case let model as StaticTableSelectableCellModel: + model.didSelectHandler?(cell) + default: + // nop + break; + } + } +} + +private extension StaticTableController { + func createTableView() { + tableView = UITableView(frame: CGRect.zero, style: tableViewStyle) + tableView!.dataSource = self + tableView!.delegate = self + tableView!.estimatedRowHeight = 44.0; + tableView!.separatorStyle = .none; + + switch tableViewStyle { + case .plain: + tableView!.backgroundColor = theme.colorForType(.NormalBackground) + case .grouped: + tableView!.backgroundColor = theme.colorForType(.SettingsBackground) + case .insetGrouped: + print("error") + } + + view.addSubview(tableView!) + + tableView!.register(StaticTableButtonCell.self, forCellReuseIdentifier: StaticTableButtonCell.staticReuseIdentifier) + tableView!.register(StaticTableAvatarCell.self, forCellReuseIdentifier: StaticTableAvatarCell.staticReuseIdentifier) + tableView!.register(StaticTableDefaultCell.self, forCellReuseIdentifier: StaticTableDefaultCell.staticReuseIdentifier) + tableView!.register(StaticTableChatButtonsCell.self, forCellReuseIdentifier: StaticTableChatButtonsCell.staticReuseIdentifier) + tableView!.register(StaticTableSwitchCell.self, forCellReuseIdentifier: StaticTableSwitchCell.staticReuseIdentifier) + tableView!.register(StaticTableInfoCell.self, forCellReuseIdentifier: StaticTableInfoCell.staticReuseIdentifier) + tableView!.register(StaticTableMultiChoiceButtonCell.self, forCellReuseIdentifier: StaticTableMultiChoiceButtonCell.staticReuseIdentifier) + } + + func installConstraints() { + tableView!.snp.makeConstraints { + $0.edges.equalTo(view) + } + } + + func dequeueCellForClass(_ identifier: String) -> StaticTableBaseCell { + return tableView!.dequeueReusableCell(withIdentifier: identifier) as! StaticTableBaseCell + } +} diff --git a/Antidote/StaticTableDefaultCell.swift b/Antidote/StaticTableDefaultCell.swift new file mode 100644 index 0000000..2b475a3 --- /dev/null +++ b/Antidote/StaticTableDefaultCell.swift @@ -0,0 +1,258 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit +import SnapKit + +private struct Constants { + static let EdgesVerticalOffset = 10.0 + static let TitleHeight = 20.0 + static let TitleToUserStatusOffset = 7.0 + static let TitleToValueOffset = 2.0 + static let MinValueLabelHeight = 20.0 +} + +class StaticTableDefaultCell: StaticTableBaseCell { + fileprivate var userStatusView: UserStatusView! + fileprivate var titleLabel: UILabel! + fileprivate var valueLabel: CopyLabel! + fileprivate var rightButton: UIButton! + fileprivate var rightImageView: UIImageView! + + fileprivate var userStatusViewVisibleConstraint: Constraint! + fileprivate var userStatusViewHiddenConstraint: Constraint! + + fileprivate var valueLabelToTitleConstraint: Constraint! + fileprivate var valueLabelToContentTopConstraint: Constraint! + + fileprivate var valueLabelToArrowConstraint: Constraint! + fileprivate var valueLabelToContentRightConstraint: Constraint! + + fileprivate var rightButtonHandler: (() -> Void)? + + fileprivate var checkmarkSelected: Bool = false + + override func setupWithTheme(_ theme: Theme, model: BaseCellModel) { + super.setupWithTheme(theme, model: model) + + guard let defaultModel = model as? StaticTableDefaultCellModel else { + assert(false, "Wrong model \(model) passed to cell \(self)") + return + } + + if let userStatus = defaultModel.userStatus { + userStatusView.theme = theme + userStatusView.userStatus = userStatus + userStatusView.isHidden = false + + userStatusViewHiddenConstraint.deactivate() + userStatusViewVisibleConstraint.activate() + } + else { + userStatusView.isHidden = true + + userStatusViewVisibleConstraint.deactivate() + userStatusViewHiddenConstraint.activate() + } + + titleLabel.textColor = theme.colorForType(.LinkText) + valueLabel.textColor = theme.colorForType(.NormalText) + rightButton.setTitleColor(theme.colorForType(.LinkText), for: UIControlState()) + + titleLabel.text = defaultModel.title + valueLabel.text = defaultModel.value + valueLabel.copyable = defaultModel.canCopyValue + + rightButton.isHidden = (defaultModel.rightButton == nil) + rightButton.setTitle(defaultModel.rightButton, for: UIControlState()) + rightButtonHandler = defaultModel.rightButtonHandler + + let showRightImageView: Bool + switch defaultModel.rightImageType { + case .none: + showRightImageView = false + checkmarkSelected = false + case .arrow: + showRightImageView = true + rightImageView.image = UIImage(named: "right-arrow")!.flippedToCorrectLayout() + checkmarkSelected = false + case .checkmark: + showRightImageView = true + rightImageView.image = UIImage(named: "checkmark")! + checkmarkSelected = true + } + + if defaultModel.userInteractionEnabled { + selectionStyle = .default + } + else { + selectionStyle = .none + } + + if defaultModel.title != nil { + valueLabelToContentTopConstraint.deactivate() + valueLabelToTitleConstraint.activate() + } + else { + valueLabelToTitleConstraint.deactivate() + valueLabelToContentTopConstraint.activate() + } + + if showRightImageView { + rightImageView.isHidden = false + + valueLabelToContentRightConstraint.deactivate() + valueLabelToArrowConstraint.activate() + } + else { + rightImageView.isHidden = true + + valueLabelToArrowConstraint.deactivate() + valueLabelToContentRightConstraint.activate() + } + } + + override func createViews() { + super.createViews() + + userStatusView = UserStatusView() + userStatusView.showExternalCircle = false + customContentView.addSubview(userStatusView) + + titleLabel = UILabel() + titleLabel.font = UIFont.antidoteFontWithSize(17.0, weight: .light) + titleLabel.backgroundColor = UIColor.clear + customContentView.addSubview(titleLabel) + + valueLabel = CopyLabel() + valueLabel.numberOfLines = 0 + valueLabel.font = UIFont.systemFont(ofSize: 17.0) + valueLabel.backgroundColor = UIColor.clear + customContentView.addSubview(valueLabel) + + rightButton = UIButton() + rightButton.addTarget(self, action: #selector(StaticTableDefaultCell.rightButtonPressed), for: .touchUpInside) + customContentView.addSubview(rightButton) + + rightImageView = UIImageView() + customContentView.addSubview(rightImageView) + } + + override func installConstraints() { + super.installConstraints() + + userStatusView.snp.makeConstraints { + $0.centerY.equalTo(customContentView) + $0.leading.equalTo(customContentView) + $0.size.equalTo(UserStatusView.Constants.DefaultSize) + } + + titleLabel.snp.makeConstraints { + $0.top.equalTo(customContentView).offset(Constants.EdgesVerticalOffset) + $0.height.equalTo(Constants.TitleHeight) + + userStatusViewVisibleConstraint = $0.leading.equalTo(userStatusView.snp.trailing).offset(Constants.TitleToUserStatusOffset).constraint + } + + userStatusViewVisibleConstraint.deactivate() + + titleLabel.snp.makeConstraints { + userStatusViewHiddenConstraint = $0.leading.equalTo(customContentView).constraint + } + + valueLabel.snp.makeConstraints { + valueLabelToTitleConstraint = $0.top.equalTo(titleLabel.snp.bottom).offset(Constants.TitleToValueOffset).constraint + valueLabelToContentTopConstraint = $0.top.equalTo(customContentView).offset(Constants.EdgesVerticalOffset).constraint + + valueLabelToContentRightConstraint = $0.trailing.equalTo(customContentView).constraint + + $0.leading.equalTo(titleLabel) + $0.bottom.equalTo(customContentView).offset(-Constants.EdgesVerticalOffset) + $0.height.greaterThanOrEqualTo(Constants.MinValueLabelHeight) + } + + // TODO fix warning in log + valueLabelToTitleConstraint.deactivate() + + rightButton.snp.makeConstraints { + $0.leading.greaterThanOrEqualTo(titleLabel.snp.trailing) + $0.trailing.equalTo(customContentView) + $0.centerY.equalTo(titleLabel) + $0.bottom.lessThanOrEqualTo(customContentView) + } + + rightImageView.snp.makeConstraints { + $0.centerY.equalTo(customContentView) + $0.trailing.equalTo(customContentView) + + valueLabelToArrowConstraint = $0.leading.greaterThanOrEqualTo(valueLabel.snp.trailing).constraint + } + } +} + +// Accessibility +extension StaticTableDefaultCell { + override var isAccessibilityElement: Bool { + get { + return true + } + set {} + } + + override var accessibilityLabel: String? { + get { + return titleLabel.text ?? valueLabel.text + } + set {} + } + + override var accessibilityValue: String? { + get { + if titleLabel.text != nil { + return valueLabel.text + } + + return nil + } + set {} + } + + override var accessibilityHint: String? { + get { + if valueLabel.copyable { + return String(localized: "accessibility_show_copy_hint") + } + + if selectionStyle == .none { + return nil + } + + return String(localized: "accessibility_edit_value_hint") + } + set {} + } + + override var accessibilityTraits: UIAccessibilityTraits { + get { + if selectionStyle == .none { + return UIAccessibilityTraitStaticText + } + + var traits = UIAccessibilityTraitButton + + if checkmarkSelected { + traits |= UIAccessibilityTraitSelected + } + + return traits + } + set {} + } +} + +extension StaticTableDefaultCell { + @objc func rightButtonPressed() { + rightButtonHandler?() + } +} diff --git a/Antidote/StaticTableDefaultCellModel.swift b/Antidote/StaticTableDefaultCellModel.swift new file mode 100644 index 0000000..70d306a --- /dev/null +++ b/Antidote/StaticTableDefaultCellModel.swift @@ -0,0 +1,28 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +class StaticTableDefaultCellModel: StaticTableSelectableCellModel { + enum RightImageType { + case none + case arrow + case checkmark + } + + var userStatus: UserStatus? + var connectionStatus: ConnectionStatus? + + var title: String? + var value: String? + + var rightButton: String? + var rightButtonHandler: (() -> Void)? + + var rightImageType: RightImageType = .none + + var userInteractionEnabled: Bool = true + + var canCopyValue: Bool = false +} diff --git a/Antidote/StaticTableInfoCell.swift b/Antidote/StaticTableInfoCell.swift new file mode 100644 index 0000000..b877a1f --- /dev/null +++ b/Antidote/StaticTableInfoCell.swift @@ -0,0 +1,123 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit +import SnapKit + +private struct Constants { + static let ValueToArrowOffset = 6.0 +} + +class StaticTableInfoCell: StaticTableBaseCell { + fileprivate var valueChangedHandler: ((Bool) -> Void)? + + fileprivate var titleLabel: UILabel! + fileprivate var valueLabel: UILabel! + fileprivate var arrowImageView: UIImageView! + + fileprivate var valueLabelToContentRightConstraint: Constraint! + fileprivate var valueLabelToArrowConstraint: Constraint! + + override func setupWithTheme(_ theme: Theme, model: BaseCellModel) { + super.setupWithTheme(theme, model: model) + + guard let infoModel = model as? StaticTableInfoCellModel else { + assert(false, "Wrong model \(model) passed to cell \(self)") + return + } + + titleLabel.textColor = theme.colorForType(.NormalText) + titleLabel.text = infoModel.title + + valueLabel.textColor = theme.colorForType(.LinkText) + valueLabel.text = infoModel.value + + + if infoModel.showArrow { + arrowImageView.isHidden = false + valueLabelToContentRightConstraint.deactivate() + valueLabelToArrowConstraint.activate() + selectionStyle = .default + } + else { + arrowImageView.isHidden = true + valueLabelToArrowConstraint.deactivate() + valueLabelToContentRightConstraint.activate() + selectionStyle = .none + } + } + + override func createViews() { + super.createViews() + + titleLabel = UILabel() + titleLabel.backgroundColor = UIColor.clear + customContentView.addSubview(titleLabel) + + valueLabel = UILabel() + valueLabel.backgroundColor = UIColor.clear + customContentView.addSubview(valueLabel) + + arrowImageView = UIImageView() + arrowImageView.image = UIImage(named: "right-arrow")!.flippedToCorrectLayout() + customContentView.addSubview(arrowImageView) + } + + override func installConstraints() { + super.installConstraints() + + titleLabel.snp.makeConstraints { + $0.centerY.equalTo(customContentView) + $0.leading.equalTo(customContentView) + } + + valueLabel.snp.makeConstraints { + $0.centerY.equalTo(customContentView) + $0.leading.greaterThanOrEqualTo(titleLabel.snp.trailing) + valueLabelToContentRightConstraint = $0.trailing.equalTo(customContentView).constraint + } + + valueLabelToContentRightConstraint.deactivate() + + arrowImageView.snp.makeConstraints { + $0.centerY.equalTo(customContentView) + $0.trailing.equalTo(customContentView) + + valueLabelToArrowConstraint = $0.leading.greaterThanOrEqualTo(valueLabel.snp.trailing).offset(Constants.ValueToArrowOffset).constraint + } + + valueLabelToArrowConstraint.deactivate() + } +} + +// Accessibility +extension StaticTableInfoCell { + override var isAccessibilityElement: Bool { + get { + return true + } + set {} + } + + override var accessibilityLabel: String? { + get { + return titleLabel.text + } + set {} + } + + override var accessibilityValue: String? { + get { + return valueLabel.text + } + set {} + } + + override var accessibilityTraits: UIAccessibilityTraits { + get { + return arrowImageView.isHidden ? UIAccessibilityTraitStaticText : UIAccessibilityTraitButton + } + set {} + } +} diff --git a/Antidote/StaticTableInfoCellModel.swift b/Antidote/StaticTableInfoCellModel.swift new file mode 100644 index 0000000..8433296 --- /dev/null +++ b/Antidote/StaticTableInfoCellModel.swift @@ -0,0 +1,12 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +class StaticTableInfoCellModel: StaticTableSelectableCellModel { + var title: String? + var value: String? + + var showArrow: Bool = false +} diff --git a/Antidote/StaticTableMultiChoiceButtonCell.swift b/Antidote/StaticTableMultiChoiceButtonCell.swift new file mode 100644 index 0000000..1a05ef7 --- /dev/null +++ b/Antidote/StaticTableMultiChoiceButtonCell.swift @@ -0,0 +1,91 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit +import SnapKit + +private struct Constants { + static let HorizontalOffset = 8.0 + static let Height = 40.0 +} + +class StaticTableMultiChoiceButtonCell: StaticTableBaseCell { + fileprivate var buttonsContainer: UIView! + + override func setupWithTheme(_ theme: Theme, model: BaseCellModel) { + super.setupWithTheme(theme, model: model) + + guard let multiModel = model as? StaticTableMultiChoiceButtonCellModel else { + assert(false, "Wrong model \(model) passed to cell \(self)") + return + } + + selectionStyle = .none + + _ = buttonsContainer.subviews.map { + $0.removeFromSuperview() + } + + var previousButton: RoundedButton? + + for buttonModel in multiModel.buttons { + let button = addButtonWithTheme(theme, model: buttonModel) + + button.snp.makeConstraints { + $0.top.bottom.equalTo(buttonsContainer) + + if let previousButton = previousButton { + $0.leading.equalTo(previousButton.snp.trailing).offset(Constants.HorizontalOffset) + $0.width.equalTo(previousButton) + } + else { + $0.leading.equalTo(buttonsContainer) + } + } + previousButton = button + } + + if let previousButton = previousButton { + previousButton.snp.makeConstraints { + $0.trailing.equalTo(buttonsContainer) + } + } + } + + override func createViews() { + super.createViews() + + buttonsContainer = UIView() + buttonsContainer.backgroundColor = .clear + customContentView.addSubview(buttonsContainer) + } + + override func installConstraints() { + super.installConstraints() + + buttonsContainer.snp.makeConstraints { + $0.leading.trailing.equalTo(customContentView) + $0.centerY.equalTo(customContentView) + $0.height.equalTo(Constants.Height) + } + } + + func addButtonWithTheme(_ theme: Theme, model: StaticTableMultiChoiceButtonCellModel.ButtonModel) -> RoundedButton { + let type: RoundedButton.ButtonType + + switch model.style { + case .negative: + type = .runningNegative + case .positive: + type = .runningPositive + } + + let button = RoundedButton(theme: theme, type: type) + button.setTitle(model.title, for: UIControlState()) + button.addTarget(model.target, action: model.action, for: .touchUpInside) + buttonsContainer.addSubview(button) + + return button + } +} diff --git a/Antidote/StaticTableMultiChoiceButtonCellModel.swift b/Antidote/StaticTableMultiChoiceButtonCellModel.swift new file mode 100644 index 0000000..d899ef0 --- /dev/null +++ b/Antidote/StaticTableMultiChoiceButtonCellModel.swift @@ -0,0 +1,21 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +class StaticTableMultiChoiceButtonCellModel: StaticTableBaseCellModel { + enum ButtonStyle { + case negative + case positive + } + + struct ButtonModel { + let title: String + let style: ButtonStyle + let target: AnyObject? + let action: Selector + } + + var buttons = [ButtonModel]() +} diff --git a/Antidote/StaticTableSelectableCellModel.swift b/Antidote/StaticTableSelectableCellModel.swift new file mode 100644 index 0000000..389e58a --- /dev/null +++ b/Antidote/StaticTableSelectableCellModel.swift @@ -0,0 +1,9 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +class StaticTableSelectableCellModel: StaticTableBaseCellModel { + var didSelectHandler: ((StaticTableBaseCell) -> Void)? +} diff --git a/Antidote/StaticTableSwitchCell.swift b/Antidote/StaticTableSwitchCell.swift new file mode 100644 index 0000000..ceb8ce1 --- /dev/null +++ b/Antidote/StaticTableSwitchCell.swift @@ -0,0 +1,122 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit +import SnapKit + +class StaticTableSwitchCell: StaticTableBaseCell { + fileprivate var valueChangedHandler: ((Bool) -> Void)? + + fileprivate var titleLabel: UILabel! + fileprivate var accessibilityButton: UIButton! + fileprivate var switchView: UISwitch! + + override func setupWithTheme(_ theme: Theme, model: BaseCellModel) { + super.setupWithTheme(theme, model: model) + + guard let switchModel = model as? StaticTableSwitchCellModel else { + assert(false, "Wrong model \(model) passed to cell \(self)") + return + } + + selectionStyle = .none + + titleLabel.textColor = theme.colorForType(.NormalText) + titleLabel.text = switchModel.title + + switchView.isEnabled = switchModel.enabled + switchView.tintColor = theme.colorForType(.LinkText) + switchView.isOn = switchModel.on + + valueChangedHandler = switchModel.valueChangedHandler + } + + override func createViews() { + super.createViews() + + titleLabel = UILabel() + titleLabel.backgroundColor = UIColor.clear + customContentView.addSubview(titleLabel) + + accessibilityButton = UIButton() + accessibilityButton.addTarget(self, + action: #selector(StaticTableSwitchCell.accessibilityButtonPressed), + for: .touchUpInside) + customContentView.addSubview(accessibilityButton) + + switchView = UISwitch() + switchView.addTarget(self, action: #selector(StaticTableSwitchCell.switchValueChanged), for: .valueChanged) + customContentView.addSubview(switchView) + } + + override func installConstraints() { + super.installConstraints() + + titleLabel.snp.makeConstraints { + $0.centerY.equalTo(customContentView) + $0.leading.equalTo(customContentView) + } + + accessibilityButton.snp.makeConstraints { + $0.edges.equalTo(customContentView) + } + + switchView.snp.makeConstraints { + $0.centerY.equalTo(customContentView) + $0.leading.greaterThanOrEqualTo(titleLabel.snp.trailing) + $0.trailing.equalTo(customContentView) + } + } +} + +// Accessibility +extension StaticTableSwitchCell { + override var isAccessibilityElement: Bool { + get { + return true + } + set {} + } + + override var accessibilityLabel: String? { + get { + return titleLabel.text + } + set {} + } + + override var accessibilityValue: String? { + get { + return switchView.accessibilityValue + } + set {} + } + + override var accessibilityHint: String? { + get { + return switchView.accessibilityHint + } + set {} + } + + override var accessibilityTraits: UIAccessibilityTraits { + get { + return switchView.accessibilityTraits + } + set {} + } +} + +extension StaticTableSwitchCell { + @objc func accessibilityButtonPressed() { + if UIAccessibilityIsVoiceOverRunning() { + switchView.isOn = !switchView.isOn + switchValueChanged() + } + } + + @objc func switchValueChanged() { + valueChangedHandler?(switchView.isOn) + } +} diff --git a/Antidote/StaticTableSwitchCellModel.swift b/Antidote/StaticTableSwitchCellModel.swift new file mode 100644 index 0000000..5e60937 --- /dev/null +++ b/Antidote/StaticTableSwitchCellModel.swift @@ -0,0 +1,14 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +class StaticTableSwitchCellModel: StaticTableBaseCellModel { + var title: String? + var on: Bool = false + + var valueChangedHandler: ((Bool) -> Void)? + + var enabled: Bool = true +} diff --git a/Antidote/StringExtension.swift b/Antidote/StringExtension.swift new file mode 100644 index 0000000..08e5a3a --- /dev/null +++ b/Antidote/StringExtension.swift @@ -0,0 +1,70 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +extension String { + init(timeInterval: TimeInterval) { + var timeInterval = timeInterval + + let hours = Int(timeInterval / 3600) + timeInterval -= TimeInterval(hours * 3600) + + let minutes = Int(timeInterval / 60) + timeInterval -= TimeInterval(minutes * 60) + + let seconds = Int(timeInterval) + + if hours > 0 { + self.init(format: "%02d:%02d:%02d", hours, minutes, seconds) + } + else { + self.init(format: "%02d:%02d", minutes, seconds) + } + } + + init(localized: String, _ arguments: CVarArg...) { + let format = NSLocalizedString(localized, tableName: nil, bundle: Bundle.main, value: "", comment: "") + self.init(format: format, arguments: arguments) + } + + init(localized: String, comment: String, _ arguments: CVarArg...) { + let format = NSLocalizedString(localized, tableName: nil, bundle: Bundle.main, value: "", comment: comment) + self.init(format: format, arguments: arguments) + } + + func substringToByteLength(_ length: Int, encoding: String.Encoding) -> String { + guard length > 0 else { + return "" + } + + var substring = self as NSString + + while substring.lengthOfBytes(using: encoding.rawValue) > length { + let newLength = substring.length - 1 + + guard newLength > 0 else { + return "" + } + + substring = substring.substring(to: newLength) as NSString + } + + return substring as String + } + + func stringSizeWithFont(_ font: UIFont) -> CGSize { + return stringSizeWithFont(font, constrainedToSize:CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude)) + } + + func stringSizeWithFont(_ font: UIFont, constrainedToSize size: CGSize) -> CGSize { + let boundingRect = (self as NSString).boundingRect( + with: size, + options: .usesLineFragmentOrigin, + attributes: [NSAttributedStringKey.font : font], + context: nil) + + return CGSize(width: ceil(boundingRect.size.width), height: ceil(boundingRect.size.height)) + } +} diff --git a/Antidote/TabBarAbstractItem.swift b/Antidote/TabBarAbstractItem.swift new file mode 100644 index 0000000..192ed8d --- /dev/null +++ b/Antidote/TabBarAbstractItem.swift @@ -0,0 +1,33 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit + +class TabBarAbstractItem: UIView { + var selected: Bool = false + var didTapHandler: (() -> Void)? +} + +// Accessibility +extension TabBarAbstractItem { + override var isAccessibilityElement: Bool { + get { + return true + } + set {} + } + + override var accessibilityTraits: UIAccessibilityTraits { + get { + var value = UIAccessibilityTraitButton + + if selected { + value |= UIAccessibilityTraitSelected + } + + return value + } + set {} + } +} diff --git a/Antidote/TabBarBadgeItem.swift b/Antidote/TabBarBadgeItem.swift new file mode 100644 index 0000000..6561286 --- /dev/null +++ b/Antidote/TabBarBadgeItem.swift @@ -0,0 +1,184 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit +import SnapKit + +private struct Constants { + static let ImageAndTextContainerYOffset = 2.0 + static let ImageAndTextOffset = 3.0 + + static let BadgeTopOffset = -5.0 + static let BadgeHorizontalOffset = 5.0 + static let BadgeMinimumWidth = 22.0 + static let BadgeHeight: CGFloat = 18.0 +} + +class TabBarBadgeItem: TabBarAbstractItem { + override var selected: Bool { + didSet { + let color = theme.colorForType(selected ? .TabItemActive : .TabItemInactive) + + textLabel.textColor = color + imageView.tintColor = color + } + } + + var image: UIImage? { + didSet { + imageView.image = image?.withRenderingMode(.alwaysTemplate) + } + } + var text: String? { + didSet { + textLabel.text = text + } + } + + var badgeText: String? { + didSet { + badgeTextWasUpdated() + } + } + + /// If there is any badge text, accessibilityValue will be set to + var badgeAccessibilityEnding: String? + + fileprivate let theme: Theme + + fileprivate var imageAndTextContainer: UIView! + fileprivate var imageView: UIImageView! + fileprivate var textLabel: UILabel! + + fileprivate var badgeContainer: UIView! + fileprivate var badgeLabel: UILabel! + + fileprivate var button: UIButton! + + init(theme: Theme) { + self.theme = theme + + super.init(frame: CGRect.zero) + + backgroundColor = .clear + + createViews() + installConstraints() + + badgeTextWasUpdated() + } + + required convenience init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +// Accessibility +extension TabBarBadgeItem { + override var accessibilityLabel: String? { + get { + return text + } + set {} + } + + override var accessibilityValue: String? { + get { + guard var result = badgeText else { + return nil + } + + if let ending = badgeAccessibilityEnding { + result += " " + ending + } + + return result + } + set {} + } +} + +// Actions +extension TabBarBadgeItem { + @objc func buttonPressed() { + didTapHandler?() + } +} + +private extension TabBarBadgeItem { + func createViews() { + imageAndTextContainer = UIView() + imageAndTextContainer.backgroundColor = .clear + addSubview(imageAndTextContainer) + + imageView = UIImageView() + imageView.backgroundColor = .clear + imageAndTextContainer.addSubview(imageView) + + textLabel = UILabel() + textLabel.textColor = theme.colorForType(.NormalText) + textLabel.textAlignment = .center + textLabel.backgroundColor = .clear + textLabel.font = UIFont.systemFont(ofSize: 10.0) + imageAndTextContainer.addSubview(textLabel) + + badgeContainer = UIView() + badgeContainer.backgroundColor = theme.colorForType(.TabBadgeBackground) + badgeContainer.layer.masksToBounds = true + badgeContainer.layer.cornerRadius = Constants.BadgeHeight / 2 + addSubview(badgeContainer) + + badgeLabel = UILabel() + badgeLabel.textColor = theme.colorForType(.TabBadgeText) + badgeLabel.textAlignment = .center + badgeLabel.backgroundColor = .clear + badgeLabel.font = UIFont.antidoteFontWithSize(14.0, weight: .light) + badgeContainer.addSubview(badgeLabel) + + button = UIButton() + button.backgroundColor = .clear + button.addTarget(self, action: #selector(TabBarBadgeItem.buttonPressed), for: .touchUpInside) + addSubview(button) + } + + func installConstraints() { + imageAndTextContainer.snp.makeConstraints { + $0.centerX.equalTo(self) + $0.centerY.equalTo(self).offset(Constants.ImageAndTextContainerYOffset) + } + + imageView.snp.makeConstraints { + $0.top.equalTo(imageAndTextContainer) + $0.centerX.equalTo(imageAndTextContainer) + } + + textLabel.snp.makeConstraints { + $0.top.equalTo(imageView.snp.bottom).offset(Constants.ImageAndTextOffset) + $0.centerX.equalTo(imageAndTextContainer) + $0.bottom.equalTo(imageAndTextContainer) + } + + badgeContainer.snp.makeConstraints { + $0.leading.equalTo(imageAndTextContainer.snp.leading) + $0.top.equalTo(imageAndTextContainer.snp.top).offset(Constants.BadgeTopOffset) + $0.width.greaterThanOrEqualTo(Constants.BadgeMinimumWidth) + $0.height.equalTo(Constants.BadgeHeight) + } + + badgeLabel.snp.makeConstraints { + $0.leading.equalTo(badgeContainer).offset(Constants.BadgeHorizontalOffset) + $0.trailing.equalTo(badgeContainer).offset(-Constants.BadgeHorizontalOffset) + $0.centerY.equalTo(badgeContainer) + } + + button.snp.makeConstraints { + $0.edges.equalTo(self) + } + } + + func badgeTextWasUpdated() { + badgeLabel.text = badgeText + badgeContainer.isHidden = (badgeText == nil) || badgeText!.isEmpty + } +} diff --git a/Antidote/TabBarController.swift b/Antidote/TabBarController.swift new file mode 100644 index 0000000..890e0ad --- /dev/null +++ b/Antidote/TabBarController.swift @@ -0,0 +1,163 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit +import SnapKit + +private struct Constants { + static let HorizontalLineHeight = 0.5 +} + +class TabBarController: UITabBarController { + override var selectedIndex: Int { + didSet { + guard let navigation = viewControllers?[selectedIndex] as? UINavigationController else { + return + } + + navigation.delegate = self + + if oldValue == selectedIndex { + navigation.popToRootViewController(animated: true) + } + + updateSelectedItems() + } + } + + fileprivate let items: [TabBarAbstractItem] + + fileprivate let theme: Theme + + fileprivate var customTabBarView: UIView! + + fileprivate var customTabBarViewVisibleConstraint: Constraint! + fileprivate var customTabBarViewHiddenConstraint: Constraint! + + init(theme: Theme, controllers: [UINavigationController], tabBarItems: [TabBarAbstractItem]) { + self.theme = theme + self.items = tabBarItems + + super.init(nibName: nil, bundle: nil) + + viewControllers = controllers + + delegate = self + } + + required convenience init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { + super.viewDidLoad() + + createCustomTabBarView() + addItems() + installConstraints() + + updateSelectedItems() + } +} + +extension TabBarController: UITabBarControllerDelegate { + func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) { + guard let navigation = viewController as? UINavigationController else { + return + } + + navigation.delegate = self + } +} + +extension TabBarController: UINavigationControllerDelegate { + func navigationController( + _ navigationController: UINavigationController, + willShow viewController: UIViewController, + animated: Bool) { + tabBar.isHidden = true + + if viewController.hidesBottomBarWhenPushed { + customTabBarViewVisibleConstraint.deactivate() + customTabBarViewHiddenConstraint.activate() + } + else { + customTabBarViewHiddenConstraint.deactivate() + customTabBarViewVisibleConstraint.activate() + } + } +} + +extension TabBarController { + func createCustomTabBarView() { + customTabBarView = UIView() + customTabBarView.backgroundColor = theme.colorForType(.NormalBackground) + view.addSubview(customTabBarView) + + let horizontalLine = UIView() + horizontalLine.backgroundColor = theme.colorForType(.SeparatorsAndBorders) + customTabBarView.addSubview(horizontalLine) + + horizontalLine.snp.makeConstraints { + $0.top.leading.trailing.equalTo(customTabBarView) + $0.height.equalTo(Constants.HorizontalLineHeight) + } + } + + func addItems() { + for (index, item) in items.enumerated() { + item.didTapHandler = { [weak self] in + self?.selectedIndex = index + } + + customTabBarView.addSubview(item) + } + } + + func installConstraints() { + customTabBarView.snp.makeConstraints { + customTabBarViewVisibleConstraint = $0.bottom.equalTo(view.snp.bottom).constraint + customTabBarViewHiddenConstraint = $0.top.equalTo(view.snp.bottom).constraint + $0.leading.trailing.equalTo(view) + $0.height.equalTo(tabBar.frame.size.height) + // TODO: this moves the view a bit more to the top, because the home button "line" is in the way otherwise + // please fix me properly in the future + if #available(iOS 11.0, *) { + let keyWindow = UIApplication.shared.keyWindow + let b = keyWindow?.safeAreaInsets.bottom + customTabBarViewVisibleConstraint?.update(offset: -(b ?? 20)) + } + + } + + customTabBarViewHiddenConstraint.deactivate() + + var previous: TabBarAbstractItem? + + for item in items { + item.snp.makeConstraints { + $0.top.bottom.equalTo(customTabBarView) + + if previous != nil { + $0.leading.equalTo(previous!.snp.trailing) + $0.width.equalTo(previous!) + } + else { + $0.leading.equalTo(customTabBarView) + } + } + + previous = item + } + previous!.snp.makeConstraints { + $0.trailing.equalTo(customTabBarView) + } + } + + func updateSelectedItems() { + for (index, item) in items.enumerated() { + item.selected = (index == selectedIndex) + } + } +} diff --git a/Antidote/TabBarProfileItem.swift b/Antidote/TabBarProfileItem.swift new file mode 100644 index 0000000..88dbcd4 --- /dev/null +++ b/Antidote/TabBarProfileItem.swift @@ -0,0 +1,110 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + + +import SnapKit + +private struct Constants { + static let ImageSize = 32.0 +} + +class TabBarProfileItem: TabBarAbstractItem { + override var selected: Bool { + didSet { + imageViewWithStatus.imageView.tintColor = theme.colorForType(selected ? .TabItemActive : .TabItemInactive) + } + } + + var userStatus: UserStatus = .offline { + didSet { + imageViewWithStatus.userStatusView.userStatus = userStatus + } + } + + var connectionStatus: ConnectionStatus = .none { + didSet { + imageViewWithStatus.userStatusView.connectionStatus = connectionStatus + } + } + + var userImage: UIImage? { + didSet { + if let image = userImage { + imageViewWithStatus.imageView.image = image + } + else { + imageViewWithStatus.imageView.image = UIImage.templateNamed("tab-bar-profile") + } + } + } + + fileprivate let theme: Theme + + fileprivate var imageViewWithStatus: ImageViewWithStatus! + fileprivate var button: UIButton! + + init(theme: Theme) { + self.theme = theme + + super.init(frame: CGRect.zero) + + backgroundColor = .clear + + createViews() + installConstraints() + } + + required convenience init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +// Accessibility +extension TabBarProfileItem { + override var accessibilityLabel: String? { + get { + return String(localized: "profile_title") + } + set {} + } + + override var accessibilityValue: String? { + get { + return userStatus.toString() + } + set {} + } +} + +// Actions +extension TabBarProfileItem { + @objc func buttonPressed() { + didTapHandler?() + } +} + +private extension TabBarProfileItem { + func createViews() { + imageViewWithStatus = ImageViewWithStatus() + imageViewWithStatus.userStatusView.theme = theme + addSubview(imageViewWithStatus) + + button = UIButton() + button.backgroundColor = .clear + button.addTarget(self, action: #selector(TabBarProfileItem.buttonPressed), for: .touchUpInside) + addSubview(button) + } + + func installConstraints() { + imageViewWithStatus.snp.makeConstraints { + $0.center.equalTo(self) + $0.size.equalTo(Constants.ImageSize) + } + + button.snp.makeConstraints { + $0.edges.equalTo(self) + } + } +} + diff --git a/Antidote/TextEditController.swift b/Antidote/TextEditController.swift new file mode 100644 index 0000000..9af31cc --- /dev/null +++ b/Antidote/TextEditController.swift @@ -0,0 +1,93 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit +import SnapKit + +private struct Constants { + static let Offset = 20.0 + static let FieldHeight = 40.0 +} + +class TextEditController: UIViewController { + fileprivate let theme: Theme + + fileprivate let defaultValue: String? + fileprivate let changeTextHandler: (String) -> Void + fileprivate let userFinishedEditing: () -> Void + + fileprivate var textField: UITextField! + + /** + Creates controller for editing single text field. + + - Parameters: + - theme: Theme controller will use. + - changeTextHandler: Handler called when user have changed the text. + - userFinishedEditing: Handler called when user have finished editing. + */ + init(theme: Theme, title: String, defaultValue: String?, changeTextHandler: @escaping (String) -> Void, userFinishedEditing: @escaping () -> Void) { + self.theme = theme + self.defaultValue = defaultValue + self.changeTextHandler = changeTextHandler + self.userFinishedEditing = userFinishedEditing + + super.init(nibName: nil, bundle: nil) + + self.title = title + edgesForExtendedLayout = UIRectEdge() + } + + required convenience init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func loadView() { + loadViewWithBackgroundColor(theme.colorForType(.NormalBackground)) + + createTextField() + installConstraints() + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + textField.becomeFirstResponder() + } + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + + changeTextHandler(textField.text ?? "") + } +} + +extension TextEditController: UITextFieldDelegate { + func textFieldShouldReturn(_ textField: UITextField) -> Bool { + changeTextHandler(textField.text ?? "") + userFinishedEditing() + + return false + } +} + +private extension TextEditController { + func createTextField() { + textField = UITextField() + textField.text = defaultValue + textField.delegate = self + textField.returnKeyType = .done + textField.borderStyle = .roundedRect + view.addSubview(textField) + } + + func installConstraints() { + textField.snp.makeConstraints { + $0.top.equalTo(view).offset(Constants.Offset) + $0.leading.equalTo(view).offset(Constants.Offset) + $0.trailing.equalTo(view).offset(-Constants.Offset) + $0.height.equalTo(Constants.FieldHeight) + } + } +} diff --git a/Antidote/TextViewController.swift b/Antidote/TextViewController.swift new file mode 100644 index 0000000..f69d492 --- /dev/null +++ b/Antidote/TextViewController.swift @@ -0,0 +1,82 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit +import SnapKit + +private struct Constants { + static let Offset = 10.0 + static let TitleColorKey = "TITLE_COLOR" + static let TextColorKey = "TEXT_COLOR" +} + +class TextViewController: UIViewController { + fileprivate let resourceName: String + fileprivate let backgroundColor: UIColor + fileprivate let titleColor: UIColor + fileprivate let textColor: UIColor + + fileprivate var textView: UITextView! + + init(resourceName: String, backgroundColor: UIColor, titleColor: UIColor, textColor: UIColor) { + self.resourceName = resourceName + self.backgroundColor = backgroundColor + self.titleColor = titleColor + self.textColor = textColor + + super.init(nibName: nil, bundle: nil) + } + + required convenience init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func loadView() { + loadViewWithBackgroundColor(backgroundColor) + + createTextView() + installConstraints() + + loadHtml() + } +} + +private extension TextViewController { + func createTextView() { + textView = UITextView() + textView.isEditable = false + textView.backgroundColor = .clear + view.addSubview(textView) + } + + func installConstraints() { + textView.snp.makeConstraints { + $0.leading.top.equalTo(view).offset(Constants.Offset) + $0.trailing.bottom.equalTo(view).offset(-Constants.Offset) + } + } + + func loadHtml() { + do { + struct FakeError: Error {} + guard let htmlFilePath = Bundle.main.path(forResource: resourceName, ofType: "html") else { + throw FakeError() + } + + var htmlString = try NSString(contentsOfFile: htmlFilePath, encoding: String.Encoding.utf8.rawValue) + htmlString = htmlString.replacingOccurrences(of: Constants.TitleColorKey, with: titleColor.hexString()) as NSString + htmlString = htmlString.replacingOccurrences(of: Constants.TextColorKey, with: textColor.hexString()) as NSString + + guard let data = htmlString.data(using: String.Encoding.unicode.rawValue) else { + throw FakeError() + } + let options = [ NSAttributedString.DocumentReadingOptionKey.documentType : NSAttributedString.DocumentType.html ] + + try textView.attributedText = NSAttributedString(data: data, options: options, documentAttributes: nil) + } + catch { + handleErrorWithType(.cannotLoadHTML) + } + } +} diff --git a/Antidote/Theme.swift b/Antidote/Theme.swift new file mode 100644 index 0000000..c6ca205 --- /dev/null +++ b/Antidote/Theme.swift @@ -0,0 +1,242 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit +import Yaml + +enum ErrorTheme: Error { + case cannotParseFile(String) + case wrongVersion(String) + + func debugDescription() -> String { + switch self { + case .cannotParseFile(let string): + return "Parse error: \(string)" + case .wrongVersion(let string): + return "Version error: \(string)" + } + } +} + +class Theme { + enum ColorType: String { + case LoginBackground = "login-background" + case LoginGradient = "login-gradient" + case LoginToxLogo = "login-tox-logo" + case LoginButtonText = "login-button-text" + case LoginButtonBackground = "login-button-background" + case LoginDescriptionLabel = "login-description-label" + case LoginFormBackground = "login-form-background" + case LoginFormText = "login-form-text" + case LoginLinkColor = "login-link-color" + + case TranslucentBackground = "translucent-background" + + case NormalBackground = "normal-background" + case NormalText = "normal-text" + case LinkText = "link-text" + case ConnectingBackground = "connecting-background" + case ConnectingText = "connecting-text" + case SeparatorsAndBorders = "separators-and-borders" + case OfflineStatus = "offline-status" + case OnlineStatus = "online-status" + case AwayStatus = "away-status" + case BusyStatus = "busy-status" + case StatusBackground = "status-background" + case FriendCellStatus = "friend-cell-status" + case ChatListCellMessage = "chat-list-cell-message" + case ChatListCellUnreadBackground = "chat-list-cell-unread-background" + case ChatInputBackground = "chat-input-background" + case ChatIncomingBubble = "chat-incoming-bubble" + case ChatOutgoingBubble = "chat-outgoing-bubble" + case ChatOutgoingUnreadBubble = "chat-outgoing-unread-bubble" + case ChatOutgoingSentPushBubble = "chat-outgoing-sentpush-bubble" + case ChatInformationText = "chat-information-text" + case TabBadgeBackground = "tab-badge-background" + case TabBadgeText = "tab-badge-text" + case TabItemActive = "tab-item-active" + case TabItemInactive = "tab-item-inactive" + case NotificationBackground = "notification-background" + case NotificationText = "notification-text" + case SettingsBackground = "settings-background" + case CallTextColor = "call-text-color" + case CallDeclineButtonBackground = "call-decline-button-background" + case CallAnswerButtonBackground = "call-answer-button-background" + case CallControlSelectedBackground = "call-control-selected-background" + case CallControlBackground = "call-control-background" + case CallButtonIconColor = "call-button-icon-color" + case CallButtonSelectedIconColor = "call-button-selected-icon-color" + case CallVideoPreviewBackground = "call-video-preview-background" + case RoundedButtonText = "rounded-button-text" + case RoundedPositiveButtonBackground = "rounded-positive-button-background" + case RoundedNegativeButtonBackground = "rounded-negative-button-background" + case EmptyScreenPlaceholderText = "empty-screen-placeholder-text" + case FileImageBackgroundActive = "file-image-background-active" + case FileImageCancelledText = "file-image-cancelled-text" + case FileImageAcceptButtonTint = "file-image-accept-button-tint" + case FileImageCancelButtonTint = "file-image-cancel-button-tint" + case LockGradientTop = "lock-gradient-top" + case LockGradientBottom = "lock-gradient-bottom" + case ChatListCellUnreadArrowBackground = "chat-list-cell-arrow-unread-background" + + // Because enums don't support enumerations we have to do this hack. Phew. + static let allValues = [ + LoginBackground, + LoginGradient, + LoginToxLogo, + LoginButtonText, + LoginButtonBackground, + LoginDescriptionLabel, + LoginFormBackground, + LoginFormText, + LoginLinkColor, + TranslucentBackground, + NormalBackground, + NormalText, + LinkText, + ConnectingBackground, + ConnectingText, + SeparatorsAndBorders, + OfflineStatus, + OnlineStatus, + AwayStatus, + BusyStatus, + StatusBackground, + FriendCellStatus, + ChatListCellMessage, + ChatListCellUnreadBackground, + ChatInputBackground, + ChatIncomingBubble, + ChatOutgoingBubble, + ChatOutgoingUnreadBubble, + ChatOutgoingSentPushBubble, + ChatInformationText, + TabBadgeBackground, + TabBadgeText, + TabItemActive, + TabItemInactive, + NotificationBackground, + NotificationText, + SettingsBackground, + CallTextColor, + CallDeclineButtonBackground, + CallAnswerButtonBackground, + CallControlBackground, + CallControlSelectedBackground, + CallButtonIconColor, + CallButtonSelectedIconColor, + CallVideoPreviewBackground, + RoundedButtonText, + RoundedPositiveButtonBackground, + RoundedNegativeButtonBackground, + EmptyScreenPlaceholderText, + FileImageBackgroundActive, + FileImageCancelledText, + FileImageAcceptButtonTint, + FileImageCancelButtonTint, + LockGradientTop, + LockGradientBottom, + ChatListCellUnreadArrowBackground, + ] + } + + init(yamlString: String) throws { + guard let dictionary = try Yaml.load(yamlString).dictionary else { + throw ErrorTheme.cannotParseFile(String(localized:"theme_error_cannot_open")) + } + + try checkVersion(dictionary) + + mappedColors = try createMappedColors(fromDictionary: dictionary) + try validateMappedColors(mappedColors) + } + + func colorForType(_ type: ColorType) -> UIColor { + return mappedColors[type.rawValue]! + } + + var loginNavigationBarColor: UIColor { + // https://developer.apple.com/library/ios/qa/qa1808/_index.html + let colorDelta: CGFloat = 0.08 + + var (red, green, blue, alpha) = colorForType(.LoginButtonBackground).components() + + red = max(0.0, red - colorDelta) + green = max(0.0, green - colorDelta) + blue = max(0.0, blue - colorDelta) + + return UIColor(red: red, green: green, blue: blue, alpha: alpha) + } + + fileprivate var mappedColors: [String: UIColor]! +} + +private extension Theme { + struct Constants { + static let VersionValue = 1 + static let VersionKey = "version" + static let ColorsKey = "colors" + static let ValuesKey = "values" + } + + func checkVersion(_ dictionary: [Yaml: Yaml]) throws { + guard let version = dictionary[Yaml.string(Constants.VersionKey)]?.int else { + throw ErrorTheme.cannotParseFile(String(localized:"theme_error_cannot_open")) + } + + guard version == Constants.VersionValue else { + throw ErrorTheme.wrongVersion(String(localized: "theme_error_cannot_open")) + } + } + + func createMappedColors(fromDictionary dictionary: [Yaml: Yaml]) throws -> [String: UIColor] { + let colorsDict = try parseDictionary(dictionary, forKey: Constants.ColorsKey) { (string: String) -> UIColor? in + return UIColor(hexString: string) + } + let valuesDict = try parseDictionary(dictionary, forKey: Constants.ValuesKey) { (string: String) -> String? in + return string + } + + var mappedColors = [String: UIColor]() + + for (key, value) in valuesDict { + guard let color = colorsDict[value] else { + throw ErrorTheme.cannotParseFile(String(localized: "theme_error_cannot_open", value)) + } + + mappedColors[key] = color + } + + return mappedColors + } + + func parseDictionary(_ dictionary: [Yaml: Yaml], forKey key: String, modifyValue: (String) -> T?) throws -> [String: T] { + guard let yamlDict = dictionary[Yaml.string(key)]?.dictionary else { + throw ErrorTheme.cannotParseFile(String(localized: "theme_error_cannot_open", key)) + } + + var resultDict = [String: T]() + + for (keyYaml, valueYaml) in yamlDict { + guard let key = keyYaml.string, + let originalValue = valueYaml.string, + let valueToSet = modifyValue(originalValue) else { + throw ErrorTheme.cannotParseFile(String(localized: "theme_error_cannot_open", keyYaml.description, valueYaml.description)) + } + + resultDict[key] = valueToSet + } + + return resultDict + } + + func validateMappedColors(_ dictionary: [String: UIColor]) throws { + for type in ColorType.allValues { + guard let _ = dictionary[type.rawValue] else { + throw ErrorTheme.cannotParseFile(String(localized: "theme_error_cannot_open", type.rawValue)) + } + } + } +} + diff --git a/Antidote/TopCoordinatorProtocol.swift b/Antidote/TopCoordinatorProtocol.swift new file mode 100644 index 0000000..c1e6351 --- /dev/null +++ b/Antidote/TopCoordinatorProtocol.swift @@ -0,0 +1,23 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +protocol TopCoordinatorProtocol: CoordinatorProtocol { + /** + Handle local notification. + + - Parameters: + - notification: Notification to handle + */ + func handleLocalNotification(_ notification: UILocalNotification) + + /** + Handle openURL request. + + - Parameters: + - url: URL to handle. + */ + func handleInboxURL(_ url: URL) +} diff --git a/Antidote/ToxFactory.swift b/Antidote/ToxFactory.swift new file mode 100644 index 0000000..0f646f0 --- /dev/null +++ b/Antidote/ToxFactory.swift @@ -0,0 +1,22 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +struct ToxFactory { + static func createToxWithConfiguration(_ configuration: OCTManagerConfiguration, + encryptPassword: String, + successBlock: @escaping (OCTManager) -> Void, + failureBlock: @escaping (Error) -> Void) { + if ProcessInfo.processInfo.arguments.contains("UI_TESTING") { + successBlock(OCTManagerMock()) + return + } + + OCTManagerFactory.manager(with: configuration, + encryptPassword: encryptPassword, + successBlock: successBlock, + failureBlock: failureBlock) + } +} diff --git a/Antidote/UIAlertControllerExtension.swift b/Antidote/UIAlertControllerExtension.swift new file mode 100644 index 0000000..c0d1385 --- /dev/null +++ b/Antidote/UIAlertControllerExtension.swift @@ -0,0 +1,63 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit + +extension UIAlertController { + class func showErrorWithMessage(_ message: String, retryBlock: (() -> Void)?) { + showWithTitle(String(localized: "error_title"), message: message, retryBlock: retryBlock) + } + + class func showWithTitle(_ title: String, message: String? = nil, retryBlock: (() -> Void)?) { + let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) + + + if let retryBlock = retryBlock { + alert.addAction(UIAlertAction(title: String(localized: "error_retry_button"), style: .default) { _ in + retryBlock() + }) + + alert.addAction(UIAlertAction(title: String(localized: "alert_cancel"), style: .cancel, handler: nil)) + } + else { + alert.addAction(UIAlertAction(title: String(localized: "error_ok_button"), style: .cancel, handler: nil)) + } + + guard let visible = visibleViewController() else { + return + } + + visible.present(alert, animated: true, completion: nil) + } + + fileprivate class func visibleViewController(_ rootViewController: UIViewController? = nil) -> UIViewController? { + var root: UIViewController + + if let rootViewController = rootViewController { + root = rootViewController + } + else { + let appDelegate = UIApplication.shared.delegate as? AppDelegate + + guard let controller = appDelegate?.window?.rootViewController else { + return nil + } + + root = controller + } + + guard let presented = root.presentedViewController else { + return root + } + + if let navigation = presented as? UINavigationController { + return visibleViewController(navigation.topViewController) + } + if let tabBar = presented as? UITabBarController { + return visibleViewController(tabBar.selectedViewController) + } + + return presented + } +} diff --git a/Antidote/UIApplicationExtension.swift b/Antidote/UIApplicationExtension.swift new file mode 100644 index 0000000..7a4d5fa --- /dev/null +++ b/Antidote/UIApplicationExtension.swift @@ -0,0 +1,20 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit + +extension UIApplication { + class var isActive: Bool { + get { + switch shared.applicationState { + case .active: + return true + case .inactive: + return false + case .background: + return false + } + } + } +} diff --git a/Antidote/UIColorExtension.swift b/Antidote/UIColorExtension.swift new file mode 100644 index 0000000..dc0235b --- /dev/null +++ b/Antidote/UIColorExtension.swift @@ -0,0 +1,59 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit + +extension UIColor { + convenience init?(hexString: String) { + var red: CGFloat = 0.0 + var green: CGFloat = 0.0 + var blue: CGFloat = 0.0 + var alpha: CGFloat = 1.0 + + guard let number = CLongLong(hexString, radix: 16) else { + return nil + } + + switch(hexString.count) { + case 6: + red = CGFloat((number & 0xFF0000) >> 16) / 255.0 + green = CGFloat((number & 0x00FF00) >> 8) / 255.0 + blue = CGFloat((number & 0x0000FF) >> 0) / 255.0 + case 8: + red = CGFloat((number & 0xFF000000) >> 24) / 255.0 + green = CGFloat((number & 0x00FF0000) >> 16) / 255.0 + blue = CGFloat((number & 0x0000FF00) >> 8) / 255.0 + alpha = CGFloat((number & 0x000000FF) >> 0) / 255.0 + default: + return nil + } + + self.init(red: red, green: green, blue: blue, alpha: alpha) + } + + func components() -> (red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) { + var red: CGFloat = 0.0 + var green: CGFloat = 0.0 + var blue: CGFloat = 0.0 + var alpha: CGFloat = 0.0 + + getRed(&red, green: &green, blue: &blue, alpha: &alpha) + + return (red, green, blue, alpha) + } + + func hexString() -> String { + let (red, green, blue, _) = components() + + return String(format: "%02x%02x%02x", Int(255 * red), Int(255 * green), Int(255 * blue)) + } + + func darkerColor() -> UIColor { + let (red, green, blue, alpha) = components() + let delta: CGFloat = 0.1 + + return UIColor(red: max(red - delta, 0.0), green: max(green - delta, 0.0), blue: max(blue - delta, 0.0), alpha: alpha) + } +} + diff --git a/Antidote/UIFontExtension.swift b/Antidote/UIFontExtension.swift new file mode 100644 index 0000000..c5236f8 --- /dev/null +++ b/Antidote/UIFontExtension.swift @@ -0,0 +1,47 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit + +extension UIFont { + enum AWeight { + case light + case medium + case bold + + func w() -> UIFont.Weight { + if #available(iOS 8.2, *) { + switch self { + case .light: + return UIFont.Weight.light + case .medium: + return UIFont.Weight.medium + case .bold: + return UIFont.Weight.bold + } + } + + return UIFont.Weight(0.0) + } + + func name() -> String { + switch self { + case .light: + return "HelveticaNeue-Light" + case .medium: + return "HelveticaNeue-Medium" + case .bold: + return "HelveticaNeue-Bold" + } + } + } + + class func antidoteFontWithSize(_ size: CGFloat, weight: AWeight) -> UIFont { + if #available(iOS 8.2, *) { + return UIFont.systemFont(ofSize: size, weight: weight.w()) + } else { + return UIFont(name: weight.name(), size: size)! + } + } +} diff --git a/Antidote/UIImageExtension.swift b/Antidote/UIImageExtension.swift new file mode 100644 index 0000000..ae8b847 --- /dev/null +++ b/Antidote/UIImageExtension.swift @@ -0,0 +1,86 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit + +extension UIImage { + class func emptyImage() -> UIImage { + return imageWithColor(.clear, size: CGSize(width: 1, height: 1)) + } + + class func imageWithColor(_ color: UIColor, size: CGSize) -> UIImage { + let rect = CGRect(origin: CGPoint.zero, size: size) + + UIGraphicsBeginImageContext(rect.size) + let context = UIGraphicsGetCurrentContext() + + context?.setFillColor(color.cgColor) + context?.fill(rect) + + let image = UIGraphicsGetImageFromCurrentImageContext() + UIGraphicsEndImageContext() + + return image! + } + + class func templateNamed(_ named: String) -> UIImage { + return UIImage(named: named)!.withRenderingMode(.alwaysTemplate) + } + + func scaleToSize(_ size: CGSize) -> UIImage { + UIGraphicsBeginImageContext(size) + draw(in: CGRect(origin: CGPoint.zero, size: size)) + let newImage = UIGraphicsGetImageFromCurrentImageContext() + UIGraphicsEndImageContext() + + return newImage! + } + + func cropWithRect(_ rect: CGRect) -> UIImage { + var rect = rect + + switch imageOrientation { + case .up: + fallthrough + case .upMirrored: + fallthrough + case .down: + fallthrough + case .downMirrored: + break + + case .left: + fallthrough + case .leftMirrored: + fallthrough + case .right: + fallthrough + case .rightMirrored: + var temp = rect.origin.x + rect.origin.x = rect.origin.y + rect.origin.y = temp + + temp = rect.size.width + rect.size.width = rect.size.height + rect.size.height = rect.size.width + } + + if (scale > 1.0) { + rect.origin.x *= scale + rect.origin.y *= scale + rect.size.width *= scale + rect.size.height *= scale + } + + let imageRef = self.cgImage?.cropping(to: rect)! + return UIImage(cgImage: imageRef!, scale: scale, orientation: imageOrientation) + } + + func flippedToCorrectLayout() -> UIImage { + if #available(iOS 9.0, *) { + return imageFlippedForRightToLeftLayoutDirection() + } + return self + } +} diff --git a/Antidote/UIViewControllerExtension.swift b/Antidote/UIViewControllerExtension.swift new file mode 100644 index 0000000..1114d49 --- /dev/null +++ b/Antidote/UIViewControllerExtension.swift @@ -0,0 +1,14 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit + +extension UIViewController { + func loadViewWithBackgroundColor(_ backgroundColor: UIColor) { + let frame = CGRect(origin: CGPoint.zero, size: UIScreen.main.bounds.size) + + view = UIView(frame: frame) + view.backgroundColor = backgroundColor + } +} diff --git a/Antidote/UserDefaultsManager.swift b/Antidote/UserDefaultsManager.swift new file mode 100644 index 0000000..e531bb0 --- /dev/null +++ b/Antidote/UserDefaultsManager.swift @@ -0,0 +1,139 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +class UserDefaultsManager { + var lastActiveProfile: String? { + get { + return stringForKey(Keys.LastActiveProfile) + } + set { + setObject(newValue as AnyObject?, forKey: Keys.LastActiveProfile) + } + } + + var UDPEnabled: Bool { + get { + return boolForKey(Keys.UDPEnabled, defaultValue: false) + } + set { + setBool(newValue, forKey: Keys.UDPEnabled) + } + } + + var EchobotAdded: Bool { + get { + return boolForKey(Keys.EchobotAdded, defaultValue: false) + } + set { + setBool(newValue, forKey: Keys.EchobotAdded) + } + } + + var DebugMode: Bool { + get { + return boolForKey(Keys.DebugMode, defaultValue: false) + } + set { + setBool(newValue, forKey: Keys.DebugMode) + } + } + + var DateonmessageMode: Bool { + get { + return boolForKey(Keys.DateonmessageMode, defaultValue: true) + } + set { + setBool(newValue, forKey: Keys.DateonmessageMode) + } + } + + var LongerbgMode: Bool { + get { + return boolForKey(Keys.LongerbgMode, defaultValue: false) + } + set { + setBool(newValue, forKey: Keys.LongerbgMode) + } + } + + var showNotificationPreview: Bool { + get { + return boolForKey(Keys.ShowNotificationsPreview, defaultValue: true) + } + set { + setBool(newValue, forKey: Keys.ShowNotificationsPreview) + } + } + + enum AutodownloadImages: String { + case Never + case UsingWiFi + case Always + } + + var autodownloadImages: AutodownloadImages { + get { + let defaultValue = AutodownloadImages.Never //Easy enough to reach option for users. Reverting change since there is an extremely high risk of people getting in trouble since an attacked can get you in prison by sending you cp. + + guard let string = stringForKey(Keys.AutodownloadImages) else { + return defaultValue + } + return AutodownloadImages(rawValue: string) ?? defaultValue + } + set { + setObject(newValue.rawValue as AnyObject?, forKey: Keys.AutodownloadImages) + } + } + + func resetUDPEnabled() { + removeObjectForKey(Keys.UDPEnabled) + } +} + +private extension UserDefaultsManager { + struct Keys { + static let LastActiveProfile = "user-info/last-active-profile" + static let EchobotAdded = "user-info/echobot-added" + static let DebugMode = "user-info/debug-mode" + static let DateonmessageMode = "user-info/dateonmessage-mode" + static let UDPEnabled = "user-info/udp-enabled" + static let ShowNotificationsPreview = "user-info/snow-notification-preview" + static let LongerbgMode = "user-info/longerbg-mode" + static let AutodownloadImages = "user-info/autodownload-images" + } + + func setObject(_ object: AnyObject?, forKey key: String) { + let defaults = UserDefaults.standard + defaults.set(object, forKey:key) + defaults.synchronize() + } + + func stringForKey(_ key: String) -> String? { + let defaults = UserDefaults.standard + return defaults.string(forKey: key) + } + + func setBool(_ value: Bool, forKey key: String) { + let defaults = UserDefaults.standard + defaults.set(value, forKey: key) + defaults.synchronize() + } + + func boolForKey(_ key: String, defaultValue: Bool) -> Bool { + let defaults = UserDefaults.standard + + if let result = defaults.object(forKey: key) { + return (result as AnyObject).boolValue + } + else { + return defaultValue + } + } + + func removeObjectForKey(_ key: String) { + let defaults = UserDefaults.standard + defaults.removeObject(forKey: key) + defaults.synchronize() + } +} diff --git a/Antidote/UserStatus.swift b/Antidote/UserStatus.swift new file mode 100644 index 0000000..5afdedf --- /dev/null +++ b/Antidote/UserStatus.swift @@ -0,0 +1,38 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +enum UserStatus { + case offline + case online + case away + case busy + + init(connectionStatus: OCTToxConnectionStatus, userStatus: OCTToxUserStatus) { + switch (connectionStatus, userStatus) { + case (.none, _): + self = .offline + case (_, .none): + self = .online + case (_, .away): + self = .away + case (_, .busy): + self = .busy + } + } + + func toString() -> String { + switch self { + case .offline: + return String(localized: "status_offline") + case .online: + return String(localized: "status_online") + case .away: + return String(localized: "status_away") + case .busy: + return String(localized: "status_busy") + } + } +} diff --git a/Antidote/UserStatusView.swift b/Antidote/UserStatusView.swift new file mode 100644 index 0000000..aaa18a6 --- /dev/null +++ b/Antidote/UserStatusView.swift @@ -0,0 +1,114 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit +import SnapKit + +class UserStatusView: StaticBackgroundView { + struct Constants { + static let DefaultSize = 14.0 + } + + fileprivate var roundView: StaticBackgroundView? + + var theme: Theme? { + didSet { + userStatusWasUpdated() + } + } + + var showExternalCircle: Bool = true { + didSet { + userStatusWasUpdated() + } + } + + var userStatus: UserStatus = .offline { + didSet { + userStatusWasUpdated() + } + } + + var connectionStatus: ConnectionStatus = .none { + didSet { + userStatusWasUpdated() + } + } + + init() { + super.init(frame: CGRect.zero) + + createRoundView() + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func layoutSubviews() { + super.layoutSubviews() + + userStatusWasUpdated() + } + + override var frame: CGRect { + didSet { + userStatusWasUpdated() + } + } +} + +private extension UserStatusView { + func createRoundView() { + roundView = StaticBackgroundView() + roundView!.layer.masksToBounds = true + addSubview(roundView!) + + roundView!.snp.makeConstraints { + $0.center.equalTo(self) + $0.size.equalTo(self).offset(-4.0) + } + } + + func userStatusWasUpdated() { + if let theme = theme { + + // TODO: show userstatus as well as connectionstatus + // Currently showing the userstatus when debug mode is off, otherwise the connection status + + if (UserDefaultsManager().DebugMode == false) { + //Default user status indicator + switch userStatus { + case .offline: + roundView?.setStaticBackgroundColor(theme.colorForType(.OfflineStatus)) + case .online: + roundView?.setStaticBackgroundColor(theme.colorForType(.OnlineStatus)) + case .away: + roundView?.setStaticBackgroundColor(theme.colorForType(.AwayStatus)) + case .busy: + roundView?.setStaticBackgroundColor(theme.colorForType(.BusyStatus)) + } + } else { + //Debug connection status indicator + switch connectionStatus { + case .tcp: + roundView?.setStaticBackgroundColor(theme.colorForType(.AwayStatus)) + case .udp: + roundView?.setStaticBackgroundColor(theme.colorForType(.OnlineStatus)) + case .none: + fallthrough + default: + roundView?.setStaticBackgroundColor(theme.colorForType(.OfflineStatus)) + } + } + + let background = showExternalCircle ? theme.colorForType(.StatusBackground) : .clear + setStaticBackgroundColor(background) + } + + layer.cornerRadius = frame.size.width / 2 + + roundView?.layer.cornerRadius = roundView!.frame.size.width / 2 + } +} diff --git a/Antidote/ViewPassingGestures.swift b/Antidote/ViewPassingGestures.swift new file mode 100644 index 0000000..4177afd --- /dev/null +++ b/Antidote/ViewPassingGestures.swift @@ -0,0 +1,19 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit + +class ViewPassingGestures: UIView { + override func point(inside point: CGPoint, with event: UIEvent?) -> Bool { + for subview in subviews { + let converted = convert(point, to: subview) + + if subview.hitTest(converted, with: event) != nil { + return true + } + } + + return false + } +} diff --git a/Antidote/antidote-acknowledgements.html b/Antidote/antidote-acknowledgements.html new file mode 100644 index 0000000..e783f73 --- /dev/null +++ b/Antidote/antidote-acknowledgements.html @@ -0,0 +1,578 @@ + + + + + +Acknowledgements + + + +

Acknowledgements

+ +

This application makes use of the following third party libraries:

+ +

CocoaLumberjack

+ +

Software License Agreement (BSD License)

+ +

Copyright (c) 2010, Deusty, LLC +All rights reserved.

+ +

Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following conditions are met:

+ +
    +
  • Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer.

  • +
  • Neither the name of Deusty nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of Deusty, LLC.

  • +
+ + +

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ +

JGProgressHUD

+ +

The MIT License (MIT)

+ +

Copyright (c) 2014-2016 Jonas Gessner

+ +

Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions:

+ +

The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software.

+ +

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ +

LNNotificationsUI

+ +

The MIT License (MIT)

+ +

Copyright (c) 2014 Leo Natan

+ +

Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions:

+ +

The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software.

+ +

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.

+ +

RBBAnimation

+ +

Copyright (c) 2013 Robert Böhnke.

+ +

Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions:

+ +

The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software.

+ +

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ +

Realm

+ +

TABLE OF CONTENTS

+ +
    +
  1. Apache License version 2.0
  2. +
  3. Realm Components
  4. +
  5. Export Compliance
  6. +
+ + +
+ +
                             Apache License
+                       Version 2.0, January 2004
+                    http://www.apache.org/licenses/
+
+ +

TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

+ +
    +
  1. . Definitions.

    + +

    "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document.

    + +

    "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License.

    + +

    "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity.

    + +

    "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License.

    + +

    "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files.

    + +

    "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types.

    + +

    "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below).

    + +

    "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof.

    + +

    "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution."

    + +

    "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work.

  2. +
  3. . Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form.

  4. +
  5. . Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed.

  6. +
  7. . Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions:

    + +

    (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and

    + +

    (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and

    + +

    (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and

    + +

    (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License.

    + +

    You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License.

  8. +
  9. . Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions.

  10. +
  11. . Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file.

  12. +
  13. . Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License.

  14. +
  15. . Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages.

  16. +
  17. . Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability.

  18. +
+ + +

END OF TERMS AND CONDITIONS

+ +

APPENDIX: How to apply the Apache License to your work.

+ +
  To apply the Apache License to your work, attach the following
+  boilerplate notice, with the fields enclosed by brackets "{}"
+  replaced with your own identifying information. (Don't include
+  the brackets!)  The text should be enclosed in the appropriate
+  comment syntax for the file format. We also recommend that a
+  file or class name and description of purpose be included on the
+  same "printed page" as the copyright notice for easier
+  identification within third-party archives.
+
+ +

Copyright {yyyy} {name of copyright owner}

+ +

Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at

+ +
   http://www.apache.org/licenses/LICENSE-2.0
+
+ +

Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License.

+ +

REALM COMPONENTS

+ +

This software contains components with separate copyright and license terms. +Your use of these components is subject to the terms and conditions of the +following licenses.

+ +

For the Realm Core component

+ +

Realm Core Binary License

+ +

Copyright (c) 2011-2014 Realm Inc All rights reserved

+ +

Redistribution and use in binary form, with or without modification, is + permitted provided that the following conditions are met:

+ +
    +
  1. You agree not to attempt to decompile, disassemble, reverse engineer or +otherwise discover the source code from which the binary code was derived. +You may, however, access and obtain a separate license for most of the +source code from which this Software was created, at +http://realm.io/pricing/.

  2. +
  3. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution.

  4. +
  5. Neither the name of the copyright holder nor the names of its +contributors may be used to endorse or promote products derived from this +software without specific prior written permission.

  6. +
+ + +

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE.

+ +

EXPORT COMPLIANCE

+ +

You understand that the Software may contain cryptographic functions that may be +subject to export restrictions, and you represent and warrant that you are not +located in a country that is subject to United States export restriction or embargo, +including Cuba, Iran, North Korea, Sudan, Syria or the Crimea region, and that you +are not on the Department of Commerce list of Denied Persons, Unverified Parties, +or affiliated with a Restricted Entity.

+ +

You agree to comply with all export, re-export and import restrictions and +regulations of the Department of Commerce or other agency or authority of the +United States or other applicable countries. You also agree not to transfer, or +authorize the transfer of, directly or indirectly, the Software to any prohibited +country, including Cuba, Iran, North Korea, Sudan, Syria or the Crimea region, +or to any person or organization on or affiliated with the Department of +Commerce lists of Denied Persons, Unverified Parties or Restricted Entities, or +otherwise in violation of any such restrictions or regulations.

+ +

SDCAlertView

+ +

The MIT License (MIT)

+ +

Copyright (c) 2013 Scott Berrevoets

+ +

Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions:

+ +

The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software.

+ +

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.

+ +

SDCAutoLayout

+ +

Copyright (c) 2013 Scott Berrevoets

+ +

Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions:

+ +

The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software.

+ +

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ +

TPCircularBuffer

+ +

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

+ +

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

+ +

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."

+ +

UITextView+Placeholder

+ +

The MIT License (MIT)

+ +

Copyright (c) 2014 Suyeol Jeon (http://xoul.kr)

+ +

Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions:

+ +

The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software.

+ +

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.

+ +

libopus-patched-config

+ +

Copyright 2001-2011 Xiph.Org, Skype Limited, Octasic, + Jean-Marc Valin, Timothy B. Terriberry, + CSIRO, Gregory Maxwell, Mark Borgerding, + Erik de Castro Lopo

+ +

Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met:

+ +
    +
  • Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer.

  • +
  • Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution.

  • +
  • Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission.

  • +
+ + +

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ +

Opus is subject to the royalty-free patent licenses which are +specified at:

+ +

Xiph.Org Foundation: +https://datatracker.ietf.org/ipr/1524/

+ +

Microsoft Corporation: +https://datatracker.ietf.org/ipr/1914/

+ +

Broadcom Corporation: +https://datatracker.ietf.org/ipr/1526/

+ +

libsodium

+ +

Copyright © 2013\nFrank Denis \n\nPermission to use, copy, modify, and distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n\n

+ +

objcTox

+ +

The MIT License (MIT)

+ +

Copyright (c) 2014 Dmitry Vorobyov

+ +

Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions:

+ +

The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software.

+ +

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ +

SnapKit

+ +

Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit

+ +

Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions:

+ +

The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software.

+ +

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.

+ +

YamlSwift

+ +

The MIT License (MIT)

+ +

Copyright (c) 2015 Behrang Noruzi Niya

+ +

Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions:

+ +

The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software.

+ +

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.

+ + \ No newline at end of file diff --git a/Antidote/appstore-512_orig.png b/Antidote/appstore-512_orig.png new file mode 100644 index 0000000000000000000000000000000000000000..612d6010122cc27ae28e9f7ba09d6f2b55b05ab5 GIT binary patch literal 10027 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 LwRy>5&#V6fGtOKa literal 0 HcmV?d00001 diff --git a/Antidote/appstore.png b/Antidote/appstore.png new file mode 100644 index 0000000000000000000000000000000000000000..d92a11bfb97661b4166bc67ac427b16228d8622e GIT binary patch literal 77165 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 \ No newline at end of file diff --git a/Antidote/ar.lproj/InfoPlist.strings b/Antidote/ar.lproj/InfoPlist.strings new file mode 100644 index 0000000000000000000000000000000000000000..6c333a86e6042a9b313f0a4b40846fa9afa0f57c GIT binary patch literal 978 zcmbu7K~KU!5QX2_U(xhP42X$bj0XZ26E&#O#ABfqNT4NcY2r`vPpaSSrcg~U*uzd| zW@p~ad)@D^fqDvb#tC$*RPV|((?)9*D%E#3CrY)%_jO~Ul3Yw}sf4W0Pm~iyE*FD0 z*9Ug0E#H#6jOZ0>-kknS6`2gQKto+=fE_wJVsed{X-B{9u+$2iK%bmTT~Is1i$O8W zKK_`^H++xPg^Ln)Psmo-*kSjWV|#o46Sm&Eiir9>)e+MY{0Kbjw7D@}p@l==kue6g zyT=Okpl3CaUJf|Z*3OXL8&0SA{@Gj@f}iR?aQqX2bQ+?O2V zYW){uBZHE&+-TS8KuDh literal 0 HcmV?d00001 diff --git a/Antidote/ar.lproj/Localizable.strings b/Antidote/ar.lproj/Localizable.strings new file mode 100644 index 0000000..15a04f1 --- /dev/null +++ b/Antidote/ar.lproj/Localizable.strings @@ -0,0 +1,415 @@ +/* + Localizable.strings + Antidote + + Created by Dmytro Vorobiov on 08/10/15. + Copyright © 2015 dvor. All rights reserved. +*/ + +/* + Translation is done with Transifex service. + See https://www.transifex.com/antidote/antidote-ios/ +*/ + +/* Login screen text */ +"login_or_label" = "أو"; +/* Login screen text */ +"create_account" = "حساب جديد"; +/* Login screen text */ +"import_profile" = "نقل الحساب"; +/* Password field */ +"password" = "كلمة المرور"; +/* Login button */ +"log_in" = "دخول"; +/* Login screen text */ +"create_profile" = "إنشاء حساب"; +/* Login screen text */ +"import_to_antidote" = "إنتقال الى انتيدوت"; +/* Login screen text */ +"create_account_username_title" = "كيف يتم مشاهدتك في قائمة الاتصال؟"; +/* Login screen text */ +"create_account_username_placeholder" = "إسم المستخدم"; +/* Login screen text */ +"create_account_profile_title" = "كيف تتصل بهذا الحساب؟"; +/* Login screen text */ +"create_account_profile_placeholder" = "إسم الحساب"; +/* Login screen text */ +"create_account_profile_hint" = "على سبيل المثال المنزل، الايفون"; +/* Login screen text */ +"set_password_title" = "ضع كلمة مرور"; +/* Login screen text */ +"set_password_hint" = "الحاجة في كلمة المرور هي لحماية البيانات الخاصة. أحتفظ بها - بفقدانها لا يمكن استعادة الحساب."; +/* Login button */ +"create_account_next_button" = "التالي"; +/* Login button */ +"create_account_go_button" = "إبدأ"; +/* Default status message */ +"default_user_status_message" = "اتواصل بواسطة انتيدوت"; + +/* PIN screen text */ +"pin_enter_to_unlock" = "أدخل رقم PIN الخاص بك للفتح"; +/* PIN screen text */ +"pin_set" = "تعيين PIN"; +/* PIN screen text */ +"pin_confirm" = "تأكيد PIN"; +/* PIN screen error */ +"pin_do_not_match" = "الأرقام غير مطابقة. حاول ثانية"; +/* PIN screen error */ +"pin_incorrect" = "PIN غير صحيح"; +/* PIN screen error details */ +"pin_failed_attempts" = "المحاولات الفاشلة: %@"; +/* PIN screen message shown on log out */ +"pin_logout_message" = "الكثير من المحاولات الفاشلة. لقد تم تسجيل خروجك."; +/* PIN screen screen */ +"pin_enabled" = "تفعيل PIN"; +/* PIN screen screen */ +"pin_touch_id_enabled" = "تفعيل الهوية باللمس"; +/* PIN screen screen */ +"pin_description" = "منع الوصول غير المصرح به إلى أنتيدوت مع PIN."; +/* PIN screen screen */ +"pin_touch_id_description" = "استخدام بصمة الإصبع كبديل لإدخال رمز PIN."; +/* PIN screen screen */ +"pin_lock_timeout" = "إقفال عند نفاذ الوقت"; +/* PIN screen screen */ +"pin_lock_immediately" = "فورا"; +/* PIN screen screen */ +"pin_lock_30_seconds" = "30 ثانية"; +/* PIN screen screen */ +"pin_lock_1_minute" = "1 دقيقة"; +/* PIN screen screen */ +"pin_lock_2_minutes" = "2 دقيقة"; +/* PIN screen screen */ +"pin_lock_5_minutes" = "5 دقيقة"; + +/* Label shown when connecting to Tox network */ +"connecting_label" = "على قيد الإتصال..."; + +/* Tab name and screen name */ +"contacts_title" = "القائمة"; +/* Tab name and screen name */ +"chats_title" = "المحادثات"; +/* Tab name and screen name */ +"settings_title" = "الإعدادات"; +/* Tab name and screen name */ +"profile_title" = "الحساب"; + +/* No contacts placeholder text */ +"contact_no_contacts" = "لا توجد جهات اتصال"; +/* No contacts placeholder text */ +"contact_no_contacts_add_contact" = "اضافة حساب\nاو\n"; +/* No contacts placeholder text */ +"contact_no_contacts_share_tox_id" = "مشاركة حساب التوكس الخاص بك"; +/* Contact request section title */ +"contact_requests_section" = "قائمة الإضافات"; +/* Contact last seen status */ +"contact_last_seen" = "نهايتها: %@"; +/* Screen name */ +"contact_request" = "طلب إضافة"; +/* Contact request button */ +"contact_request_decline" = "رفض"; +/* Contact request button */ +"contact_request_accept" = "قبول"; +/* Contact request confirmation */ +"contact_request_delete_title" = "إزالة طلب الإضافة؟"; +/* Text shown when contact was deleted */ +"contact_deleted" = "جهة اتصال محذوفة"; + +/* Share Tox ID text */ +"show_qr_code" = "عرض رمز الاستجابة السريع او الباركود"; +/* Share Tox ID text */ +"copy" = "نسخ"; + +/* Add contat screen name */ +"add_contact_title" = "إضافة حساب"; +/* Add contat button */ +"add_contact_send" = "إرسال"; +/* Add contat placeholder text */ +"add_contact_tox_id_placeholder" = "أدخل عنوان حساب التوكس"; +/* Add contat placeholder text */ +"add_contact_or_label" = "أو"; +/* Add contat button */ +"add_contact_use_qr" = "إستخدام رمز الاستجابة السريع او الباركود"; +/* Add contat placeholder text */ +"add_contact_default_message_title" = "رسالة"; +/* Add contat default text sended to contact */ +"add_contact_default_message_text" = "مرحباً! هل من الممكن أن تقبل إضافتي في قائمتك؟"; +/* Add contat error */ +"add_contact_wrong_qr" = "رمز الاستجابة السريع او الباركود خطأ. يجب توفر عنوان حساب التوكس"; + +/* User name text */ +"name" = "الإسم"; +/* User nickname text */ +"nickname" = "اللقب"; +/* User status message text */ +"status_message" = "وضع الحالة"; +/* User status text */ +"status_title" = "الحالة"; +/* User Tox ID text */ +"my_tox_id" = "عنوان حساب التوكس"; +/* User public key text */ +"public_key" = "مفتاح المعلن المشفر"; +/* Share Tox ID text */ +"show_qr" = "عرض رمز الاستجابة السريع او الباركود"; +/* Profile menu item / screen name */ +"profile_details" = "بيانات الحساب"; +/* Profile button */ +"logout_button" = "تسجيل خروج"; + +/* QR code screen button */ +"qr_close_button" = "إغلاق"; + +/* Chat screen placeholder */ +"chat_no_chats" = "لا توجد محادثات"; +/* Chats screen message text */ +"chat_outgoing_file" = "الملف الصادر:"; +/* Chats screen message text */ +"chat_incoming_file" = "الملف الوارد:"; +/* Chats screen message text */ +"chat_call_finished" = "انتهت المكالمة"; +/* Chats screen message text */ +"chat_unanwered_call" = "لم تتم الإستجابة على المكالمة"; +/* Chat button */ +"chat_send_button" = "إرسال"; +/* Chat notification toast */ +"chat_new_messages" = "رسائل جديدة"; +/* Chat call information */ +"chat_call_message" = "اتصل، "; +/* Chat call information */ +"chat_missed_call_message" = "مكالمة لم يرد عليها"; +/* Item present in the menu on long press on message */ +"chat_more_menu_item" = "المزيد"; + +/* Status message */ +"status_offline" = "غير متصل"; +/* Status message */ +"status_online" = "متصل"; +/* Status message */ +"status_away" = "بالخارج"; +/* Status message */ +"status_busy" = "مشغول"; + +/* Notification text */ +"notification_new_message" = "رسالة جديدة"; +/* Notification text */ +"notification_incoming_contact_request" = "طلب دعوة إضافة"; +/* Notification text */ +"notification_is_calling" = "يتصل"; +/* Notification text */ +"notification_incoming_file" = "وصول ملف"; + +/* Settings menu / screen name */ +"settings_about" = "نبذة عن"; +/* Settings menu / screen name */ +"settings_faq" = "التعليمات"; +/* Settings menu / screen name */ +"settings_advanced_settings" = "خصائص الاعدادات"; +/* About screen menu */ +"settings_antidote_version" = "إصدار الانتيدوت"; +/* About screen menu */ +"settings_antidote_build" = "بناء الانتيدوت"; +/* About screen menu */ +"settings_toxcore_version" = "إصدار نواة التوكس او التوكس كور"; +/* About screen menu */ +"settings_acknowledgements" = "شكر وتنويه"; +/* Settings screen menu */ +"settings_autodownload_images" = "ملفات التنزيل التلقائي"; +/* Settings screen menu */ +"settings_autodownload_images_description" = "تنزيل الملفات الواردة تلقائيا."; +/* Settings screen menu */ +"settings_notifications_message_preview" = "عرض الإشعارات"; +/* Settings screen menu */ +"settings_notifications_description" = "حينما يتم عمل البرنامج في النظام، سيتم عرض الإشعارات حتى 10 دقائق."; +/* Settings screen menu */ +"settings_udp_enabled" = "تفعيل UDP"; +/* Settings screen menu */ +"settings_restore_default" = "إسترجاع الإعدادات التلقائية"; +/* Settings screen autodownload images option */ +"settings_never" = "لا"; +/* Settings screen autodownload images option */ +"settings_wifi" = "إتصال لاسلكي او واي-فاي"; +/* Settings screen autodownload images option */ +"settings_using_wifi" = "إستخدام إتصال لاسلكي او واي-فاي"; +/* Settings screen autodownload images option */ +"settings_always" = "دائماً"; + +/* Profile settings menu */ +"change_password" = "تغيير كلمة المرور"; +/* Profile settings menu */ +"delete_password" = "إزالة كلمة المرور"; +/* Profile settings menu */ +"old_password" = "كلمة المرور القديمة"; +/* Change password text */ +"new_password" = "كلمة المرور الجديدة"; +/* Change password text */ +"repeat_password" = "كرر كلمة المرور"; +/* Change password button */ +"change_password_done" = "انتهى"; +/* Change password error */ +"password_is_empty_error" = "كلمة المرور يجب أن تكون غير فارغة"; +/* Change password error */ +"wrong_old_password" = "كلمة المرور خطأ"; +/* Change password error */ +"passwords_do_not_match" = "كلمة المرور غير مطابقة"; + +/* Source of photo to take */ +"photo_from_camera" = "تصوير"; +/* Source of photo to take */ +"photo_from_photo_library" = "قائمة الصور"; +/* Error while converting avatar image */ +"change_avatar_error_convert_image" = "لا يمكن تحويل الصورة"; + +/* Alert text when sending file to contacts */ +"file_send_to_contact" = "إرسال إلى جهة اتصال"; + +/* Profile menu item */ +"export_profile" = "حفظ الحساب الشخصي"; +/* Profile menu item */ +"delete_profile" = "حذف الحساب الشخصي"; +/* Delete profile confirmation */ +"delete_profile_confirmation_title_1" = "هل تريد حذف هذا الحساب؟"; +/* Delete profile confirmation */ +"delete_profile_confirmation_title_2" = "هل أنت متأكد؟"; +/* Delete profile confirmation */ +"delete_profile_confirmation_message" = "هذه العملية لا يمكن التراجع عنها"; + +/* Call screen text */ +"call_incoming" = "مكالمة واردة"; +/* Call screen text */ +"call_ended" = "انتهت المكالمة"; +/* Call screen text */ +"call_reaching" = "على قيد الوصول..."; + +/* File message text */ +"chat_file_cancelled" = "تم الإلغاء"; +/* File message text */ +"chat_waiting" = "إنتظار..."; +/* File message text */ +"chat_paused" = "إيقاف مؤقت"; + +/* Deleting chat confirmation */ +"delete_chat_title" = "حذف هذه المحادثة والرسائل المحفوظة بها؟"; +/* Deleting contat confirmation */ +"delete_contact_title" = "إزالة هذا الحساب؟\nسيتم فقدان سجل المحادثة."; +/* Deleting contat request confirmation */ +"delete_contact_request_title" = "إزالة الدعوة لهذا الحساب؟"; +/* Deleting single message in chat */ +"delete_single_message" = "حذف الرسالة"; +/* Deleting multiple messages in chat. */ +"delete_multiple_messages" = "حذف الرسائل"; +/* Deleting all messages in chat. */ +"delete_all_messages" = "حذف الكل"; +/* Delete button */ +"alert_delete" = "إزالة"; +/* Delete button */ +"alert_cancel" = "إلغاء الامر"; + +/* Error while creating new profile */ +"login_enter_username_and_profile" = "الرجاء إدخال كل من اسم المستخدم واسم الحساب."; +/* Error while creating new profile */ +"login_profile_already_exists" = "إسم الحساب موجود مسبقاً"; + +/* General error title */ +"error_title" = "خطأ"; +/* General error button */ +"error_ok_button" = "موافق"; +/* General error button */ +"error_retry_button" = "إعادة المحاولة"; +/* Error */ +"error_contact_not_connected" = "الحساب غير متصل"; +/* Error */ +"error_too_many_files" = "هناك عدد كبير من الملفات المفعلة على قيد النقل"; +/* Error */ +"error_internal_message" = "حدث خطأ داخلي"; +/* Error */ +"error_wrong_password_title" = "كلمة المرور خطأ"; +/* Error */ +"error_wrong_password_message" = "كلمة المرور تحتوي على رموز خاطئة."; +/* Error */ +"error_import_not_exist_title" = "لا يمكن نقل ملف التوكس المحفوظ"; +/* Error */ +"error_import_not_exist_message" = "الملف غير موجود."; +/* Error */ +"error_decrypt_title" = "لا يمكن فك تشفير ملف التوكس المحفوظ"; +/* Error */ +"error_decrypt_empty_data_message" = "بعض بيانات الإدخال كانت فارغة."; +/* Error */ +"error_decrypt_bad_format_message" = "الملف يحتوي على تنسيق سيء أو تالف."; +/* Error */ +"error_decrypt_wrong_password_message" = "كلمة السر غير صحيحة أو قد يكون الملف تالف."; +/* Error */ +"error_general_unknown_message" = "حدث خطأ مجهول."; +/* Error */ +"error_general_no_memory_message" = "الذاكرة لا تكفي."; +/* Error */ +"error_general_bind_port_message" = "لم يتمكن لربط المنفذ."; +/* Error */ +"error_general_profile_encrypted_message" = "تم تشفير الحساب."; +/* Error */ +"error_general_bad_format_message" = "الملف يحتوي على تنسيق سيء أو تالف."; +/* Error */ +"error_proxy_title" = "خطأ في الخادم الوكيل او البروكسي"; +/* Error */ +"error_proxy_invalid_address_message" = "عنوان الوكيل او البروكسي غير صالح."; +/* Error */ +"error_proxy_invalid_port_message" = "منفذ الوكيل او البروكسي غير صالح."; +/* Error */ +"error_proxy_host_not_resolved_message" = "لا يمكن حل استضافة الوكيل او البروكسي."; + +/* Error */ +"error_name_too_long" = "الإسم طويل جداً."; +/* Error */ +"error_status_message_too_long" = "الرسالة في الحالة طويلة جداً"; + +/* Error */ +"error_contact_request_too_long" = "الرسالة طويلة جداً"; +/* Error */ +"error_contact_request_no_message" = "لا يوجد رسائل محددة"; +/* Error */ +"error_contact_request_own_key" = "لا يمكن إضافة نفس حسابي في قائمة الاتصال الخاصة بي"; +/* Error */ +"error_contact_request_already_sent" = "طلب الإضافة قد تم ارسالها مسبقاً"; +/* Error */ +"error_contact_request_bad_checksum" = "المجموع الاختباري باطل، يرجى التحقق من هوية Tox المدخلة"; +/* Error */ +"error_contact_request_new_nospam" = "قيمة تعطيل الإزعاج nospam باطلة، يرجى التحقق من هوية Tox المدخلة."; + +/* Call error */ +"call_error_already_in_call" = "حالياً في مكالمة"; +/* Call error */ +"call_error_contact_is_offline" = "الحساب غير متصل"; +/* Call error */ +"call_error_no_active_call" = "ليس هناك مكالمة أخرى"; + +/* Error while using color theme */ +"theme_error_cannot_open" = "لا يمكن فتح السمة، التنسيق خاطئ"; + +/* Tab chats badge ending */ +"accessibility_chats_ending" = "المحادثات الغير مقروء"; +/* Avatar button label in settings */ +"accessibility_avatar_button_label" = "الصورة الرمزية"; +/* Avatar button hint in settings */ +"accessibility_avatar_button_hint" = "تحديد أو إزالة الصورة الرمزية."; +/* Chat button label in contact screen */ +"accessibility_chat_button_label" = "محادثة"; +/* Chat button hint in contact screen */ +"accessibility_chat_button_hint" = "يفتح حوار المحادثة."; +/* Call button label in contact screen */ +"accessibility_call_button_label" = "مكالمة صوتية"; +/* Call button hint in contact screen */ +"accessibility_call_button_hint" = "لطلب مكالمة صوتية."; +/* Video button label in contact screen */ +"accessibility_video_button_label" = "مكالمة مرئية"; +/* Video button hint in contact screen */ +"accessibility_video_button_hint" = "لطلب مكالمة مرئية."; +/* Tap to copy hint */ +"accessibility_show_copy_hint" = "يظهر نسخة القائمة."; +/* Tap to edit value hint */ +"accessibility_edit_value_hint" = "تعديلات القيمة."; +/* Incoming message label */ +"accessibility_incoming_message_label" = "رسالة"; +/* Outgoing message label */ +"accessibility_outgoing_message_label" = "رسالتك"; +/* Text shown in chat when there are undelivered faux offline messages */ +"chat_pending_faux_offline_messages" = "سيتم إرسال الرسائل التي لم يتم تسليمها عندما تكون أنت وصديقك متصلين بالإنترنت."; +/* Message shown on chat list when contact is typing */ +"chat_is_typing_text" = "يكتب..."; diff --git a/Antidote/ar.lproj/import-profile.html b/Antidote/ar.lproj/import-profile.html new file mode 100644 index 0000000..fecedc1 --- /dev/null +++ b/Antidote/ar.lproj/import-profile.html @@ -0,0 +1,9 @@ + +

لنقل حساب التوكس الخاص بك:

+ +
    +
  1. ارسال ملف ".tox" للجهاز الخاص بك بواسطة اي برنامج (بريد الكتروني، دروبوكس، الخ).
  2. +
  3. استخدام قائمة "فتح" لهذا الملف.
  4. +
  5. اختر انتيدوت في قائمة البرامج الرئيسية.
  6. +
  7. أختر الاسم لحسابك الجديد وبعدها انقر على موافق.
  8. +
diff --git a/Antidote/br.lproj/InfoPlist.strings b/Antidote/br.lproj/InfoPlist.strings new file mode 100644 index 0000000000000000000000000000000000000000..b8e96563516d01643d8025247309adb23e21f6c5 GIT binary patch literal 1092 zcmc(e%}T>i5QWd$rwCaVu~x7faZy?jL8U6XzcsO~ZF55t3;ISro=Z3CH#ep!*j)t) zcQU_c=AKNxKHF+3(jF($xiUS$F?yBP!z%G54|1kV(L9(Z}Yl?%!wXMaXdEKa=g~mZCfGtkU`>XoVgEdXC3# zV6#_Pv95HhO{BXu&R}b0OzkNr)){e|+|%1S*%WpM)2B?96PxO39nXLA$9NWcCEsSt zc)UKSS&?lXuYIf;apR%(+T4~k34IFUDSbB)tjhcjM5p(F;mN4#u5|;4u}(G^yriQs zV_$26%)s1@$!&=L$LK8Vf$ght-*D-FF)P@Nl$J5_7q1u6OC?CO5 literal 0 HcmV?d00001 diff --git a/Antidote/br.lproj/Localizable.strings b/Antidote/br.lproj/Localizable.strings new file mode 100644 index 0000000..da5d0c0 --- /dev/null +++ b/Antidote/br.lproj/Localizable.strings @@ -0,0 +1,415 @@ +/* + Localizable.strings + Antidote + + Created by Dmytro Vorobiov on 08/10/15. + Copyright © 2015 dvor. All rights reserved. +*/ + +/* + Translation is done with Transifex service. + See https://www.transifex.com/antidote/antidote-ios/ +*/ + +/* Login screen text */ +"login_or_label" = "pe"; +/* Login screen text */ +"create_account" = "Krouiñ ur Gont"; +/* Login screen text */ +"import_profile" = "Emporzhiañ ur Profil"; +/* Password field */ +"password" = "Ger-kuzh"; +/* Login button */ +"log_in" = "Kevreañ"; +/* Login screen text */ +"create_profile" = "Krouiñ ur profil"; +/* Login screen text */ +"import_to_antidote" = "Emporzhiañ e-barzh Antidote"; +/* Login screen text */ +"create_account_username_title" = "Penaos e viot gwelet gant ho tarempredoù ?"; +/* Login screen text */ +"create_account_username_placeholder" = "Anv-Implijer"; +/* Login screen text */ +"create_account_profile_title" = "Penaos pellgomz d'ar profil-mañ ?"; +/* Login screen text */ +"create_account_profile_placeholder" = "Anv ar profil"; +/* Login screen text */ +"create_account_profile_hint" = "d.sk. Home, iPhone"; +/* Login screen text */ +"set_password_title" = "Termeniñ ur Ger-Kuzh"; +/* Login screen text */ +"set_password_hint" = "Ret eo da gaout gerioù-kuzh da wareziñ ho roadennoù. Mirit anezhañ sur - ur wezh kollet ne c'hallo bet bezañ adroet."; +/* Login button */ +"create_account_next_button" = "Goude"; +/* Login button */ +"create_account_go_button" = "Mont"; +/* Default status message */ +"default_user_status_message" = "Toksi a ran war Antidote"; + +/* PIN screen text */ +"pin_enter_to_unlock" = "Ebarzhiñ ho PIN da zibrennañ"; +/* PIN screen text */ +"pin_set" = "Termenit ur PIN"; +/* PIN screen text */ +"pin_confirm" = "Kadarnaat ar PIN"; +/* PIN screen error */ +"pin_do_not_match" = "Ne glot ket ar PINoù. Klaskit adarre"; +/* PIN screen error */ +"pin_incorrect" = "PIN Direizh"; +/* PIN screen error details */ +"pin_failed_attempts" = "C'hwitet ez eus bet gant ar glaskadenn : %@"; +/* PIN screen message shown on log out */ +"pin_logout_message" = "C'hwitet ez eus bet war re a glaskadennoù. Digevreet oc'h bet."; +/* PIN screen screen */ +"pin_enabled" = "Pin Gweredeakaet"; +/* PIN screen screen */ +"pin_touch_id_enabled" = "Gweredekaat Touchenn an ID"; +/* PIN screen screen */ +"pin_description" = "Mirout ouzh an haezennoù diaotreet war Antidote gant ur c'hod PIN."; +/* PIN screen screen */ +"pin_touch_id_description" = "Ober gant ur roudennviz evel un hent-biou da ebarzhañ ur PIN."; +/* PIN screen screen */ +"pin_lock_timeout" = "Prennañ an Diamzer"; +/* PIN screen screen */ +"pin_lock_immediately" = "Diouzhtu-dak"; +/* PIN screen screen */ +"pin_lock_30_seconds" = "30 Eilenn"; +/* PIN screen screen */ +"pin_lock_1_minute" = "1 Vunutenn"; +/* PIN screen screen */ +"pin_lock_2_minutes" = "2 Vunutenn"; +/* PIN screen screen */ +"pin_lock_5_minutes" = "5 Munutenn"; + +/* Label shown when connecting to Tox network */ +"connecting_label" = "O kevreiñ..."; + +/* Tab name and screen name */ +"contacts_title" = "Darempredoù"; +/* Tab name and screen name */ +"chats_title" = "Flapoùva"; +/* Tab name and screen name */ +"settings_title" = "Arventennoù"; +/* Tab name and screen name */ +"profile_title" = "Profil"; + +/* No contacts placeholder text */ +"contact_no_contacts" = "Darempred ebet"; +/* No contacts placeholder text */ +"contact_no_contacts_add_contact" = "Ouzhpenniñ un darempred\npe\n"; +/* No contacts placeholder text */ +"contact_no_contacts_share_tox_id" = "Rannañ hoc'h identelezh Tox"; +/* Contact request section title */ +"contact_requests_section" = "Goulennoù darempred"; +/* Contact last seen status */ +"contact_last_seen" = "Gwelet da : %@"; +/* Screen name */ +"contact_request" = "Goulenn darempred"; +/* Contact request button */ +"contact_request_decline" = "Nac'hañ"; +/* Contact request button */ +"contact_request_accept" = "Asantiñ"; +/* Contact request confirmation */ +"contact_request_delete_title" = "Lemmel ar goulenn darempred kuit ?"; +/* Text shown when contact was deleted */ +"contact_deleted" = "Lemel an darempred kuit"; + +/* Share Tox ID text */ +"show_qr_code" = "Diskouez ar c'hod QR"; +/* Share Tox ID text */ +"copy" = "Eilañ"; + +/* Add contat screen name */ +"add_contact_title" = "Ouzhpenniñ Darempred"; +/* Add contat button */ +"add_contact_send" = "Kas"; +/* Add contat placeholder text */ +"add_contact_tox_id_placeholder" = "Ebarzhiañ identelezh Tox"; +/* Add contat placeholder text */ +"add_contact_or_label" = "pe"; +/* Add contat button */ +"add_contact_use_qr" = "Implijout ar c'hod QR"; +/* Add contat placeholder text */ +"add_contact_default_message_title" = "Kemennadenn"; +/* Add contat default text sended to contact */ +"add_contact_default_message_text" = "Demat ! Ha gellout a rafec'h ouzhpenniñ ac'hanon d'ho listenn darempredoù ?"; +/* Add contat error */ +"add_contact_wrong_qr" = "Kod QR fall. Rankout a rafe kaout en ennañ an identelezh Tox"; + +/* User name text */ +"name" = "Anv"; +/* User nickname text */ +"nickname" = "Lezanv"; +/* User status message text */ +"status_message" = "Statud ar gemennadenn"; +/* User status text */ +"status_title" = "Statud"; +/* User Tox ID text */ +"my_tox_id" = "Ma identelezh Tox"; +/* User public key text */ +"public_key" = "Alc'hwez Foran"; +/* Share Tox ID text */ +"show_qr" = "Diskouez QR"; +/* Profile menu item / screen name */ +"profile_details" = "Munudoù ar profil"; +/* Profile button */ +"logout_button" = "Digevreañ"; + +/* QR code screen button */ +"qr_close_button" = "Serriñ"; + +/* Chat screen placeholder */ +"chat_no_chats" = "Flapoù ebet"; +/* Chats screen message text */ +"chat_outgoing_file" = "Restr o vont maez :"; +/* Chats screen message text */ +"chat_incoming_file" = "Restr o vont e-barzh :"; +/* Chats screen message text */ +"chat_call_finished" = "Pellgomzadenn echuet"; +/* Chats screen message text */ +"chat_unanwered_call" = "Pellgomzadenn chomet direspont"; +/* Chat button */ +"chat_send_button" = "Kas"; +/* Chat notification toast */ +"chat_new_messages" = "↓ Kemennadennoù nevez"; +/* Chat call information */ +"chat_call_message" = "Pellgomz, "; +/* Chat call information */ +"chat_missed_call_message" = "Pellgomzadennoù c'hwitet"; +/* Item present in the menu on long press on message */ +"chat_more_menu_item" = "Muioc'h"; + +/* Status message */ +"status_offline" = "Maezlinenn"; +/* Status message */ +"status_online" = "Enlinenn"; +/* Status message */ +"status_away" = "Ezvezant"; +/* Status message */ +"status_busy" = "Ac'hubet"; + +/* Notification text */ +"notification_new_message" = "Kemennadennoù nevez"; +/* Notification text */ +"notification_incoming_contact_request" = "Goulenn darempred nevez"; +/* Notification text */ +"notification_is_calling" = "O pellgomz"; +/* Notification text */ +"notification_incoming_file" = "Restr o vont e-barzh"; + +/* Settings menu / screen name */ +"settings_about" = "Diwar-benn"; +/* Settings menu / screen name */ +"settings_faq" = "FAG"; +/* Settings menu / screen name */ +"settings_advanced_settings" = "Arventennoù araokaet"; +/* About screen menu */ +"settings_antidote_version" = "Stumm Antidote"; +/* About screen menu */ +"settings_antidote_build" = "Sevel Antidote"; +/* About screen menu */ +"settings_toxcore_version" = "Stumm Toxcore"; +/* About screen menu */ +"settings_acknowledgements" = "Trugarekadurioù"; +/* Settings screen menu */ +"settings_autodownload_images" = "Pellgargañ skeudennoù emgefreek"; +/* Settings screen menu */ +"settings_autodownload_images_description" = "Pellgargañ en un doare emgefreek ar skeudennoù o tont e-barzh."; +/* Settings screen menu */ +"settings_notifications_message_preview" = "Diskouez ar C'hemennadennoù"; +/* Settings screen menu */ +"settings_notifications_description" = "Pa vo an arload war an drekleur, resev a rit kemennadennoù e-pad dek munud c'hoazh."; +/* Settings screen menu */ +"settings_udp_enabled" = "Gweredekaat an UDP"; +/* Settings screen menu */ +"settings_restore_default" = "Resteurel an arventennoù dre ziouer"; +/* Settings screen autodownload images option */ +"settings_never" = "Morse"; +/* Settings screen autodownload images option */ +"settings_wifi" = "Wi-fi"; +/* Settings screen autodownload images option */ +"settings_using_wifi" = "Oc'h implijout ar Wi-fi"; +/* Settings screen autodownload images option */ +"settings_always" = "Dalc'hmat"; + +/* Profile settings menu */ +"change_password" = "Cheñch ar Ger-Kuzh"; +/* Profile settings menu */ +"delete_password" = "Dilemmel ar Ger-Kuzh"; +/* Profile settings menu */ +"old_password" = "Ger-Kuzh kozh"; +/* Change password text */ +"new_password" = "Ger-Kuzh nevez"; +/* Change password text */ +"repeat_password" = "Ar Ger-Kuzh c'hoazh"; +/* Change password button */ +"change_password_done" = "Graet"; +/* Change password error */ +"password_is_empty_error" = "Ne rankfe ket bezañ goullo ar Ger-Kuzh"; +/* Change password error */ +"wrong_old_password" = "Ger-Kuzh Fall"; +/* Change password error */ +"passwords_do_not_match" = "Ne Glot ket ar Gerioù-Kuzh"; + +/* Source of photo to take */ +"photo_from_camera" = "Kamera"; +/* Source of photo to take */ +"photo_from_photo_library" = "Ar Skeudennaoueg"; +/* Error while converting avatar image */ +"change_avatar_error_convert_image" = "Dibosupl eo da emdreiñ ar skeudenn"; + +/* Alert text when sending file to contacts */ +"file_send_to_contact" = "Kas d'an darempred"; + +/* Profile menu item */ +"export_profile" = "Ezporzhiañ ar Profil"; +/* Profile menu item */ +"delete_profile" = "Lemmel kuit ar Profil"; +/* Delete profile confirmation */ +"delete_profile_confirmation_title_1" = "Lammel Kuit ar Profil ?"; +/* Delete profile confirmation */ +"delete_profile_confirmation_title_2" = "Ha sur oc'h ?"; +/* Delete profile confirmation */ +"delete_profile_confirmation_message" = "Ne c'hellec'h ket distreiñ war an oberiadenn-mañ"; + +/* Call screen text */ +"call_incoming" = "Pellgomzadenn o tont-tre"; +/* Call screen text */ +"call_ended" = "Pellgomzadenn echuet"; +/* Call screen text */ +"call_reaching" = "O c'hortoz..."; + +/* File message text */ +"chat_file_cancelled" = "Nulet"; +/* File message text */ +"chat_waiting" = "O C'hortoz..."; +/* File message text */ +"chat_paused" = "Ehanet"; + +/* Deleting chat confirmation */ +"delete_chat_title" = "Lemmel ar flap hag ar c'hemennadennoù istorel-mañ kuit ?"; +/* Deleting contat confirmation */ +"delete_contact_title" = "Lemmel an darempred-mañ kuit ?\nHo flap istorel a vo kollet."; +/* Deleting contat request confirmation */ +"delete_contact_request_title" = "Lemmel ar goulenn darempred kuit ?"; +/* Deleting single message in chat */ +"delete_single_message" = "Dilemmel ar Gemennadenn"; +/* Deleting multiple messages in chat. */ +"delete_multiple_messages" = "Dilemmel ar C'hemennadennoù"; +/* Deleting all messages in chat. */ +"delete_all_messages" = "Lemmel kuit an Holl"; +/* Delete button */ +"alert_delete" = "Lemmel kuit"; +/* Delete button */ +"alert_cancel" = "Nulañ"; + +/* Error while creating new profile */ +"login_enter_username_and_profile" = "Ebarzhit un anv implijer hag un anv profil."; +/* Error while creating new profile */ +"login_profile_already_exists" = "Graet e vez gant an anv profil-mañ dija"; + +/* General error title */ +"error_title" = "Fazi"; +/* General error button */ +"error_ok_button" = "Mat eo"; +/* General error button */ +"error_retry_button" = "Adklask"; +/* Error */ +"error_contact_not_connected" = "N'emañ ket maez-linenn an darempred"; +/* Error */ +"error_too_many_files" = "Re a dreuskasoù restr gweredekaet"; +/* Error */ +"error_internal_message" = "Fazi Diabarzh"; +/* Error */ +"error_wrong_password_title" = "Ger-Kuzh Fall"; +/* Error */ +"error_wrong_password_message" = "Ar ger-kuzh a embarzh arouezhioù fall."; +/* Error */ +"error_import_not_exist_title" = "Dibosupl da embarzhañ ar restr tox enrollet"; +/* Error */ +"error_import_not_exist_message" = "N'eus ket eus ar restr."; +/* Error */ +"error_decrypt_title" = "Dibosupl da zirinegañ ar restr tox enrollet"; +/* Error */ +"error_decrypt_empty_data_message" = "Lod eus ar maeziennoù stlenn a oa goullo."; +/* Error */ +"error_decrypt_bad_format_message" = "Ar restr a zo er stumm fall pe trefoet."; +/* Error */ +"error_decrypt_wrong_password_message" = "Fall eo ar ger-kuzh pe trefoet eo ar restr."; +/* Error */ +"error_general_unknown_message" = "C'hoarvezet ez eus ur fazi dianavezet."; +/* Error */ +"error_general_no_memory_message" = "N'eus ket trawalc'h a vemor."; +/* Error */ +"error_general_bind_port_message" = "Dibosubl d'en em lugañ ouzh ur porzh."; +/* Error */ +"error_general_profile_encrypted_message" = "Rineget eo ar Profil."; +/* Error */ +"error_general_bad_format_message" = "Ar restr a zo er stumm fall pe trefoet."; +/* Error */ +"error_proxy_title" = "Fazi a-berzh ar Proxy"; +/* Error */ +"error_proxy_invalid_address_message" = "Ur stumm fall a zo gant chomlec'h ar Proxy."; +/* Error */ +"error_proxy_invalid_port_message" = "Porzh Proxy a zo direizh."; +/* Error */ +"error_proxy_host_not_resolved_message" = "N'en deus ket gallet bezañ digoublet hostiz Proxy."; + +/* Error */ +"error_name_too_long" = "An anv a zo re hir."; +/* Error */ +"error_status_message_too_long" = "Statud ar gemennadenn a zo re hir"; + +/* Error */ +"error_contact_request_too_long" = "Ar gemennadenn a zo re hir"; +/* Error */ +"error_contact_request_no_message" = "Kemennadenn ebet spisaet"; +/* Error */ +"error_contact_request_own_key" = "Ne c'hallan ket ma ouzhpennañ d'am listenn darempredoù"; +/* Error */ +"error_contact_request_already_sent" = "Goulenn mignoniezh kaset dija"; +/* Error */ +"error_contact_request_bad_checksum" = "Checksum fall, gwiriekait mar-plij ho ped ebarzhet an identelezh Tox mat"; +/* Error */ +"error_contact_request_new_nospam" = "Nospam fall, gwiriekait mar-plij ho ped ebarzhet an identelezh Tox mat"; + +/* Call error */ +"call_error_already_in_call" = "Oc'h ober ur bellgomzadenn dija"; +/* Call error */ +"call_error_contact_is_offline" = "E maez-linenn emañ an darempred"; +/* Call error */ +"call_error_no_active_call" = "N'eus pellgomzadenn gweredakaet ebet"; + +/* Error while using color theme */ +"theme_error_cannot_open" = "Dibosupl eo da zigeriñ an tem, stumm fall"; + +/* Tab chats badge ending */ +"accessibility_chats_ending" = "flapoù amlennet"; +/* Avatar button label in settings */ +"accessibility_avatar_button_label" = "Avatar"; +/* Avatar button hint in settings */ +"accessibility_avatar_button_hint" = "Lakaat pe dilemel an avatar."; +/* Chat button label in contact screen */ +"accessibility_chat_button_label" = "Flapva"; +/* Chat button hint in contact screen */ +"accessibility_chat_button_hint" = "Digeriñ ar flapva."; +/* Call button label in contact screen */ +"accessibility_call_button_label" = "Pellgomzadenn gant ar vouezh"; +/* Call button hint in contact screen */ +"accessibility_call_button_hint" = "Pellgomz gant ar vouezh."; +/* Video button label in contact screen */ +"accessibility_video_button_label" = "Pellgomzadenn gant ar Video"; +/* Video button hint in contact screen */ +"accessibility_video_button_hint" = "Pellgomz gant ar Video."; +/* Tap to copy hint */ +"accessibility_show_copy_hint" = "Diskouez ar roll eilañ."; +/* Tap to edit value hint */ +"accessibility_edit_value_hint" = "Kemm an talvoudegezh."; +/* Incoming message label */ +"accessibility_incoming_message_label" = "Kemennadenn"; +/* Outgoing message label */ +"accessibility_outgoing_message_label" = "Ho kemennadenn"; +/* Message shown on chat list when contact is typing */ +"chat_is_typing_text" = "'zo o skrivañ..."; +/* Text shown in chat when there are undelivered faux offline messages */ +"chat_pending_faux_offline_messages" = "Kemennadoù nan-dasparzhet a vo kaset pa e vi kevreet kenkoulz hag ho vignon."; diff --git a/Antidote/br.lproj/import-profile.html b/Antidote/br.lproj/import-profile.html new file mode 100644 index 0000000..afb06b5 --- /dev/null +++ b/Antidote/br.lproj/import-profile.html @@ -0,0 +1,9 @@ + +

Evit emporzhiañ ho profil Tox :

+ +
    +
  1. Kas ar restr ".tox" betek hoc'h ardivink diouzh forzh peseurt arload (Mail, Dropbox, etc.).
  2. +
  3. Implijout ar roll "Digeriñ E-Barzh" evit ar restr-ma.
  4. +
  5. Diuzit Antidote e-barzh listenn an arloadoù da bellgarga.
  6. +
  7. Gwiriekait anv ho profil nevez ha pouezit war OK.
  8. +
diff --git a/Antidote/ca.lproj/AppStoreLocalizable.strings b/Antidote/ca.lproj/AppStoreLocalizable.strings new file mode 100644 index 0000000..d6fbb04 --- /dev/null +++ b/Antidote/ca.lproj/AppStoreLocalizable.strings @@ -0,0 +1,54 @@ +/* + AppStoreLocalizable.strings + Antidote + + Created by Dmytro Vorobiov on 08/02/17. + Copyright © 2017 dvor. All rights reserved. +*/ + +/* Name of friend for the App Store screenshot. Should be fully random, no real people here. Can be generated with service like http://www.fakenamegenerator.com/ */ +"app_store_screenshot_friend_female_1" = "Mary Cokley"; +/* Name of friend for the App Store screenshot. Should be fully random, no real people here. Can be generated with service like http://www.fakenamegenerator.com/ */ +"app_store_screenshot_friend_female_2" = "Shirley Knox"; +/* Name of friend for the App Store screenshot. Should be fully random, no real people here. Can be generated with service like http://www.fakenamegenerator.com/ */ +"app_store_screenshot_friend_female_3" = "Jennifer Smith"; +/* Name of friend for the App Store screenshot. Should be fully random, no real people here. Can be generated with service like http://www.fakenamegenerator.com/ */ +"app_store_screenshot_friend_female_4" = "Marina Dixon"; +/* Name of friend for the App Store screenshot. Should be fully random, no real people here. Can be generated with service like http://www.fakenamegenerator.com/ */ +"app_store_screenshot_friend_female_5" = "Carol Ortega"; +/* Name of friend for the App Store screenshot. Should be fully random, no real people here. Can be generated with service like http://www.fakenamegenerator.com/ */ +"app_store_screenshot_friend_male_1" = "Michael Sharpe"; +/* Name of friend for the App Store screenshot. Should be fully random, no real people here. Can be generated with service like http://www.fakenamegenerator.com/ */ +"app_store_screenshot_friend_male_2" = "Charles Donahue"; +/* Name of friend for the App Store screenshot. Should be fully random, no real people here. Can be generated with service like http://www.fakenamegenerator.com/ */ +"app_store_screenshot_friend_male_3" = "Lee Murdock"; +/* Name of friend for the App Store screenshot. Should be fully random, no real people here. Can be generated with service like http://www.fakenamegenerator.com/ */ +"app_store_screenshot_friend_male_4" = "Wayne Henderson"; +/* Name of friend for the App Store screenshot. Should be fully random, no real people here. Can be generated with service like http://www.fakenamegenerator.com/ */ +"app_store_screenshot_friend_male_5" = "Robert Newton"; + +/* Demo conversation for the App Store screenshot */ +"app_store_screenshot_conversation_1" = "Is Antidote really that secure?"; +/* Demo conversation for the App Store screenshot */ +"app_store_screenshot_conversation_2" = "sure, it is peer-to-peer"; +/* Demo conversation for the App Store screenshot */ +"app_store_screenshot_conversation_3" = "And what does that mean? Peer-to-peer? 😄"; +/* Demo conversation for the App Store screenshot */ +"app_store_screenshot_conversation_4" = "you text me directly, the are no servers or things like that"; +/* Demo conversation for the App Store screenshot */ +"app_store_screenshot_conversation_5" = "+ it's encrypted 🔐😎"; +/* Demo conversation for the App Store screenshot */ +"app_store_screenshot_conversation_6" = "Cool!"; +/* Demo conversation for the App Store screenshot */ +"app_store_screenshot_conversation_7" = "I'll give it a go then"; + +/* Demo chat message for the App Store screenshot */ +"app_store_screenshot_chat_message_1" = "😂😂😂"; +/* Demo chat message for the App Store screenshot */ +"app_store_screenshot_chat_message_2" = "dinner tonight?"; +/* Demo chat message for the App Store screenshot */ +"app_store_screenshot_chat_message_3" = "I think I know what you are talking about"; +/* Demo chat message for the App Store screenshot */ +"app_store_screenshot_chat_message_4" = "Sure, thanks!"; +/* Demo chat message for the App Store screenshot */ +"app_store_screenshot_chat_message_5" = "yep"; diff --git a/Antidote/ca.lproj/InfoPlist.strings b/Antidote/ca.lproj/InfoPlist.strings new file mode 100644 index 0000000..b79a4d0 --- /dev/null +++ b/Antidote/ca.lproj/InfoPlist.strings @@ -0,0 +1,16 @@ +/* + InfoPlist.strings + Antidote + + Created by Dmytro Vorobiov on 15/11/16. + Copyright © 2016 dvor. All rights reserved. +*/ + +/* Camera usage alert description */ +"NSCameraUsageDescription" = "You can use video calls, send photos and videos, scan QR codes."; + +/* Microphone usage alert description */ +"NSMicrophoneUsageDescription" = "You can use audio and video calls."; + +/* Photo library usage alert description */ +"NSPhotoLibraryUsageDescription" = "You can send photos and videos."; \ No newline at end of file diff --git a/Antidote/ca.lproj/Localizable.strings b/Antidote/ca.lproj/Localizable.strings new file mode 100644 index 0000000..bdccfe3 --- /dev/null +++ b/Antidote/ca.lproj/Localizable.strings @@ -0,0 +1,404 @@ + + +/* Contact request button */ +"contact_request_accept" = "Acceptar"; +/* Login screen text */ +"login_or_label" = "o"; +/* Login button */ +"log_in" = "Iniciar sessió"; +/* Login screen text */ +"create_account" = "Crear compte"; +/* Password field */ +"password" = "Contrasenya"; +/* Login screen text */ +"create_profile" = "Crear perfil"; +/* Login screen text */ +"create_account_username_title" = "Com et veuran els contactes?"; +/* Login screen text */ +"create_account_username_placeholder" = "Nom d'usuari"; +/* Login screen text */ +"create_account_profile_placeholder" = "Nom del perfil"; +/* Login screen text */ +"import_profile" = "Importar perfil"; +/* Login screen text */ +"import_to_antidote" = "Importar a Antidote"; +/* Login screen text */ +"create_account_profile_hint" = "per exemple: Casa, iPhone"; +/* Login screen text */ +"set_password_title" = "Establir contrasenya"; +/* PIN screen error */ +"pin_do_not_match" = "Els PIN no coincideixen. Torna-ho a provar"; +/* PIN screen error */ +"pin_incorrect" = "PIN incorrecte"; +/* PIN screen error details */ +"pin_failed_attempts" = "Intents fallits: %@"; +/* PIN screen screen */ +"pin_lock_immediately" = "Immediatament"; +/* PIN screen screen */ +"pin_lock_30_seconds" = "30 segons"; +/* Login button */ +"create_account_go_button" = "Anar"; +/* PIN screen text */ +"pin_set" = "Establir el PIN"; +/* PIN screen text */ +"pin_confirm" = "Confirmar el PIN"; +/* PIN screen screen */ +"pin_enabled" = "Activar el PIN"; +/* PIN screen screen */ +"pin_description" = "Evitar l'accés no autoritzat a Antidote amb un PIN."; +/* PIN screen screen */ +"pin_touch_id_description" = "Utilitzar l'empremta com a alternativa al PIN."; +/* PIN screen screen */ +"pin_touch_id_enabled" = "Activar Touch ID"; +/* PIN screen screen */ +"pin_lock_timeout" = "Temps d'autobloqueig"; +/* PIN screen screen */ +"pin_lock_5_minutes" = "5 minuts"; + +/* Tab name and screen name */ +"contacts_title" = "Contactes"; +/* Tab name and screen name */ +"chats_title" = "Xats"; +/* Tab name and screen name */ +"settings_title" = "Configuració"; +/* Tab name and screen name */ +"profile_title" = "Perfil"; + +/* No contacts placeholder text */ +"contact_no_contacts" = "Sense contactes"; +/* Contact request section title */ +"contact_requests_section" = "Sol·licituds de contacte"; +/* Contact last seen status */ +"contact_last_seen" = "Última visualització: %@"; +/* Contact request button */ +"contact_request_decline" = "Rebutjar"; +/* No contacts placeholder text */ +"contact_no_contacts_add_contact" = "Afegir un contacte\no\n"; +/* PIN screen screen */ +"pin_lock_2_minutes" = "2 minuts"; +/* No contacts placeholder text */ +"contact_no_contacts_share_tox_id" = "compartir el teu Tox ID"; +/* Text shown when contact was deleted */ +"contact_deleted" = "Contacte eliminat"; + +/* Share Tox ID text */ +"show_qr_code" = "Mostrar el codi QR"; +/* Share Tox ID text */ +"copy" = "Copiar"; + +/* Add contat screen name */ +"add_contact_title" = "Afegir contacte"; +/* Add contat button */ +"add_contact_send" = "Enviar"; +/* Add contat placeholder text */ +"add_contact_or_label" = "o"; +/* Add contat placeholder text */ +"add_contact_default_message_title" = "Missatge"; +/* Add contat default text sended to contact */ +"add_contact_default_message_text" = "Hola! Vols afegir-me?"; +/* Add contat error */ +"add_contact_wrong_qr" = "Codi QR erroni. Ha de contenir el Tox ID"; + +/* User name text */ +"name" = "Nom"; +/* User nickname text */ +"nickname" = "Sobrenom"; +/* User status message text */ +"status_message" = "Missatge d'estat"; +/* User status text */ +"status_title" = "Estat"; +/* User public key text */ +"public_key" = "Clau pública"; +/* Profile menu item / screen name */ +"profile_details" = "Detalls del perfil"; +/* Profile button */ +"logout_button" = "Sortir"; + +/* QR code screen button */ +"qr_close_button" = "Tancar"; + +/* Chat screen placeholder */ +"chat_no_chats" = "Sense xats"; +/* Chats screen message text */ +"chat_outgoing_file" = "Fitxer sortint:"; +/* Chats screen message text */ +"chat_incoming_file" = "Fitxer entrant:"; +/* Chat button */ +"chat_send_button" = "Enviar"; +/* Chat notification toast */ +"chat_new_messages" = "↓ Missatges nous"; +/* Chat call information */ +"chat_call_message" = "Trucada, "; +/* Chat call information */ +"chat_missed_call_message" = "Trucada perduda"; +/* Item present in the menu on long press on message */ +"chat_more_menu_item" = "Més"; +/* Message shown on chat list when contact is typing */ +"chat_is_typing_text" = "està escrivint..."; +/* Status message */ +"status_online" = "Connectat"; + +/* Status message */ +"status_offline" = "No connectat"; +/* Status message */ +"status_away" = "Lluny"; +/* Status message */ +"status_busy" = "Ocupat"; + +/* Notification text */ +"notification_new_message" = "Missatge nou"; +/* Add contat placeholder text */ +"add_contact_tox_id_placeholder" = "Introduïr el Tox ID"; +/* Add contat button */ +"add_contact_use_qr" = "Utilitzar el codi QR"; +/* Share Tox ID text */ +"show_qr" = "Mostrar el QR"; +/* Chats screen message text */ +"chat_unanwered_call" = "Trucada sense resposta"; +/* Notification text */ +"notification_is_calling" = "està trucant"; +/* Notification text */ +"notification_incoming_file" = "Fitxer entrant"; + +/* Settings menu / screen name */ +"settings_about" = "Quant a"; +/* Settings menu / screen name */ +"settings_faq" = "Preguntes freqüents"; +/* About screen menu */ +"settings_antidote_version" = "Versió d'Antidote"; +/* About screen menu */ +"settings_antidote_build" = "Compilació d'Antidote"; +/* About screen menu */ +"settings_toxcore_version" = "Versió de Toxcore"; +/* Settings screen menu */ +"settings_autodownload_images" = "Descàrrega automàtica de fitxers"; +/* Settings screen menu */ +"settings_notifications_message_preview" = "Previsualitzar les notificacions"; +/* Settings screen menu */ +"settings_notifications_description" = "Quan l'aplicació passa a segon pla, rebràs notificacions durant 10 minuts."; +/* Settings screen menu */ +"settings_udp_enabled" = "Activar UDP"; +/* Settings screen menu */ +"settings_restore_default" = "Restaurar la configuració predeterminada"; +/* Settings screen autodownload images option */ +"settings_never" = "Mai"; +/* Settings screen autodownload images option */ +"settings_wifi" = "Wi-Fi"; +/* Settings screen autodownload images option */ +"settings_using_wifi" = "Utilitzant Wi-Fi"; +/* Profile settings menu */ +"delete_password" = "Eliminar contrasenya"; + +/* Profile settings menu */ +"change_password" = "Canviar contrasenya"; +/* Profile settings menu */ +"old_password" = "Contrasenya antiga"; +/* Change password text */ +"new_password" = "Contrasenya nova"; +/* Change password text */ +"repeat_password" = "Repetir contrasenya"; +/* Change password button */ +"change_password_done" = "Fet"; +/* Change password error */ +"password_is_empty_error" = "La contrasenya no pot de ser buida"; +/* Change password error */ +"wrong_old_password" = "Contrasenya incorrecta"; +/* Change password error */ +"passwords_do_not_match" = "Les contrasenyes no coincideixen"; + +/* Source of photo to take */ +"photo_from_camera" = "Càmera"; +/* Source of photo to take */ +"photo_from_photo_library" = "Fototeca"; +/* Error while converting avatar image */ +"change_avatar_error_convert_image" = "No es pot convertir la imatge"; + +/* Alert text when sending file to contacts */ +"file_send_to_contact" = "Enviar a un contacte"; + +/* Profile menu item */ +"export_profile" = "Exportar perfil"; +/* Profile menu item */ +"delete_profile" = "Eliminar perfil"; +/* Delete profile confirmation */ +"delete_profile_confirmation_title_2" = "Estàs segur?"; +/* Delete profile confirmation */ +"delete_profile_confirmation_message" = "Aquesta operació no es pot desfer"; + +/* Call screen text */ +"call_incoming" = "Trucada entrant"; +/* Call screen text */ +"call_ended" = "Trucada finalitzada"; +/* About screen menu */ +"settings_acknowledgements" = "Agraïments"; + +/* File message text */ +"chat_file_cancelled" = "Cancel·lat"; +/* File message text */ +"chat_waiting" = "En espera..."; +/* File message text */ +"chat_paused" = "En pausa"; +/* Deleting multiple messages in chat. */ +"delete_multiple_messages" = "Eliminar missatges"; +/* Delete button */ +"alert_delete" = "Eliminar"; +/* Delete button */ +"alert_cancel" = "Cancel·lar"; + +/* Error while creating new profile */ +"login_enter_username_and_profile" = "Introduir el nom d'usuari i el nom del perfil."; +/* Error while creating new profile */ +"login_profile_already_exists" = "Ja existeix un perfil amb aquest nom"; + +/* General error title */ +"error_title" = "Error"; +/* General error button */ +"error_ok_button" = "OK"; +/* Error */ +"error_contact_not_connected" = "El contacte no està connectat"; +/* Error */ +"error_too_many_files" = "Massa transferències de fitxers actives"; +/* Error */ +"error_internal_message" = "Error intern"; +/* Error */ +"error_wrong_password_title" = "Contrasenya incorrecta"; + +/* Deleting chat confirmation */ +"delete_chat_title" = "Eliminar aquest xat i els missatges?"; +/* Deleting contat request confirmation */ +"delete_contact_request_title" = "Eliminar aquesta sol·licitud de contacte?"; +/* Error */ +"error_import_not_exist_message" = "El fitxer no existeix."; +/* Error */ +"error_decrypt_empty_data_message" = "Algunes dades d'entrada estaven buides."; +/* Error */ +"error_decrypt_bad_format_message" = "El fitxer té un format incorrecte o està corrupte."; +/* Error */ +"error_decrypt_wrong_password_message" = "La contrasenya és incorrecta o el fitxer està corrupte."; +/* Error */ +"error_general_unknown_message" = "Error desconegut."; +/* Error */ +"error_general_no_memory_message" = "Memòria insuficient."; +/* Error */ +"error_general_bind_port_message" = "Error en la connexió al port."; +/* Error */ +"error_general_profile_encrypted_message" = "El perfil està xifrat."; +/* Error */ +"error_proxy_title" = "Error de proxy"; +/* Error */ +"error_proxy_invalid_address_message" = "L'adreça de proxy té un format no vàlid."; +/* Error */ +"error_proxy_invalid_port_message" = "El port del proxy no és vàlid."; +/* Error */ +"error_proxy_host_not_resolved_message" = "No s'ha pogut resoldre el proxy."; + +/* Error */ +"error_name_too_long" = "El nom és massa llarg."; +/* Error */ +"error_status_message_too_long" = "El missatge d'estat és massa llarg"; + +/* Error */ +"error_contact_request_too_long" = "Missatge massa llarg"; +/* Error */ +"error_contact_request_no_message" = "No s'ha especificat cap missatge"; +/* Error */ +"error_contact_request_own_key" = "No em puc afegir a la llista de contactes"; +/* Error */ +"error_contact_request_already_sent" = "La sol·licitud de contacte ja s'ha enviat"; +/* Error */ +"error_contact_request_new_nospam" = "Valor de no spam incorrecte, comprova el Tox ID introduït"; +/* Call error */ +"call_error_contact_is_offline" = "El contacte està desconnectat"; +/* Call error */ +"call_error_no_active_call" = "No hi ha cap trucada activa"; + +/* Error while using color theme */ +"theme_error_cannot_open" = "No es pot obrir el tema, format incorrecte"; + +/* Tab chats badge ending */ +"accessibility_chats_ending" = "xats no llegits"; +/* Avatar button label in settings */ +"accessibility_avatar_button_label" = "Avatar"; +/* Avatar button hint in settings */ +"accessibility_avatar_button_hint" = "Establir o eliminar l'avatar."; +/* Chat button label in contact screen */ +"accessibility_chat_button_label" = "Xat"; +/* Chat button hint in contact screen */ +"accessibility_chat_button_hint" = "Obrir el diàleg de xat."; +/* Call button label in contact screen */ +"accessibility_call_button_label" = "Trucada d'àudio"; +/* Video button label in contact screen */ +"accessibility_video_button_label" = "Trucada de vídeo"; +/* Tap to copy hint */ +"accessibility_show_copy_hint" = "Mostrar el menú de còpia."; +/* Tap to edit value hint */ +"accessibility_edit_value_hint" = "Modificar el valor."; +/* Outgoing message label */ +"accessibility_outgoing_message_label" = "El teu missatge"; +/* Video button hint in contact screen */ +"accessibility_video_button_hint" = "Fer una trucada de vídeo."; +/* Error */ +"error_general_bad_format_message" = "El fitxer té un format incorrecte o està corrupte."; +/* Error */ +"error_contact_request_bad_checksum" = "Suma de comprovació incorrecta, comprova el Tox ID introduït"; +/* Login screen text */ +"create_account_profile_title" = "Nom d'aquest perfil?"; +/* Login screen text */ +"set_password_hint" = "La contrasenya és necessària per a protegir les teves dades. Guarda-la bé: un cop perduda, no es pot recuperar."; +/* Default status message */ +"default_user_status_message" = "Toxing a Antidote"; +/* Login button */ +"create_account_next_button" = "Següent"; +/* PIN screen message shown on log out */ +"pin_logout_message" = "Massa intents fallits. La sessió s'ha tancat."; +/* PIN screen screen */ +"pin_lock_1_minute" = "1 minut"; + +/* Label shown when connecting to Tox network */ +"connecting_label" = "Connectant..."; +/* Screen name */ +"contact_request" = "Sol·licitud de contacte"; + +/* PIN screen text */ +"pin_enter_to_unlock" = "Introduïr el PIN per a desbloquejar"; +/* User Tox ID text */ +"my_tox_id" = "El meu Tox ID"; +/* Contact request confirmation */ +"contact_request_delete_title" = "Eliminar la sol·licitud de contacte?"; +/* Text shown in chat when there are undelivered faux offline messages */ +"chat_pending_faux_offline_messages" = "Els missatges no lliurats s'enviaran quan el teu amic i tu estigueu connectats."; +/* Chats screen message text */ +"chat_call_finished" = "Trucada finalitzada"; +/* Notification text */ +"notification_incoming_contact_request" = "Sol·licitud de contacte entrant"; +/* Settings menu / screen name */ +"settings_advanced_settings" = "Configuració avançada"; +/* Settings screen menu */ +"settings_autodownload_images_description" = "Descàrregar automàticament fitxers entrants."; +/* Settings screen autodownload images option */ +"settings_always" = "Sempre"; +/* Delete profile confirmation */ +"delete_profile_confirmation_title_1" = "Eliminar aquest perfil?"; +/* Deleting contat confirmation */ +"delete_contact_title" = "Eliminar aquest contacte?\nEs perdrà l'historial de xat."; +/* Call screen text */ +"call_reaching" = "Contactant..."; +/* Deleting all messages in chat. */ +"delete_all_messages" = "Eliminar-ho tot"; +/* Error */ +"error_wrong_password_message" = "La contrasenya conté símbols no permesos."; +/* Error */ +"error_decrypt_title" = "No s'ha pogut desxifrar el fitxer tox"; +/* General error button */ +"error_retry_button" = "Reintentar"; + +/* Call error */ +"call_error_already_in_call" = "Ja en una trucada"; +/* Incoming message label */ +"accessibility_incoming_message_label" = "Missatge"; +/* Call button hint in contact screen */ +"accessibility_call_button_hint" = "Fer una trucada d'àudio."; +/* Deleting single message in chat */ +"delete_single_message" = "Eliminar missatge"; +/* Error */ +"error_import_not_exist_title" = "No s'ha pogut importar el fitxer tox"; diff --git a/Antidote/ca.lproj/import-profile.html b/Antidote/ca.lproj/import-profile.html new file mode 100644 index 0000000..7f2b2f3 --- /dev/null +++ b/Antidote/ca.lproj/import-profile.html @@ -0,0 +1,10 @@ + +

To import your Tox profile:

+ +
    +
  1. Send the ".tox" file to your device using any app (Mail, Dropbox, etc.).
  2. +
  3. Use "Open In" menu for this file.
  4. +
  5. Select Antidote in a list of available apps.
  6. +
  7. Check the name of your new profile and press OK.
  8. +
+
diff --git a/Antidote/cs.lproj/InfoPlist.strings b/Antidote/cs.lproj/InfoPlist.strings new file mode 100644 index 0000000000000000000000000000000000000000..df6a0c0f356b666f638cee6ac7528f77d95d2053 GIT binary patch literal 998 zcmb`G!A`I!s%1iDtH7v&mgqE{6v)o^-_muZOY^E!AXv4q@GDN!HqYK|AV zSOQ+G3f7`k z+(K)n^qF>lrN)kV+htQ}b_PPs_kg*^*qOufb$7ZaKGr*ZDi{iNxx-JN{g-u{c z$MJLs@&EXW;4g9aV>h^EVV}R>TMpcArDMqcfS8RV#9r|+Z(@skvxj=jzJI%Ozu_1E CSFX(f literal 0 HcmV?d00001 diff --git a/Antidote/cs.lproj/Localizable.strings b/Antidote/cs.lproj/Localizable.strings new file mode 100644 index 0000000..4f3fcf1 --- /dev/null +++ b/Antidote/cs.lproj/Localizable.strings @@ -0,0 +1,411 @@ +/* + Localizable.strings + Antidote + + Created by Dmytro Vorobiov on 08/10/15. + Copyright © 2015 dvor. All rights reserved. +*/ + +/* + Translation is done with Transifex service. + See https://www.transifex.com/antidote/antidote-ios/ +*/ + +/* Login screen text */ +"login_or_label" = "nebo"; +/* Login screen text */ +"create_account" = "Vytvořit účet"; +/* Login screen text */ +"import_profile" = "Importovat profil"; +/* Password field */ +"password" = "Heslo"; +/* Login button */ +"log_in" = "Přihlásit"; +/* Login screen text */ +"create_profile" = "Vytvořit profil"; +/* Login screen text */ +"import_to_antidote" = "Importovat do Antidote"; +/* Login screen text */ +"create_account_username_title" = "Jak Vás kontakty uvidí?"; +/* Login screen text */ +"create_account_username_placeholder" = "Uživatelské jméno"; +/* Login screen text */ +"create_account_profile_title" = "Jak nazvete tento profil?"; +/* Login screen text */ +"create_account_profile_placeholder" = "Název profilu"; +/* Login screen text */ +"create_account_profile_hint" = "např. Domací, iPhone"; +/* Login screen text */ +"set_password_title" = "Nastavit heslo"; +/* Login screen text */ +"set_password_hint" = "Heslo je vyžadováno k ochraně Vašich dat. Uložte si jej na bezpečné místo - v budoucnu již nejde obnovit."; +/* Login button */ +"create_account_next_button" = "Další"; +/* Login button */ +"create_account_go_button" = "Založit"; +/* Default status message */ +"default_user_status_message" = "Toxuju přes Antidote"; + +/* PIN screen text */ +"pin_enter_to_unlock" = "Vložte kód pro odemčení"; +/* PIN screen text */ +"pin_set" = "Nastavit kód"; +/* PIN screen text */ +"pin_confirm" = "Potvrdit kód"; +/* PIN screen error */ +"pin_do_not_match" = "Zadané kódy nesouhlasí. Zkuste to znovu"; +/* PIN screen error */ +"pin_incorrect" = "Špatný kód"; +/* PIN screen error details */ +"pin_failed_attempts" = "Špatných pokusů: %@"; +/* PIN screen message shown on log out */ +"pin_logout_message" = "Příliš mnoho špatných pokusů. Účet byl odhlášen."; +/* PIN screen screen */ +"pin_enabled" = "Aktivovat PIN"; +/* PIN screen screen */ +"pin_touch_id_enabled" = "Aktivovat Touch ID"; +/* PIN screen screen */ +"pin_description" = "Chraňte Antidote kódem před neoprávněným přístupem."; +/* PIN screen screen */ +"pin_touch_id_description" = "Můžete použít Váš otisk prstu jako alternativu k zadání kódu."; +/* PIN screen screen */ +"pin_lock_timeout" = "Požadovat kód"; +/* PIN screen screen */ +"pin_lock_immediately" = "Ihned"; +/* PIN screen screen */ +"pin_lock_30_seconds" = "30 sekund"; +/* PIN screen screen */ +"pin_lock_1_minute" = "1 minuta"; +/* PIN screen screen */ +"pin_lock_2_minutes" = "2 minuty"; +/* PIN screen screen */ +"pin_lock_5_minutes" = "5 minut"; + +/* Label shown when connecting to Tox network */ +"connecting_label" = "Připojuji..."; + +/* Tab name and screen name */ +"contacts_title" = "Kontakty"; +/* Tab name and screen name */ +"chats_title" = "Konverzace"; +/* Tab name and screen name */ +"settings_title" = "Nastavení"; +/* Tab name and screen name */ +"profile_title" = "Profil"; + +/* No contacts placeholder text */ +"contact_no_contacts" = "Žádné kontakty"; +/* No contacts placeholder text */ +"contact_no_contacts_add_contact" = "Přidat kontakt\nnebo\n"; +/* No contacts placeholder text */ +"contact_no_contacts_share_tox_id" = "sdílet Vaše Tox ID"; +/* Contact request section title */ +"contact_requests_section" = "Žádosti o kontakt"; +/* Contact last seen status */ +"contact_last_seen" = "Naposledy viděn: %@"; +/* Screen name */ +"contact_request" = "Žádost o kontakt"; +/* Contact request button */ +"contact_request_decline" = "Zamítnout"; +/* Contact request button */ +"contact_request_accept" = "Přijmout"; +/* Contact request confirmation */ +"contact_request_delete_title" = "Smazat žádost?"; +/* Text shown when contact was deleted */ +"contact_deleted" = "Smazaný kontakt"; + +/* Share Tox ID text */ +"show_qr_code" = "Zobrazit QR kód"; +/* Share Tox ID text */ +"copy" = "Kopírovat"; + +/* Add contat screen name */ +"add_contact_title" = "Přidat kontakt"; +/* Add contat button */ +"add_contact_send" = "Odeslat"; +/* Add contat placeholder text */ +"add_contact_tox_id_placeholder" = "Vložte Tox ID"; +/* Add contat placeholder text */ +"add_contact_or_label" = "nebo"; +/* Add contat button */ +"add_contact_use_qr" = "načtěte QR kód"; +/* Add contat placeholder text */ +"add_contact_default_message_title" = "Zpráva"; +/* Add contat default text sended to contact */ +"add_contact_default_message_text" = "Ahoj! Můžeš si mě prosím přidat do kontaktů?"; +/* Add contat error */ +"add_contact_wrong_qr" = "Špatný QR kód. Neobsahuje Tox ID"; + +/* User name text */ +"name" = "Jméno"; +/* User nickname text */ +"nickname" = "Přezdívka"; +/* User status message text */ +"status_message" = "Stav"; +/* User status text */ +"status_title" = "Stav"; +/* User Tox ID text */ +"my_tox_id" = "Moje Tox ID"; +/* User public key text */ +"public_key" = "Veřejný klíč"; +/* Share Tox ID text */ +"show_qr" = "Zobrazit QR"; +/* Profile menu item / screen name */ +"profile_details" = "Detaily profilu"; +/* Profile button */ +"logout_button" = "Odhlásit"; + +/* QR code screen button */ +"qr_close_button" = "Zavřít"; + +/* Chat screen placeholder */ +"chat_no_chats" = "Žádné konverzace"; +/* Chats screen message text */ +"chat_outgoing_file" = "Odchozí soubor:"; +/* Chats screen message text */ +"chat_incoming_file" = "Příchozí soubor:"; +/* Chats screen message text */ +"chat_call_finished" = "Hovor ukončen"; +/* Chats screen message text */ +"chat_unanwered_call" = "Nepřijatý hovor"; +/* Chat button */ +"chat_send_button" = "Poslat"; +/* Chat notification toast */ +"chat_new_messages" = "↓ Nová zpráva"; +/* Chat call information */ +"chat_call_message" = "Hovor,"; +/* Chat call information */ +"chat_missed_call_message" = "Zmeškaný hovor"; +/* Item present in the menu on long press on message */ +"chat_more_menu_item" = "Více"; + +/* Status message */ +"status_offline" = "Odpojen"; +/* Status message */ +"status_online" = "Připojen"; +/* Status message */ +"status_away" = "Pryč"; +/* Status message */ +"status_busy" = "Nedostupný"; + +/* Notification text */ +"notification_new_message" = "Nová zpráva"; +/* Notification text */ +"notification_incoming_contact_request" = "Příchozí žádost o kontakt"; +/* Notification text */ +"notification_is_calling" = "telefonuje"; +/* Notification text */ +"notification_incoming_file" = "Příchozí soubor"; + +/* Settings menu / screen name */ +"settings_about" = "O Antidote"; +/* Settings menu / screen name */ +"settings_faq" = "FAQ"; +/* Settings menu / screen name */ +"settings_advanced_settings" = "Pokročilé nastavení"; +/* About screen menu */ +"settings_antidote_version" = "Verze Antidote"; +/* About screen menu */ +"settings_antidote_build" = "Sestavení Antidote"; +/* About screen menu */ +"settings_toxcore_version" = "Verze Toxcore"; +/* About screen menu */ +"settings_acknowledgements" = "Poděkování"; +/* Settings screen menu */ +"settings_autodownload_images" = "Automaticky stahovat obrázky"; +/* Settings screen menu */ +"settings_autodownload_images_description" = "Automaticky stahovat příchozí obrázky"; +/* Settings screen menu */ +"settings_notifications_message_preview" = "Náhled notifikací"; +/* Settings screen menu */ +"settings_notifications_description" = "Jakmile přepnete aplikaci do pozadí, budete dostavát notifikace dalších 10 minut."; +/* Settings screen menu */ +"settings_udp_enabled" = "Aktivovat UDP"; +/* Settings screen menu */ +"settings_restore_default" = "Obnovit výchozí nastavení"; +/* Settings screen autodownload images option */ +"settings_never" = "Nikdy"; +/* Settings screen autodownload images option */ +"settings_wifi" = "Wi-Fi"; +/* Settings screen autodownload images option */ +"settings_using_wifi" = "Pouze přes Wi-Fi"; +/* Settings screen autodownload images option */ +"settings_always" = "Vždy"; + +/* Profile settings menu */ +"change_password" = "Změnit heslo"; +/* Profile settings menu */ +"delete_password" = "Smazat heslo"; +/* Profile settings menu */ +"old_password" = "Staré heslo"; +/* Change password text */ +"new_password" = "Nové heslo"; +/* Change password text */ +"repeat_password" = "Zopakujte nové heslo"; +/* Change password button */ +"change_password_done" = "Změnit"; +/* Change password error */ +"password_is_empty_error" = "Heslo by němělo být prázdné"; +/* Change password error */ +"wrong_old_password" = "Špatné heslo"; +/* Change password error */ +"passwords_do_not_match" = "Hesla nesedí"; + +/* Source of photo to take */ +"photo_from_camera" = "Pořídit snímek/video"; +/* Source of photo to take */ +"photo_from_photo_library" = "Knihovna obrázků"; +/* Error while converting avatar image */ +"change_avatar_error_convert_image" = "Nelze konvertovat obrázek"; + +/* Alert text when sending file to contacts */ +"file_send_to_contact" = "Odeslat kontakt"; + +/* Profile menu item */ +"export_profile" = "Exportovat profil"; +/* Profile menu item */ +"delete_profile" = "Smazat profil"; +/* Delete profile confirmation */ +"delete_profile_confirmation_title_1" = "Smazat tento profil?"; +/* Delete profile confirmation */ +"delete_profile_confirmation_title_2" = "Jste si jistý?"; +/* Delete profile confirmation */ +"delete_profile_confirmation_message" = "Tato operace nemůže být vrácena"; + +/* Call screen text */ +"call_incoming" = "Příchozí hovor"; +/* Call screen text */ +"call_ended" = "Hovor ukončen"; +/* Call screen text */ +"call_reaching" = "Vytáčím..."; + +/* File message text */ +"chat_file_cancelled" = "Zrušeno"; +/* File message text */ +"chat_waiting" = "Čekám..."; +/* File message text */ +"chat_paused" = "Pozastaveno"; + +/* Deleting chat confirmation */ +"delete_chat_title" = "Smazat tuto konverzaci a její historii?"; +/* Deleting contat confirmation */ +"delete_contact_title" = "Smazat tento kontakt?\nHistorie bude ztracena."; +/* Deleting contat request confirmation */ +"delete_contact_request_title" = "Smazat tuto žádost?"; +/* Deleting single message in chat */ +"delete_single_message" = "Smazat zprávu"; +/* Deleting multiple messages in chat. */ +"delete_multiple_messages" = "Smazané zprávy"; +/* Deleting all messages in chat. */ +"delete_all_messages" = "Smazat vše"; +/* Delete button */ +"alert_delete" = "Smazat"; +/* Delete button */ +"alert_cancel" = "Zrušit"; + +/* Error while creating new profile */ +"login_enter_username_and_profile" = "Prosím zadejte uživatelské jméno a název profilu"; +/* Error while creating new profile */ +"login_profile_already_exists" = "Profil s tímto jménem již existuje"; + +/* General error title */ +"error_title" = "Chyba"; +/* General error button */ +"error_ok_button" = "OK"; +/* General error button */ +"error_retry_button" = "Zkusit znovu"; +/* Error */ +"error_contact_not_connected" = "Kontakt není online"; +/* Error */ +"error_too_many_files" = "Příliš mnoho aktivních přenosů"; +/* Error */ +"error_internal_message" = "Interní chyba"; +/* Error */ +"error_wrong_password_title" = "Špatné heslo"; +/* Error */ +"error_wrong_password_message" = "Heslo nemůže obsahovat symboly."; +/* Error */ +"error_import_not_exist_title" = "Nelze importovat tox profil"; +/* Error */ +"error_import_not_exist_message" = "Soubor neexistuje."; +/* Error */ +"error_decrypt_title" = "Nelze rozšifrovat tox profil"; +/* Error */ +"error_decrypt_empty_data_message" = "Některá vstupní data jsou prázdná."; +/* Error */ +"error_decrypt_bad_format_message" = "Soubor má špatný formát nebo je poškozen."; +/* Error */ +"error_decrypt_wrong_password_message" = "Heslo je špatné nebo je poškozen soubor."; +/* Error */ +"error_general_unknown_message" = "Vyskytla se neznámý chyba."; +/* Error */ +"error_general_no_memory_message" = "Nedostatek paměti."; +/* Error */ +"error_general_bind_port_message" = "Nebylo možné se připojit na port"; +/* Error */ +"error_general_profile_encrypted_message" = "Profil je zašifrován."; +/* Error */ +"error_general_bad_format_message" = "Soubor má špatný formát nebo je poškozen."; +/* Error */ +"error_proxy_title" = "Chyba proxy"; +/* Error */ +"error_proxy_invalid_address_message" = "Proxy adresa má špatný formát"; +/* Error */ +"error_proxy_invalid_port_message" = "Port proxy je špatný"; +/* Error */ +"error_proxy_host_not_resolved_message" = "Proxy host nemůže být rozpoznán."; + +/* Error */ +"error_name_too_long" = "Jméno je moc dlouhé"; +/* Error */ +"error_status_message_too_long" = "Stav je moc dlouhý"; + +/* Error */ +"error_contact_request_too_long" = "Zpráva je moc dlouhá"; +/* Error */ +"error_contact_request_no_message" = "Žádná zpráva není specifikována"; +/* Error */ +"error_contact_request_own_key" = "Nemůžu se sám přidat mezi kontakty"; +/* Error */ +"error_contact_request_already_sent" = "Žádost o kontakt byla již odeslána"; +/* Error */ +"error_contact_request_bad_checksum" = "Špatný kontrolní součet, prosím zkontrolujte vložené Tox ID"; +/* Error */ +"error_contact_request_new_nospam" = "Špatná hodnota nospam, prosím zkontrolujte vložené Tox ID"; + +/* Call error */ +"call_error_already_in_call" = "Již hovoří"; +/* Call error */ +"call_error_contact_is_offline" = "Kontakt je offline"; +/* Call error */ +"call_error_no_active_call" = "Není žádný aktivní hovor"; + +/* Error while using color theme */ +"theme_error_cannot_open" = "Nemůžu otevřít motiv, špatný formát"; + +/* Tab chats badge ending */ +"accessibility_chats_ending" = "nepřečtené zprávy"; +/* Avatar button label in settings */ +"accessibility_avatar_button_label" = "Avatar"; +/* Avatar button hint in settings */ +"accessibility_avatar_button_hint" = "Nastavit nebo odebrat avatar."; +/* Chat button label in contact screen */ +"accessibility_chat_button_label" = "Zpráva"; +/* Chat button hint in contact screen */ +"accessibility_chat_button_hint" = "Otevře konverzaci"; +/* Call button label in contact screen */ +"accessibility_call_button_label" = "Zavolat"; +/* Call button hint in contact screen */ +"accessibility_call_button_hint" = "Vytvoří hovor"; +/* Video button label in contact screen */ +"accessibility_video_button_label" = "Video"; +/* Video button hint in contact screen */ +"accessibility_video_button_hint" = "Vytvoří videohovor"; +/* Tap to copy hint */ +"accessibility_show_copy_hint" = "Zobrazí menu ke kopírování"; +/* Tap to edit value hint */ +"accessibility_edit_value_hint" = "Upraví položku"; +/* Incoming message label */ +"accessibility_incoming_message_label" = "Zpráva"; +/* Outgoing message label */ +"accessibility_outgoing_message_label" = "Vaše zpráva"; \ No newline at end of file diff --git a/Antidote/cs.lproj/import-profile.html b/Antidote/cs.lproj/import-profile.html new file mode 100644 index 0000000..70837ff --- /dev/null +++ b/Antidote/cs.lproj/import-profile.html @@ -0,0 +1,9 @@ + +

Pro import Tox profilu:

+ +
    +
  1. Přeneste soubor do telefonu (např. emailem, Dropboxem apod.).
  2. +
  3. Použijte "Otevřít v" menu pro tento soubor.
  4. +
  5. Vyberte Antidote v seznamu aplikací.
  6. +
  7. Zkontrolujte jméno vašeho profilu a zvolte OK.
  8. +
diff --git a/Antidote/da.lproj/AppStoreLocalizable.strings b/Antidote/da.lproj/AppStoreLocalizable.strings new file mode 100644 index 0000000000000000000000000000000000000000..03d6b2f17d466174e7e0f4ffb445ca8aa0e0b572 GIT binary patch literal 7646 zcmeI1OHUI~6vt1DD;CC&FtS8#1s@nqW3XrpA{a5aB!x~Nls-}l2EUQts2kb&9bBou z|G6D|i{OHVnI@CT+_`ff=bn51=W*xEub*XGvcwj+6I-(Z*N%;>Z$nFMljnie?8w^o zh37uC)Jk^Dh#_q~Yf{hV_GoQeojD^$Elk?0PO0W?b=KIoGs<=A@)VUmZ@a!;pT0J= zQ(F4aPV9j_wKC-j<+81^a#*WM|A6`8p=mAXB=(hig|Ql!z{RQ4EKy&B>m#1i(Z~Ll z!h1^VDP`ShFR_mJ4l>zd$6flwO@p%G6jC_TJ{nFxVeOWW39?Hf=_SxVU{1=_quyf1 zh;=kZ^%J-X644qBe?M~R3|U#L^jZHNeLZU8KXoh;_MXx*a5NHMUwxun^_h~gXf`Q( z+@dE;wAyE6CZ5Gz*nJx=HCiZlye5f`p#Ka>l$oKc1cx>6@9~seW~obKN>CEdWvB&N zE;3d+wa03iR;m8CT=r(3*dBbfb z!tFJP$v@Pye|l6Pn6tCY<>wgr(twuiPd>F<#6TpH zj~F<`EIz}?Yc@HnoM2;x&E@&~VTxaTe%S;$ebEZN4f}!r3|}!t%*)r;-xR(0%<{pJ z>rSliBR;di7ew*hkUyUppHe;%=ahkIgI?F|E+r!nTU?fLS;zZ#K{fF_LeDcZLq;ll zq0EqSLf6f^Tqh%;Y{q3=%;qCr;YE~Xn$3SDaNnj!85Qll$(UpN?xjwbY9F$%7c=@h zKN5(e;s$#ec&4gOP1!i@E##?GyH8u6Qh6)A#}+$3JC5VXw&U3XqHq-`GW*YmsKdg znMp0kF65Q<4LZ$Hsz-BWOUejJ#>$E+dQ0Eh+@hj6b-0*U9gF?u-N~M&_9VHUVMUUo zme<{Ny{NORJ9FwGR-@hQxUW|XkggwsmLkB&Yr*>mjTMF` z=xnh5%OYXRZqOX{lzg%Q9J0Q{=&(lW?CBli0L~#i*NF&(%$etMq~A#XFf5GBi05xQUub@ SI{)xH`9?L48sRJ!kogVSw??l3 literal 0 HcmV?d00001 diff --git a/Antidote/da.lproj/InfoPlist.strings b/Antidote/da.lproj/InfoPlist.strings new file mode 100644 index 0000000000000000000000000000000000000000..ebfec2086dc1e2fa63d57c2c6432ed88ea531b3b GIT binary patch literal 982 zcmb`F!A=4}5Jc{JXt*dIwx_45 zuI{Sg{jI5*f{yrtE>-ABrTUs`qNOS|JTABu8j(j_hg(H016wJl8tYvxxTRjp;2Y?L z*wc)&;Gs%1~#FRabL7Ae$cMAS$6$n#X z(iu={?_+(oeZ&u)zn~Iyt2@=toXAjZ2<-PjG`d6*LdFQC{17Sm^v;Y7A literal 0 HcmV?d00001 diff --git a/Antidote/da.lproj/Localizable.strings b/Antidote/da.lproj/Localizable.strings new file mode 100644 index 0000000..e240f5b --- /dev/null +++ b/Antidote/da.lproj/Localizable.strings @@ -0,0 +1,411 @@ +/* + Localizable.strings + Antidote + + Created by Dmytro Vorobiov on 08/10/15. + Copyright © 2015 dvor. All rights reserved. +*/ + +/* + Translation is done with Transifex service. + See https://www.transifex.com/antidote/antidote-ios/ +*/ + +/* Login screen text */ +"login_or_label" = "eller"; +/* Login screen text */ +"create_account" = "Opret en konto"; +/* Login screen text */ +"import_profile" = "Importer profil"; +/* Password field */ +"password" = "Adgangskode"; +/* Login button */ +"log_in" = "Log ind"; +/* Login screen text */ +"create_profile" = "Opret profil"; +/* Login screen text */ +"import_to_antidote" = "Importer til Antidote"; +/* Login screen text */ +"create_account_username_title" = "Hvordan kontakter vil se dig?"; +/* Login screen text */ +"create_account_username_placeholder" = "Brugernavn"; +/* Login screen text */ +"create_account_profile_title" = "Hvordan du ringer til denne profil?"; +/* Login screen text */ +"create_account_profile_placeholder" = "Profilnavn"; +/* Login screen text */ +"create_account_profile_hint" = "f.eks. Hjem, iPhone"; +/* Login screen text */ +"set_password_title" = "Indtast adgangskode"; +/* Login screen text */ +"set_password_hint" = "Adgangskoden er krævet for at beskytte dine data. Opbevar det et sikkert sted - hvis du mister det kan det ikke gendannes."; +/* Login button */ +"create_account_next_button" = "Næste"; +/* Login button */ +"create_account_go_button" = "Gå til"; +/* Default status message */ +"default_user_status_message" = "Toxer på Antidote"; + +/* PIN screen text */ +"pin_enter_to_unlock" = "Indtast din PIN-kode for at låse op"; +/* PIN screen text */ +"pin_set" = "Indstil PIN-kode"; +/* PIN screen text */ +"pin_confirm" = "Bekræft PIN-kode"; +/* PIN screen error */ +"pin_do_not_match" = "PIN-koderne er ikke ens. Prøv igen"; +/* PIN screen error */ +"pin_incorrect" = "Forkert PIN-kode"; +/* PIN screen error details */ +"pin_failed_attempts" = "Mislykkedes forsøg: %@"; +/* PIN screen message shown on log out */ +"pin_logout_message" = "Det var for mange mislykkede forsøg. Du er blevet logget ud."; +/* PIN screen screen */ +"pin_enabled" = "Aktiver PIN"; +/* PIN screen screen */ +"pin_touch_id_enabled" = "Aktiver Touch ID"; +/* PIN screen screen */ +"pin_description" = "Forhindre uautoriseret adgang til Antidote med en PIN-kode."; +/* PIN screen screen */ +"pin_touch_id_description" = "Brug dit fingeraftryk som et alternativ til indtastning af en PIN-kode."; +/* PIN screen screen */ +"pin_lock_timeout" = "Låsnings-timeout"; +/* PIN screen screen */ +"pin_lock_immediately" = "Øjeblikkeligt"; +/* PIN screen screen */ +"pin_lock_30_seconds" = "30 sekunder"; +/* PIN screen screen */ +"pin_lock_1_minute" = "1 minut"; +/* PIN screen screen */ +"pin_lock_2_minutes" = "2 minutter"; +/* PIN screen screen */ +"pin_lock_5_minutes" = "5 minutter"; + +/* Label shown when connecting to Tox network */ +"connecting_label" = "Forbinder..."; + +/* Tab name and screen name */ +"contacts_title" = "Kontakter"; +/* Tab name and screen name */ +"chats_title" = "Samtaler"; +/* Tab name and screen name */ +"settings_title" = "Indstillinger"; +/* Tab name and screen name */ +"profile_title" = "Profil"; + +/* No contacts placeholder text */ +"contact_no_contacts" = "Ingen kontakter"; +/* No contacts placeholder text */ +"contact_no_contacts_add_contact" = "Tilføj en kontakt\neller\n"; +/* No contacts placeholder text */ +"contact_no_contacts_share_tox_id" = "del dit Tox-ID"; +/* Contact request section title */ +"contact_requests_section" = "Kontakt-anmodninger"; +/* Contact last seen status */ +"contact_last_seen" = "Sidst set: %@"; +/* Screen name */ +"contact_request" = "Kontakt-anmodning"; +/* Contact request button */ +"contact_request_decline" = "Afvis"; +/* Contact request button */ +"contact_request_accept" = "Accepter"; +/* Contact request confirmation */ +"contact_request_delete_title" = "Slet kontakt-anmodning?"; +/* Text shown when contact was deleted */ +"contact_deleted" = "Kontaktperson slettet"; + +/* Share Tox ID text */ +"show_qr_code" = "Vis QR-kode"; +/* Share Tox ID text */ +"copy" = "Kopier"; + +/* Add contat screen name */ +"add_contact_title" = "Tilføj kontakt"; +/* Add contat button */ +"add_contact_send" = "Send"; +/* Add contat placeholder text */ +"add_contact_tox_id_placeholder" = "Indtast Tox-ID"; +/* Add contat placeholder text */ +"add_contact_or_label" = "eller"; +/* Add contat button */ +"add_contact_use_qr" = "Brug QR-kode"; +/* Add contat placeholder text */ +"add_contact_default_message_title" = "Besked"; +/* Add contat default text sended to contact */ +"add_contact_default_message_text" = "Hej! Vil du være så venlig at føje mig til din kontakt-liste?"; +/* Add contat error */ +"add_contact_wrong_qr" = "Forkert QR-kode. Det skal indeholde et Tox-ID"; + +/* User name text */ +"name" = "Navn"; +/* User nickname text */ +"nickname" = "Kaldenavn"; +/* User status message text */ +"status_message" = "Status-besked"; +/* User status text */ +"status_title" = "Status"; +/* User Tox ID text */ +"my_tox_id" = "Mit Tox-ID"; +/* User public key text */ +"public_key" = "Offentlig nøgle"; +/* Share Tox ID text */ +"show_qr" = "Vis QR"; +/* Profile menu item / screen name */ +"profile_details" = "Profil-detaljer"; +/* Profile button */ +"logout_button" = "Log ud"; + +/* QR code screen button */ +"qr_close_button" = "Luk"; + +/* Chat screen placeholder */ +"chat_no_chats" = "ingen samtaler"; +/* Chats screen message text */ +"chat_outgoing_file" = "Udgående fil:"; +/* Chats screen message text */ +"chat_incoming_file" = "Indkommende fil:"; +/* Chats screen message text */ +"chat_call_finished" = "Opkald afsluttet"; +/* Chats screen message text */ +"chat_unanwered_call" = "Ubesvaret opkald"; +/* Chat button */ +"chat_send_button" = "Send"; +/* Chat notification toast */ +"chat_new_messages" = "↓ Nye beskeder"; +/* Chat call information */ +"chat_call_message" = "Opkald,"; +/* Chat call information */ +"chat_missed_call_message" = "Mistet opkald"; +/* Item present in the menu on long press on message */ +"chat_more_menu_item" = "Mere"; + +/* Status message */ +"status_offline" = "Offline"; +/* Status message */ +"status_online" = "Online"; +/* Status message */ +"status_away" = "Ikke til stede"; +/* Status message */ +"status_busy" = "Optaget"; + +/* Notification text */ +"notification_new_message" = "Ny besked"; +/* Notification text */ +"notification_incoming_contact_request" = "Indkommende kontakt-anmodning"; +/* Notification text */ +"notification_is_calling" = "ringer til dig"; +/* Notification text */ +"notification_incoming_file" = "Indkommende fil"; + +/* Settings menu / screen name */ +"settings_about" = "Om"; +/* Settings menu / screen name */ +"settings_faq" = "FAQ"; +/* Settings menu / screen name */ +"settings_advanced_settings" = "Avancerede indstillinger"; +/* About screen menu */ +"settings_antidote_version" = "Antidote version"; +/* About screen menu */ +"settings_antidote_build" = "Antidote Build"; +/* About screen menu */ +"settings_toxcore_version" = "Toxcore Version"; +/* About screen menu */ +"settings_acknowledgements" = "Taksigelser"; +/* Settings screen menu */ +"settings_autodownload_images" = "Hent billeder automatisk"; +/* Settings screen menu */ +"settings_autodownload_images_description" = "Hent automatisk indkommende billeder."; +/* Settings screen menu */ +"settings_notifications_message_preview" = "Notifikations-forevisning"; +/* Settings screen menu */ +"settings_notifications_description" = "Når appen er i baggrunden vil du stadig modtage notifikationer i op til 10 minutter."; +/* Settings screen menu */ +"settings_udp_enabled" = "Aktiver UDP"; +/* Settings screen menu */ +"settings_restore_default" = "Gendan standardindstillinger"; +/* Settings screen autodownload images option */ +"settings_never" = "Aldrig"; +/* Settings screen autodownload images option */ +"settings_wifi" = "Wi-Fi"; +/* Settings screen autodownload images option */ +"settings_using_wifi" = "Ved brug af Wi-Fi"; +/* Settings screen autodownload images option */ +"settings_always" = "Altid"; + +/* Profile settings menu */ +"change_password" = "Skift adgangskode"; +/* Profile settings menu */ +"delete_password" = "Slet adgangskode"; +/* Profile settings menu */ +"old_password" = "Gammel adgangskode"; +/* Change password text */ +"new_password" = "Ny adgangskode"; +/* Change password text */ +"repeat_password" = "Gentag ny adgangskode"; +/* Change password button */ +"change_password_done" = "Færdig"; +/* Change password error */ +"password_is_empty_error" = "Adgangskoden skulle ikke være tom"; +/* Change password error */ +"wrong_old_password" = "Forkert adgangskode"; +/* Change password error */ +"passwords_do_not_match" = "Adgangskoderne er ikke ens"; + +/* Source of photo to take */ +"photo_from_camera" = "Kamera"; +/* Source of photo to take */ +"photo_from_photo_library" = "Foto-bibliotek"; +/* Error while converting avatar image */ +"change_avatar_error_convert_image" = "Kan ikke konvertere billede"; + +/* Alert text when sending file to contacts */ +"file_send_to_contact" = "Send til kontakt"; + +/* Profile menu item */ +"export_profile" = "Eksporter profil"; +/* Profile menu item */ +"delete_profile" = "Slet profil"; +/* Delete profile confirmation */ +"delete_profile_confirmation_title_1" = "Slet denne profil?"; +/* Delete profile confirmation */ +"delete_profile_confirmation_title_2" = "Er du sikker?"; +/* Delete profile confirmation */ +"delete_profile_confirmation_message" = "Denne handling kan ikke fortrydes"; + +/* Call screen text */ +"call_incoming" = "Indkommende opkald"; +/* Call screen text */ +"call_ended" = "Opkald afsluttet"; +/* Call screen text */ +"call_reaching" = "Rækker ud..."; + +/* File message text */ +"chat_file_cancelled" = "Annulleret"; +/* File message text */ +"chat_waiting" = "Venter..."; +/* File message text */ +"chat_paused" = "Sat på pause"; + +/* Deleting chat confirmation */ +"delete_chat_title" = "Slet denne chat og besked-historikken?"; +/* Deleting contat confirmation */ +"delete_contact_title" = "Slet denne kontakt?\nDin chat-historik vil gå tabt."; +/* Deleting contat request confirmation */ +"delete_contact_request_title" = "Slet denne kontakt-anmodning?"; +/* Deleting single message in chat */ +"delete_single_message" = "Slet besked"; +/* Deleting multiple messages in chat. */ +"delete_multiple_messages" = "Slet beskeder"; +/* Deleting all messages in chat. */ +"delete_all_messages" = "Slet alle"; +/* Delete button */ +"alert_delete" = "Slet"; +/* Delete button */ +"alert_cancel" = "Annuller"; + +/* Error while creating new profile */ +"login_enter_username_and_profile" = "Indtast venligst både brugernavn og profil-navn."; +/* Error while creating new profile */ +"login_profile_already_exists" = "En profil med det angivne navn eksisterer allerede"; + +/* General error title */ +"error_title" = "Fejl"; +/* General error button */ +"error_ok_button" = "OK"; +/* General error button */ +"error_retry_button" = "Prøv igen"; +/* Error */ +"error_contact_not_connected" = "Kontakten er ikke online"; +/* Error */ +"error_too_many_files" = "For mange aktive fil-overførsler"; +/* Error */ +"error_internal_message" = "Intern fejl"; +/* Error */ +"error_wrong_password_title" = "Forkert adgangskode"; +/* Error */ +"error_wrong_password_message" = "Adgangskode indeholder forkerte symboler."; +/* Error */ +"error_import_not_exist_title" = "Tox-arkivfil kan ikke importeres"; +/* Error */ +"error_import_not_exist_message" = "Filen eksisterer ikke."; +/* Error */ +"error_decrypt_title" = "Kan ikke dekryptere Tox-arkivfilen"; +/* Error */ +"error_decrypt_empty_data_message" = "Nogle indtastnings-data var tomme."; +/* Error */ +"error_decrypt_bad_format_message" = "Filen er i et dårligt format, eller beskadiget."; +/* Error */ +"error_decrypt_wrong_password_message" = "Adgangskoden er forkert eller filen er beskadiget."; +/* Error */ +"error_general_unknown_message" = "Der opstod en ukendt fejl."; +/* Error */ +"error_general_no_memory_message" = "Ikke nok hukommelse."; +/* Error */ +"error_general_bind_port_message" = "Kunne ikke binde til en port."; +/* Error */ +"error_general_profile_encrypted_message" = "Profilen er krypteret."; +/* Error */ +"error_general_bad_format_message" = "Filen er i et dårligt format, eller beskadiget."; +/* Error */ +"error_proxy_title" = "Proxy-fejl"; +/* Error */ +"error_proxy_invalid_address_message" = "Proxy-adressen har et ugyldigt format."; +/* Error */ +"error_proxy_invalid_port_message" = "Proxy-porten er ugyldig."; +/* Error */ +"error_proxy_host_not_resolved_message" = "Proxy-værten kunne ikke nås."; + +/* Error */ +"error_name_too_long" = "Navnet er for langt."; +/* Error */ +"error_status_message_too_long" = "Status-beskeden er for lang"; + +/* Error */ +"error_contact_request_too_long" = "Beskeden er for lang"; +/* Error */ +"error_contact_request_no_message" = "Ingen besked specificeret"; +/* Error */ +"error_contact_request_own_key" = "Kan ikke føje mig selv til kontakt-listen"; +/* Error */ +"error_contact_request_already_sent" = "Kontakt-anmodningen var allerede sendt"; +/* Error */ +"error_contact_request_bad_checksum" = "Forkert checksum, tjek venligst indtastet Tox-ID"; +/* Error */ +"error_contact_request_new_nospam" = "Dårlig nospam-værdi, tjek venligst indtasted Tox-ID"; + +/* Call error */ +"call_error_already_in_call" = "Allerede i et opkald"; +/* Call error */ +"call_error_contact_is_offline" = "Kontakten er offline"; +/* Call error */ +"call_error_no_active_call" = "Der er intet aktivt opkald"; + +/* Error while using color theme */ +"theme_error_cannot_open" = "Tema kan ikke åbnes, forkert format"; + +/* Tab chats badge ending */ +"accessibility_chats_ending" = "Ulæste samtaler"; +/* Avatar button label in settings */ +"accessibility_avatar_button_label" = "Avatar"; +/* Avatar button hint in settings */ +"accessibility_avatar_button_hint" = "Indstiller eller fjerner avatar."; +/* Chat button label in contact screen */ +"accessibility_chat_button_label" = "Chat"; +/* Chat button hint in contact screen */ +"accessibility_chat_button_hint" = "Åbner chat-samtale."; +/* Call button label in contact screen */ +"accessibility_call_button_label" = "Taleopkald"; +/* Call button hint in contact screen */ +"accessibility_call_button_hint" = "Foretager taleopkald."; +/* Video button label in contact screen */ +"accessibility_video_button_label" = "Videoopkald"; +/* Video button hint in contact screen */ +"accessibility_video_button_hint" = "Foretager videoopkald."; +/* Tap to copy hint */ +"accessibility_show_copy_hint" = "Viser kopier-menu."; +/* Tap to edit value hint */ +"accessibility_edit_value_hint" = "Redigerer værdi."; +/* Incoming message label */ +"accessibility_incoming_message_label" = "Besked"; +/* Outgoing message label */ +"accessibility_outgoing_message_label" = "Din besked"; \ No newline at end of file diff --git a/Antidote/da.lproj/import-profile.html b/Antidote/da.lproj/import-profile.html new file mode 100644 index 0000000..ca99079 --- /dev/null +++ b/Antidote/da.lproj/import-profile.html @@ -0,0 +1,9 @@ + +

For at importere din Tox-profil:

+ +
    +
  1. Send ".tox"-filen til din enhed ved brug af enhver app (Mail, Dropbox, etc.).
  2. +
  3. Brug "Åben i"-menuen til denne fil.
  4. +
  5. Vælg Antidote på en liste over tilgængelige apps.
  6. +
  7. Tjek navnet på din nye profil og tryk på OK.
  8. +
diff --git a/Antidote/de.lproj/AppStoreLocalizable.strings b/Antidote/de.lproj/AppStoreLocalizable.strings new file mode 100644 index 0000000000000000000000000000000000000000..6ab49860352310f53ba8ae348a25033c9cd1b2a9 GIT binary patch literal 7588 zcmeI0%Wl&^6oyBLRTqdyFkKd!(sC&RMOBn6D7}EF0I{ml#!0NEPLxY8yb*7d4eg5{ z;QPXHnKNh3e{OSr|5|ZNE^-Upk*l~K*Pa`?uIszlZSy{Kb=Pr; z`^Ni#R_sb{z=%G5scX^B=BD%}uECrkqZTIpRijk5z6NU?xO1L0cg$Ns(6=Nivdx6aCbtt$U}%oh(W*M?5yzH_fJR^uYLI5Cf1xf-5f(twEbjd76S&l9p?qX5NpuMP*GOW88M;bvShxQvZ^>nrx-_N)CGorh zH80CW#!9F5SuN8lwf~mO{)~L}6+=n77c+a+Ekd)*z36u6?VFsW2S+yIoc=cja^RXb z!z|VV4 z#q2uR)j;kH@0k|1ms8t&5n!jNu1rZ;%zIjjc5^?#Kr_R7SqYjEpg?uePXY;Aeg;~l+P*UAN`AOte=(nO2t9L+IO^+}ZE%j!?1KsRssX4P(6D!m9SluFBpp>C zHBxrtHAX&6XHa?gJ)XY$s`=fCulLq7pArkb;p3}4XI7#*v;3TVLdX52r3!4vq*ES0 z{81i1m{U!8iFeDYv#QDJr21%1J>Gh-mrcVex{6Svi9gS@*~dYzt2aeAo%W>rs+J4w zy4B48cXaby>|f(zHoBF^_b#&gHrvbhZo)`au{^|QkKW3ZQz#OTz$5-gG|u-P!^o8B zX3L`T$aWmzTjgC8ujFSht>q(E!#ub&QT|uC%zWY;Mx`(#QM^elN50+ja$p(U3>;v@N9K8O0vty(n1g-vsR zW_sq#nbW?%wbhW*5zFaHnWoA$)KUv=RHzkpPn2oKy~Op13UUe9LMhoY-p3_=o5#Hg3Y&YgR?ht8?C*((Va|eC9d0l9gN@sVf4t7z74P*A)_Sx5|DP!5 F{s1qHwG{vW literal 0 HcmV?d00001 diff --git a/Antidote/de.lproj/Localizable.strings b/Antidote/de.lproj/Localizable.strings new file mode 100644 index 0000000..4fa95eb --- /dev/null +++ b/Antidote/de.lproj/Localizable.strings @@ -0,0 +1,411 @@ +/* + Localizable.strings + Antidote + + Created by Dmytro Vorobiov on 08/10/15. + Copyright © 2015 dvor. All rights reserved. +*/ + + +/* Login screen text */ +"login_or_label" = "oder"; +/* Login screen text */ +"create_account" = "Konto erstellen"; +/* Login screen text */ +"import_profile" = "Profil importieren"; +/* Password field */ +"password" = "Passwort"; +/* Login button */ +"log_in" = "Anmelden"; +/* Login screen text */ +"create_profile" = "Profil erstellen"; +/* Login screen text */ +"import_to_antidote" = "Profil importieren"; +/* Login screen text */ +"create_account_username_title" = "Wie sollen dich Kontakte sehen?"; +/* Login screen text */ +"create_account_username_placeholder" = "Nutzername"; +/* Login screen text */ +"create_account_profile_title" = "Wie soll dieses Profil heißen?"; +/* Login screen text */ +"create_account_profile_placeholder" = "Profilname"; +/* Login screen text */ +"create_account_profile_hint" = "Bsp.: Zu Hause, iPhone"; +/* Login screen text */ +"set_password_title" = "Passwort setzen"; +/* Login screen text */ +"set_password_hint" = "Ein Passwort wird benötigt, um deine Daten zu schützen. Bewahre es gut auf – es kann nicht wiederhergestellt werden wenn es verloren gegangen ist."; +/* Login button */ +"create_account_next_button" = "Weiter"; +/* Login button */ +"create_account_go_button" = "Los"; +/* Default status message */ +"default_user_status_message" = "Toxing mit Antidote"; + +/* PIN screen text */ +"pin_enter_to_unlock" = "Gibt deine PIN ein zum entsprren"; +/* PIN screen text */ +"pin_set" = "PIN setzen"; +/* PIN screen text */ +"pin_confirm" = "PIN wiederholen"; +/* PIN screen error */ +"pin_do_not_match" = "PIN ist falsch. Probier es noch mal"; +/* PIN screen error */ +"pin_incorrect" = "falsche PIN"; +/* PIN screen error details */ +"pin_failed_attempts" = "Fehlversuche: %@"; +/* PIN screen message shown on log out */ +"pin_logout_message" = "Zu viele Fehlversuche. Du wurdest ausgeloggt."; +/* PIN screen screen */ +"pin_enabled" = "Aktiviere Pin"; +/* PIN screen screen */ +"pin_touch_id_enabled" = "Aktiviere Touch-ID"; +/* PIN screen screen */ +"pin_description" = "Verhindere unberechtigten Zugriff auf Antidote mittels einer PIN."; +/* PIN screen screen */ +"pin_touch_id_description" = "Benutze deinen Fingerabdruck als Alternative zur PIN."; +/* PIN screen screen */ +"pin_lock_timeout" = "Zeitsperre"; +/* PIN screen screen */ +"pin_lock_immediately" = "sofort"; +/* PIN screen screen */ +"pin_lock_30_seconds" = "30 Sekunden"; +/* PIN screen screen */ +"pin_lock_1_minute" = "1 Minute"; +/* PIN screen screen */ +"pin_lock_2_minutes" = "2 Minuten"; +/* PIN screen screen */ +"pin_lock_5_minutes" = "5 Minuten"; + +/* Label shown when connecting to Tox network */ +"connecting_label" = "Verbinde ..."; + +/* Tab name and screen name */ +"contacts_title" = "Kontakte"; +/* Tab name and screen name */ +"chats_title" = "Chats"; +/* Tab name and screen name */ +"settings_title" = "Einstellungen"; +/* Tab name and screen name */ +"profile_title" = "Profil"; + +/* No contacts placeholder text */ +"contact_no_contacts" = "Keine Kontakte"; +/* No contacts placeholder text */ +"contact_no_contacts_add_contact" = "Füge einen Kontakt hinzu\noder\n"; +/* No contacts placeholder text */ +"contact_no_contacts_share_tox_id" = "Teile deine Tox-ID"; +/* Contact request section title */ +"contact_requests_section" = "Kontaktanfragen"; +/* Contact last seen status */ +"contact_last_seen" = "Zuletzt online: %@"; +/* Screen name */ +"contact_request" = "Kontaktanfrage"; +/* Contact request button */ +"contact_request_decline" = "Ablehnen"; +/* Contact request button */ +"contact_request_accept" = "Akzeptieren"; +/* Contact request confirmation */ +"contact_request_delete_title" = "Kontaktanfrage löschen?"; +/* Text shown when contact was deleted */ +"contact_deleted" = "Gelöschter Kontakt"; + +/* Share Tox ID text */ +"show_qr_code" = "Zeige QR-Code"; +/* Share Tox ID text */ +"copy" = "Kopieren"; + +/* Add contat screen name */ +"add_contact_title" = "Kontakt hinzufügen"; +/* Add contat button */ +"add_contact_send" = "Hinzufügen"; +/* Add contat placeholder text */ +"add_contact_tox_id_placeholder" = "Tox-ID eingeben"; +/* Add contat placeholder text */ +"add_contact_or_label" = "oder"; +/* Add contat button */ +"add_contact_use_qr" = "Scanne QR-Code"; +/* Add contat placeholder text */ +"add_contact_default_message_title" = "Nachricht"; +/* Add contat default text sended to contact */ +"add_contact_default_message_text" = "Hallo! Würdest du mich bitte zu deiner Kontaktliste hinzufügen?"; +/* Add contat error */ +"add_contact_wrong_qr" = "Falscher QR-Code. Es sollte eine Tox-ID enthalten sein"; + +/* User name text */ +"name" = "Name"; +/* User nickname text */ +"nickname" = "Spitzname"; +/* User status message text */ +"status_message" = "Status Nachricht"; +/* User status text */ +"status_title" = "Status"; +/* User Tox ID text */ +"my_tox_id" = "Meine Tox-ID"; +/* User public key text */ +"public_key" = "Öffentlicher Schlüssel"; +/* Share Tox ID text */ +"show_qr" = "Zeige QR-Code"; +/* Profile menu item / screen name */ +"profile_details" = "Profil Details"; +/* Profile button */ +"logout_button" = "Abmelden"; + +/* QR code screen button */ +"qr_close_button" = "Schließen"; + +/* Chat screen placeholder */ +"chat_no_chats" = "Keine Chats"; +/* Chats screen message text */ +"chat_outgoing_file" = "Ausgehende Datei:"; +/* Chats screen message text */ +"chat_incoming_file" = "Eingehende Datei:"; +/* Chats screen message text */ +"chat_call_finished" = "Anruf beendet"; +/* Chats screen message text */ +"chat_unanwered_call" = "Unbeantworteter Anruf"; +/* Chat button */ +"chat_send_button" = "Senden"; +/* Chat notification toast */ +"chat_new_messages" = "↓ Neue Nachrichten"; +/* Chat call information */ +"chat_call_message" = "Anruf, "; +/* Chat call information */ +"chat_missed_call_message" = "Verpasster Anruf"; +/* Item present in the menu on long press on message */ +"chat_more_menu_item" = "Mehr"; + +/* Status message */ +"status_offline" = "Offline"; +/* Status message */ +"status_online" = "Online"; +/* Status message */ +"status_away" = "Abwesend"; +/* Status message */ +"status_busy" = "Beschäftigt"; + +/* Notification text */ +"notification_new_message" = "Neue Nachricht"; +/* Notification text */ +"notification_incoming_contact_request" = "Eingehende Kontaktanfrage"; +/* Notification text */ +"notification_is_calling" = "ruft an"; +/* Notification text */ +"notification_incoming_file" = "Eingehende Datei"; + +/* Settings menu / screen name */ +"settings_about" = "Über Antidote"; +/* Settings menu / screen name */ +"settings_faq" = "FAQ"; +/* Settings menu / screen name */ +"settings_advanced_settings" = "Erweiterte Einstellungen"; +/* About screen menu */ +"settings_antidote_version" = "Antidote Version"; +/* About screen menu */ +"settings_antidote_build" = "Antidote-Build"; +/* About screen menu */ +"settings_toxcore_version" = "Toxcore-Version"; +/* About screen menu */ +"settings_acknowledgements" = "Danksagungen"; +/* Settings screen menu */ +"settings_autodownload_images" = "Dateien automatisch herunterladen"; +/* Settings screen menu */ +"settings_autodownload_images_description" = "Eingehende Dateien automatisch herunterladen."; +/* Settings screen menu */ +"settings_notifications_message_preview" = "Mitteilungsvorschau"; +/* Settings screen menu */ +"settings_notifications_description" = "Wenn die App im Hintergrund ist, wirst du noch für bis zu 10 Minuten Benachrichtigungen erhalten."; +/* Settings screen menu */ +"settings_udp_enabled" = "Aktiviere UDP"; +/* Settings screen menu */ +"settings_restore_default" = "Standardeinstellungen wiederherstellen"; +/* Settings screen autodownload images option */ +"settings_never" = "Nie"; +/* Settings screen autodownload images option */ +"settings_wifi" = "WLAN"; +/* Settings screen autodownload images option */ +"settings_using_wifi" = "Nur im WLAN"; +/* Settings screen autodownload images option */ +"settings_always" = "Immer"; + +/* Profile settings menu */ +"change_password" = "Passwort ändern"; +/* Profile settings menu */ +"delete_password" = "Passwort löschen"; +/* Profile settings menu */ +"old_password" = "Altes Passwort"; +/* Change password text */ +"new_password" = "Neues Passwort"; +/* Change password text */ +"repeat_password" = "Passwort wiederholen"; +/* Change password button */ +"change_password_done" = "Fertig"; +/* Change password error */ +"password_is_empty_error" = "Passwort darf nicht leer sein"; +/* Change password error */ +"wrong_old_password" = "Falsches passwort"; +/* Change password error */ +"passwords_do_not_match" = "Passwörter stimmen nicht überein"; + +/* Source of photo to take */ +"photo_from_camera" = "Kamera"; +/* Source of photo to take */ +"photo_from_photo_library" = "Fotogalerie"; +/* Error while converting avatar image */ +"change_avatar_error_convert_image" = "Kann Bild nicht konvertieren"; + +/* Alert text when sending file to contacts */ +"file_send_to_contact" = "Zu einem Kontakt senden"; + +/* Profile menu item */ +"export_profile" = "Profil exportieren"; +/* Profile menu item */ +"delete_profile" = "Profil löschen"; +/* Delete profile confirmation */ +"delete_profile_confirmation_title_1" = "Dieses Profil löschen?"; +/* Delete profile confirmation */ +"delete_profile_confirmation_title_2" = "Bist du sicher?"; +/* Delete profile confirmation */ +"delete_profile_confirmation_message" = "Diese Operation kann nicht rückgängig gemacht werden"; + +/* Call screen text */ +"call_incoming" = "Eingehender Anruf"; +/* Call screen text */ +"call_ended" = "Anruf beendet"; +/* Call screen text */ +"call_reaching" = "Anrufen ..."; + +/* File message text */ +"chat_file_cancelled" = "Abgebrochen"; +/* File message text */ +"chat_waiting" = "Warten ..."; +/* File message text */ +"chat_paused" = "Pausiert"; + +/* Deleting chat confirmation */ +"delete_chat_title" = "Diesen Chat und den Chatverlauf löschen?"; +/* Deleting contat confirmation */ +"delete_contact_title" = "Diesen Kontakt löschen?\nDer Chatverlauf wird ebenfalls gelöscht."; +/* Deleting contat request confirmation */ +"delete_contact_request_title" = "Diese Kontaktanfrage löschen?"; +/* Deleting single message in chat */ +"delete_single_message" = "Nachricht löschen"; +/* Deleting multiple messages in chat. */ +"delete_multiple_messages" = "Nachrichten löschen"; +/* Deleting all messages in chat. */ +"delete_all_messages" = "Alles löschen"; +/* Delete button */ +"alert_delete" = "Löschen"; +/* Delete button */ +"alert_cancel" = "Abbrechen"; + +/* Error while creating new profile */ +"login_enter_username_and_profile" = "Bitte gib einen Usernamen und einen Profilnamen ein."; +/* Error while creating new profile */ +"login_profile_already_exists" = "Ein Profil mit diesem Namen existiert bereits"; + +/* General error title */ +"error_title" = "Fehler"; +/* General error button */ +"error_ok_button" = "OK"; +/* General error button */ +"error_retry_button" = "Erneut versuchen"; +/* Error */ +"error_contact_not_connected" = "Kontakt ist nicht online"; +/* Error */ +"error_too_many_files" = "Zu viele aktive Dateiübertragungen"; +/* Error */ +"error_internal_message" = "Interner Fehler"; +/* Error */ +"error_wrong_password_title" = "Falsches Passwort"; +/* Error */ +"error_wrong_password_message" = "Passwort enthält ungültige Zeichen."; +/* Error */ +"error_import_not_exist_title" = "Kann Tox-Profil-Datei nicht importieren"; +/* Error */ +"error_import_not_exist_message" = "Datei existiert nicht."; +/* Error */ +"error_decrypt_title" = "Kann Tox-Profil-Datei nicht entschlüsseln"; +/* Error */ +"error_decrypt_empty_data_message" = "Manche Eingabedaten waren leer."; +/* Error */ +"error_decrypt_bad_format_message" = "Datei hat falsches Format oder ist beschädigt."; +/* Error */ +"error_decrypt_wrong_password_message" = "Passwort ist falsch oder Datei ist beschädigt."; +/* Error */ +"error_general_unknown_message" = "Unbekannter Fehler."; +/* Error */ +"error_general_no_memory_message" = "Nicht genügend Arbeitsspeicher."; +/* Error */ +"error_general_bind_port_message" = "Konnte nicht an Port binden."; +/* Error */ +"error_general_profile_encrypted_message" = "Profil ist verschlüsselt."; +/* Error */ +"error_general_bad_format_message" = "Datei hat falsches Format oder ist beschädigt."; +/* Error */ +"error_proxy_title" = "Proxy Fehler"; +/* Error */ +"error_proxy_invalid_address_message" = "Proxy-Adresse hat ein falsches Format."; +/* Error */ +"error_proxy_invalid_port_message" = "Proxy-Port ist ungültig."; +/* Error */ +"error_proxy_host_not_resolved_message" = "Proxy-Host konnte nicht aufgelöst werden."; + +/* Error */ +"error_name_too_long" = "Name ist zu lang."; +/* Error */ +"error_status_message_too_long" = "Status Nachricht ist zu lang"; + +/* Error */ +"error_contact_request_too_long" = "Nachricht ist zu lang"; +/* Error */ +"error_contact_request_no_message" = "Keine Nachricht angegeben"; +/* Error */ +"error_contact_request_own_key" = "Man kann sich nicht selbst zur Kontaktliste hinzufügen"; +/* Error */ +"error_contact_request_already_sent" = "Kontaktanfrage wurde bereits verschickt"; +/* Error */ +"error_contact_request_bad_checksum" = "Falsche Prüfsumme, bitte eingegebene Tox-ID überprüfen"; +/* Error */ +"error_contact_request_new_nospam" = "Falscher No-Spam-Wert, bitte eingegebene Tox-ID überprüfen"; + +/* Call error */ +"call_error_already_in_call" = "Bereits im Gespräch"; +/* Call error */ +"call_error_contact_is_offline" = "Kontakt ist offline"; +/* Call error */ +"call_error_no_active_call" = "Es gibt keinen aktiven Anruf"; + +/* Error while using color theme */ +"theme_error_cannot_open" = "Kann Farbschema nicht öffnen, falsches Format"; + +/* Tab chats badge ending */ +"accessibility_chats_ending" = "ungelesene Chats"; +/* Avatar button label in settings */ +"accessibility_avatar_button_label" = "Avatar"; +/* Avatar button hint in settings */ +"accessibility_avatar_button_hint" = "Avatar hinzufügen oder löschen."; +/* Chat button label in contact screen */ +"accessibility_chat_button_label" = "Chat"; +/* Chat button hint in contact screen */ +"accessibility_chat_button_hint" = "Öffnet Chat."; +/* Call button label in contact screen */ +"accessibility_call_button_label" = "Sprachanruf"; +/* Call button hint in contact screen */ +"accessibility_call_button_hint" = "Startet Sprachanruf."; +/* Video button label in contact screen */ +"accessibility_video_button_label" = "Videoanruf"; +/* Video button hint in contact screen */ +"accessibility_video_button_hint" = "Startet Videoanruf."; +/* Tap to copy hint */ +"accessibility_show_copy_hint" = "Zeigt Kopiermenü."; +/* Tap to edit value hint */ +"accessibility_edit_value_hint" = "Bearbeitet den Wert."; +/* Incoming message label */ +"accessibility_incoming_message_label" = "Nachricht"; +/* Outgoing message label */ +"accessibility_outgoing_message_label" = "Deine Nachricht"; +/* Message shown on chat list when contact is typing */ +"chat_is_typing_text" = "schreibt …"; +/* Text shown in chat when there are undelivered faux offline messages */ +"chat_pending_faux_offline_messages" = "Nicht zugestellte Nachrichten werden gesendet, wenn sowohl du als auch dein Freund online sind."; diff --git a/Antidote/de.lproj/import-profile.html b/Antidote/de.lproj/import-profile.html new file mode 100644 index 0000000..13d3441 --- /dev/null +++ b/Antidote/de.lproj/import-profile.html @@ -0,0 +1,9 @@ + +

Um dein Tox-Profil zu importieren:

+ +
    +
  1. Sende die „.tox“-Datei an dein Gerät mit einer beliebigen App (Mail, Dropbox, etc.).
  2. +
  3. Benutze das „Öffnen in“-Menü für diese Datei.
  4. +
  5. Wähle Antidote in der Liste der verfügbaren Apps.
  6. +
  7. Überprüfe den Namen von deinem Profil und klicke auf „OK“.
  8. +
diff --git a/Antidote/default-theme.yaml b/Antidote/default-theme.yaml new file mode 100644 index 0000000..41b7c47 --- /dev/null +++ b/Antidote/default-theme.yaml @@ -0,0 +1,86 @@ +version: 1 + +colors: + white: FFFFFF + transparent_white: FFFFFF55 + transparent_dark_gray: 413839DD + black: "000000" + gray: CCCCCC + lightgraypink: EFEFF4 + darkgray: AAAAAA + color_offline_status: "A3A3A3" + darkgray2: 8C8C8C + lightgrayblue: EDF3F5 + simpleblue: 2E76D3 + mediumblue: 00A7E9 + lightblue: 9CBDE9 + purple: 575CCF + green: 85B452 + green_bright: 00D116 + yellow: FFF300 + pushyellow: FFC533 + red: E94F42 + palered: C56258 + rust: B7410E + +values: + login-background: white + login-gradient: lightblue + login-tox-logo: simpleblue + login-button-text: white + login-button-background: simpleblue + login-description-label: white + login-form-background: white + login-form-text: black + login-link-color: white + + # Color used for fullscreen translucent views background, e.g. fullscreen picker + translucent-background: transparent_white + + # normal background color used all over application + normal-background: white + normal-text: black + link-text: simpleblue + connecting-background: simpleblue + connecting-text: white + separators-and-borders: gray + rounded-button-text: white + rounded-positive-button-background: simpleblue + rounded-negative-button-background: gray + offline-status: color_offline_status + online-status: green_bright + away-status: yellow + busy-status: palered + status-background: white + friend-cell-status: darkgray2 + chat-list-cell-message: darkgray + chat-list-cell-unread-background: lightgrayblue + chat-input-background: lightgrayblue + chat-incoming-bubble: lightgrayblue + chat-outgoing-bubble: purple + chat-outgoing-unread-bubble: rust + chat-outgoing-sentpush-bubble: pushyellow + chat-information-text: darkgray2 + tab-badge-background: palered + tab-badge-text: white + tab-item-active: simpleblue + tab-item-inactive: darkgray2 + notification-background: transparent_dark_gray + notification-text: white + settings-background: lightgraypink + call-text-color: white + call-decline-button-background: red + call-answer-button-background: green + call-control-background: simpleblue + call-control-selected-background: white + call-button-icon-color: white + call-button-selected-icon-color: simpleblue + call-video-preview-background: black + empty-screen-placeholder-text: darkgray + file-image-background-active: darkgray + file-image-cancelled-text: white + file-image-accept-button-tint: white + file-image-cancel-button-tint: black + lock-gradient-top: mediumblue + lock-gradient-bottom: purple + chat-list-cell-arrow-unread-background: red diff --git a/Antidote/dummy-photo.jpg b/Antidote/dummy-photo.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6c4915fe2a760dd2b0f007d7d368f30c0294e9f3 GIT binary patch literal 6266 zcma)9XH*kwx1JD62p|LkQUobVladfZ?}Ug#=pbFv!~{s_ML|#rQdNWq2uSZ1x`=c^ zsY(?oqM)cCO0yr78$IRwe%y1{-Rqq-@9e#wXP0-+tTnq&cNYOsi%7}|0620)8Gr!) zk=-=_h6yA3MFAjyouxJafZau~>dDa1Ks|MJT8J8+L?@8di1YyUNPM6=QVpRF7#K$e z;)#CbP-z0$mqIg?UBA~UD@`F8${s`G5V$~d@=1#2sbI3>DH|u^DL&Z~|uc9I% zBGe*KYV=@Vb)>GY?k^4v4ONzhYDg3<6d$Qd3z7Sq0YeTU22%nZG=wZP`GRs}= z7dTMQJeZ6Rr3X9F>HdFr(e5NYlpb=D9w=?@s3on4!xJgAUkat)2pmrD2rVQOPa~3# zU<_qh9BLE_Nl(j67pslH>gr-NEs#hHEmK`HZ7c$6&zgXsa%zl+wR{Ch6i|H}6lmh|tr==>{Iot2FGucQ61 zqyAgPnx9|We+HNJ@XzRzX{>n~;Y#2yhkX2ZLY$8w>=7fp&X=Yybd*e#<{!01z9Por9AL@~0XE`o{qL zX%PU}05Gc*2s@aQ>z5J42Ef2FNI@ZXQ+qr|(Ao4NSz zX=?Hws^=*9fH%$DSdj%Ed&ZsXPvILZ28c60;5CP+N7Pwc7L{Vp+_0xI(<3V0eH7gG zxvL_69pUbywGCmKXt8|lQz_`M64xf4`!oqy$T()KL zITHf`es<^$0Y~_-uvwmkyW{4b>}v?>8MzZr$3>1qik3GL%d*%FS`yu&r7xThHM=gP zWKwF^C7UOmnTBjt=BTFBY8QXf&6N~P_vSgQXj8lqN0PmushTYO2~uvDJC~n zEJ-4!2q$O#=R^tz8D^R-7Cg#uu^=>$8bsp-BMaDC0;|Er?92xfc`NP6CN9SyTufl= zh2vm~1yo+xNy)^nf`he?Hc#!%GKH}B zsMtjMsXx}$WCnM^xR=Pnk!He9iofEq!eXlZuwx|cWAI-c5UbYEF)Jbk zvJzAl!Fcy;=wPZi4@2xom`bC9cx7G|ZT}*4|HK9Z!y%Sf<^PmBy?}Ud_2#P ztNx-3qNaNJBmX<<$q88(v;|k&gNWHV+Gp)~=m?MZ9_~_147VI| z^f*%H9AII3#Pc$v!asgwq7~I){dgu%I~Iq7?QKA8alQ?g?oXPLc@=npAmoUVI;724 zyB0>Ew0i(oBBb(vu=VF>)!>XWJ{^Oo^d{xs*|~l*wcJoSk6}4!s~oae3<)^ z4R`(N{e_2f`#RS?M#Uaq{NVB=xLRa-nnK}ur1vpveC&CLPUv)g$3oC*^wy$`=LTWCog{+=6KQ8&L_I{G4Jzd9O3D4cvE2fILV*R0MFb0r#|j(V|^ zO8qguZ9&=vhy&)6yuy^5s$sz{XFkguy>irp`@*x15#I|bN4Xv3#xiDCXSQ zvQOjtf=l*p*cHqly6QG!8^iX0%+=T_S7;Qe9IVwkZw-;!;QAyQm=d+3Pmy(C{8`#dr)e#e6`C!>3Y`uXKI#x5`rJzZH!S;d~^IquSY?|4&AwxR7ydZ_lp)|lH93D?UM>y(Gx-i6x{ z^O8Qcg3FcBQ2 zD*ZHp$11`oQ-w92PpO)nNQR6A9kr4&gU1W3g(*SW6TL;lT@6qIYx&0?#ZDUxI27MB z!q-qgK-h98uL~SNdMF(=@Y)4#N7yc1x^{OVN0MJ-db~0zPPfuBvzwIuRuJ#+xqR3wc%SWdmcFa%m*RIYXD|lq|<)R*6tZR#q%-aQq zyzPsutZRk@nuwlgDpUDbgp!TlQssybQ8xwKKdq+oh&KJ?q~>+6F-MDutr)fZb2m0d zOSSk`tvw%vx5pT3I)}k2FB&ZmWYGuN1 !7H-zO@qAF$`2pQjroZD1X*O6m9#Qge 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 literal 0 HcmV?d00001 diff --git a/Antidote/el.lproj/Localizable.strings b/Antidote/el.lproj/Localizable.strings new file mode 100644 index 0000000..d32a220 --- /dev/null +++ b/Antidote/el.lproj/Localizable.strings @@ -0,0 +1,404 @@ + + +/* Notification text */ +"notification_incoming_contact_request" = "Εισερχόμενο αίτημα επικοινωνίας"; +/* Notification text */ +"notification_is_calling" = "καλεί"; +/* Settings menu / screen name */ +"settings_faq" = "Συχνές ερωτήσεις"; +/* Settings menu / screen name */ +"settings_advanced_settings" = "Ρυθμίσεις για προχωρημένους"; +/* About screen menu */ +"settings_antidote_version" = "Έκδοση Antidote"; +/* About screen menu */ +"settings_toxcore_version" = "Έκδοση Toxcore"; +/* About screen menu */ +"settings_acknowledgements" = "Ευχαριστίες"; +/* Settings screen menu */ +"settings_autodownload_images_description" = "Αυτόματη λήψη εισερχομένων αρχείων."; +/* Settings screen menu */ +"settings_notifications_description" = "Όταν η εφαρμογή πηγαίνει στο παρασκήνιο, θα εξακολουθείτε να λαμβάνετε ειδοποιήσεις για έως και 10 λεπτά."; +/* Settings screen autodownload images option */ +"settings_never" = "Ποτέ"; +/* Settings screen autodownload images option */ +"settings_always" = "Πάντα"; +/* Call screen text */ +"call_ended" = "Η κλήση τερματίστηκε"; +/* Settings screen menu */ +"settings_autodownload_images" = "Αυτόματη λήψη αρχείων"; +/* Error */ +"error_wrong_password_message" = "Ο κωδικός πρόσβασης περιέχει λάθος σύμβολα."; +/* Settings screen menu */ +"settings_notifications_message_preview" = "Προεπισκόπηση ειδοποιήσεων"; +/* Settings screen autodownload images option */ +"settings_wifi" = "Wi-Fi"; +/* Change password text */ +"repeat_password" = "Επαναλάβετε τον κωδικό πρόσβασης"; +/* Settings screen autodownload images option */ +"settings_using_wifi" = "Μόνο μέσω Wi-Fi"; + +/* Profile settings menu */ +"change_password" = "Αλλαγή κωδικού πρόσβασης"; +/* Profile settings menu */ +"delete_password" = "Διαγραφή κωδικού πρόσβασης"; +/* Change password text */ +"new_password" = "Νέος κωδικός πρόσβασης"; +/* Change password error */ +"password_is_empty_error" = "Ο κωδικός πρόσβασης δεν πρέπει να είναι κενός"; +/* Change password error */ +"wrong_old_password" = "Λάθος κωδικός"; +/* Change password error */ +"passwords_do_not_match" = "Οι κωδικοί πρόσβασης δεν ταιριάζουν"; + +/* Source of photo to take */ +"photo_from_camera" = "Κάμερα"; +/* Profile settings menu */ +"old_password" = "Παλιός κωδικός πρόσβασης"; +/* Change password button */ +"change_password_done" = "Ολοκλήρωση"; + +/* Alert text when sending file to contacts */ +"file_send_to_contact" = "Αποστολή σε επαφή"; +/* Delete profile confirmation */ +"delete_profile_confirmation_title_1" = "Να γίνει διαγραφή αυτού του προφίλ;"; + +/* Call screen text */ +"call_incoming" = "Εισερχόμενη κλήση"; +/* Delete profile confirmation */ +"delete_profile_confirmation_message" = "Αυτή η λειτουργία δεν μπορεί να αναιρεθεί"; + +/* File message text */ +"chat_file_cancelled" = "Ακυρώθηκε"; + +/* Deleting chat confirmation */ +"delete_chat_title" = "Να διαγραφεί αυτό το ιστορικό συνομιλιών και μηνυμάτων;"; +/* Error while creating new profile */ +"login_profile_already_exists" = "Το προφίλ με το συγκεκριμένο όνομα υπάρχει ήδη"; + +/* General error title */ +"error_title" = "Σφάλμα"; +/* General error button */ +"error_ok_button" = "Εντάξει"; +/* Error */ +"error_too_many_files" = "Πάρα πολλές ενεργές μεταφορές αρχείων"; +/* Error */ +"error_import_not_exist_message" = "Το αρχείο δεν υπάρχει."; +/* Error */ +"error_decrypt_bad_format_message" = "Το αρχείο έχει κακή μορφή ή είναι κατεστραμμένο."; +/* Error */ +"error_decrypt_wrong_password_message" = "Ο κωδικός πρόσβασης είναι λάθος ή το αρχείο είναι κατεστραμμένο."; + +/* Error */ +"error_name_too_long" = "Το όνομα είναι πολύ μεγάλο."; +/* Source of photo to take */ +"photo_from_photo_library" = "Βιβλιοθήκη φωτογραφιών"; +/* Error while converting avatar image */ +"change_avatar_error_convert_image" = "Δεν είναι δυνατή η μετατροπή της εικόνας"; + +/* Profile menu item */ +"export_profile" = "Εξαγωγή προφίλ"; +/* Profile menu item */ +"delete_profile" = "Διαγραφή προφίλ"; +/* Deleting single message in chat */ +"delete_single_message" = "Διαγραφή μηνύματος"; +/* Deleting multiple messages in chat. */ +"delete_multiple_messages" = "Διαγραφή μηνυμάτων"; +/* Delete button */ +"alert_cancel" = "Ακύρωση"; + +/* Error while creating new profile */ +"login_enter_username_and_profile" = "Εισαγάγετε όνομα χρήστη και όνομα προφίλ."; +/* General error button */ +"error_retry_button" = "Επανάληψη"; +/* Error */ +"error_contact_not_connected" = "Η επαφή δεν είναι συνδεδεμένη"; +/* Error */ +"error_internal_message" = "Εσωτερικό σφάλμα"; +/* Error */ +"error_wrong_password_title" = "Λάθος κωδικός"; +/* Error */ +"error_import_not_exist_title" = "Δεν είναι δυνατή η εισαγωγή αρχείου αποθήκευσης tox"; +/* Error */ +"error_status_message_too_long" = "Το μήνυμα κατάστασης είναι πολύ μεγάλο"; + +/* Error */ +"error_contact_request_too_long" = "Το μήνυμα είναι πολύ μεγάλο"; +/* Error */ +"error_contact_request_no_message" = "Δεν έχει καθοριστεί μήνυμα"; +/* Error */ +"error_contact_request_bad_checksum" = "Εσφαλμένο άθροισμα ελέγχου, ελέγξτε το εισαγόμενο Tox ID"; +/* File message text */ +"chat_waiting" = "Αναμονή..."; +/* Deleting contat confirmation */ +"delete_contact_title" = "Διαγραφή αυτής της επαφής;\nΤο ιστορικό συνομιλιών σας θα χαθεί."; +/* Delete button */ +"alert_delete" = "Διαγραφή"; +/* Error */ +"error_decrypt_title" = "Δεν είναι δυνατή η αποκρυπτογράφηση του αρχείου αποθήκευσης tox"; +/* Error */ +"error_decrypt_empty_data_message" = "Ορισμένα δεδομένα εισόδου ήταν άδεια."; +/* Error */ +"error_contact_request_already_sent" = "Το αίτημα επικοινωνίας έχει ήδη σταλεί"; +/* Call error */ +"call_error_contact_is_offline" = "Η επαφή είναι εκτός σύνδεσης"; +/* Delete profile confirmation */ +"delete_profile_confirmation_title_2" = "Είστε σίγουροι;"; +/* Call screen text */ +"call_reaching" = "Καλεί..."; +/* File message text */ +"chat_paused" = "Σε παύση"; +/* Deleting contat request confirmation */ +"delete_contact_request_title" = "Διαγραφή αυτού του αιτήματος επικοινωνίας;"; +/* Deleting all messages in chat. */ +"delete_all_messages" = "Διαγραφή όλων"; +/* Error */ +"error_contact_request_own_key" = "Δεν μπορώ να προσθέσω τον εαυτό μου στη λίστα επαφών"; + +/* Tab chats badge ending */ +"accessibility_chats_ending" = "αδιάβαστες συζητήσεις"; +/* Chat button hint in contact screen */ +"accessibility_chat_button_hint" = "Ανοίγει το παράθυρο διαλόγου συνομιλίας."; +/* Call button hint in contact screen */ +"accessibility_call_button_hint" = "Πραγματοποιεί ηχητική κλήση."; +/* Error */ +"error_contact_request_new_nospam" = "Εσφαλμένη τιμή nospam, ελέγξτε το καταχωρισμένο Tox ID"; + +/* Call error */ +"call_error_already_in_call" = "Ήδη σε κλήση"; +/* Call error */ +"call_error_no_active_call" = "Δεν υπάρχει ενεργή κλήση"; + +/* Error while using color theme */ +"theme_error_cannot_open" = "Δεν είναι δυνατό το άνοιγμα του θέματος, λάθος μορφή"; +/* Avatar button label in settings */ +"accessibility_avatar_button_label" = "Εικόνα χρήστη"; +/* Avatar button hint in settings */ +"accessibility_avatar_button_hint" = "Ορίζει ή αφαιρεί την εικόνα χρήστη."; +/* Chat button label in contact screen */ +"accessibility_chat_button_label" = "Συζήτηση"; +/* Video button label in contact screen */ +"accessibility_video_button_label" = "Βιντεοκλήση"; +/* Video button hint in contact screen */ +"accessibility_video_button_hint" = "Πραγματοποιεί βιντεοκλήση."; +/* Call button label in contact screen */ +"accessibility_call_button_label" = "Ηχητική κλήση"; +/* Login screen text */ +"login_or_label" = "ή"; +/* Login screen text */ +"create_account" = "Δημιουργία λογαριασμού"; +/* Login screen text */ +"import_profile" = "Εισαγωγή προφίλ"; +/* Password field */ +"password" = "Κωδικός πρόσβασης"; +/* Login button */ +"log_in" = "Σύνδεση"; +/* Login screen text */ +"create_profile" = "Δημιουργία προφίλ"; +/* Login screen text */ +"import_to_antidote" = "Εισαγωγή στο Antidote"; +/* Login screen text */ +"create_account_username_title" = "Πώς θα σας βλέπουν οι επαφές;"; +/* Login screen text */ +"create_account_username_placeholder" = "Όνομα χρήστη"; +/* Login screen text */ +"create_account_profile_title" = "Πώς ονομάζεται αυτό το προφίλ;"; +/* Login screen text */ +"create_account_profile_hint" = "π.χ. Σπίτι, iPhone"; +/* Login button */ +"create_account_next_button" = "Επόμενο"; + +/* PIN screen text */ +"pin_enter_to_unlock" = "Εισαγάγετε το PIN σας για ξεκλείδωμα"; +/* PIN screen text */ +"pin_set" = "Ορισμός PIN"; +/* PIN screen text */ +"pin_confirm" = "Επιβεβαίωση PIN"; +/* PIN screen error */ +"pin_do_not_match" = "Τα PIN δεν ταιριάζουν. Προσπάθησε ξανά"; +/* PIN screen error */ +"pin_incorrect" = "Λανθασμένο PIN"; +/* PIN screen error details */ +"pin_failed_attempts" = "Αποτυχημένες προσπάθειες: %@"; +/* PIN screen screen */ +"pin_enabled" = "Ενεργοποίηση PIN"; +/* PIN screen screen */ +"pin_touch_id_enabled" = "Ενεργοποίηση Touch ID"; +/* PIN screen screen */ +"pin_description" = "Αποτρέψτε τη μη εξουσιοδοτημένη πρόσβαση στο Antidote με ένα PIN."; +/* PIN screen screen */ +"pin_lock_timeout" = "Λήξη χρονικού ορίου κλειδώματος"; +/* PIN screen screen */ +"pin_lock_immediately" = "Άμεσα"; +/* PIN screen screen */ +"pin_lock_30_seconds" = "30 δευτερόλεπτα"; +/* PIN screen screen */ +"pin_lock_1_minute" = "1 λεπτό"; +/* PIN screen screen */ +"pin_lock_2_minutes" = "2 λεπτά"; +/* PIN screen screen */ +"pin_lock_5_minutes" = "5 λεπτά"; + +/* Label shown when connecting to Tox network */ +"connecting_label" = "Γίνεται σύνδεση..."; + +/* Tab name and screen name */ +"contacts_title" = "Επαφές"; +/* Tab name and screen name */ +"chats_title" = "Συνομιλίες"; +/* Tab name and screen name */ +"settings_title" = "Ρυθμίσεις"; +/* Tab name and screen name */ +"profile_title" = "Προφίλ"; + +/* No contacts placeholder text */ +"contact_no_contacts" = "Δεν υπάρχουν επαφές"; +/* No contacts placeholder text */ +"contact_no_contacts_share_tox_id" = "μοιραστείτε το Tox ID σας"; +/* Contact request section title */ +"contact_requests_section" = "Αιτήματα Επικοινωνίας"; +/* Contact last seen status */ +"contact_last_seen" = "Εθεάθη τελευταία: %@"; +/* Screen name */ +"contact_request" = "Αίτημα επικοινωνίας"; +/* Contact request button */ +"contact_request_decline" = "Παρακμή"; +/* Contact request button */ +"contact_request_accept" = "Αποδοχή"; +/* Text shown when contact was deleted */ +"contact_deleted" = "Διαγραμμένη επαφή"; +/* Share Tox ID text */ +"copy" = "Αντιγραφή"; + +/* Add contat screen name */ +"add_contact_title" = "Προσθήκη επαφής"; +/* Login button */ +"create_account_go_button" = "Είσοδος"; +/* Default status message */ +"default_user_status_message" = "Toxing στο Antidote"; +/* Add contat placeholder text */ +"add_contact_default_message_title" = "Μήνυμα"; +/* Add contat error */ +"add_contact_wrong_qr" = "Λάθος κωδικός QR. Θα πρέπει να περιέχει Tox ID"; + +/* User name text */ +"name" = "Όνομα"; +/* About screen menu */ +"settings_antidote_build" = "Έκδοση Antidote"; +/* Settings screen menu */ +"settings_udp_enabled" = "Ενεργοποίηση UDP"; +/* Settings screen menu */ +"settings_restore_default" = "Επαναφορά αρχικών ρυθμίσεων"; +/* Error */ +"error_general_unknown_message" = "Παρουσιάστηκε άγνωστο σφάλμα."; +/* Error */ +"error_general_no_memory_message" = "Ανεπαρκής μνήμη."; +/* Error */ +"error_general_bind_port_message" = "Δεν ήταν δυνατή η δέσμευση σε μια θύρα."; +/* Error */ +"error_general_profile_encrypted_message" = "Το προφίλ είναι κρυπτογραφημένο."; +/* Error */ +"error_general_bad_format_message" = "Το αρχείο έχει κακή μορφή ή είναι κατεστραμμένο."; +/* Error */ +"error_proxy_title" = "Σφάλμα διακομιστή μεσολάβησης"; +/* Error */ +"error_proxy_invalid_address_message" = "Η διεύθυνση διακομιστή μεσολάβησης έχει μη έγκυρη μορφή."; +/* Error */ +"error_proxy_invalid_port_message" = "Η θύρα διακομιστή μεσολάβησης δεν είναι έγκυρη."; +/* Error */ +"error_proxy_host_not_resolved_message" = "Δεν ήταν δυνατή η επίλυση του διακομιστή μεσολάβησης."; +/* Login screen text */ +"set_password_title" = "Ορίστε τον κωδικό πρόσβασης"; +/* Tap to copy hint */ +"accessibility_show_copy_hint" = "Εμφανίζει το μενού αντιγραφής."; +/* Tap to edit value hint */ +"accessibility_edit_value_hint" = "Επεξεργάζεται την τιμή."; +/* Incoming message label */ +"accessibility_incoming_message_label" = "Μήνυμα"; +/* Outgoing message label */ +"accessibility_outgoing_message_label" = "Το μήνυμά σας"; +/* Login screen text */ +"create_account_profile_placeholder" = "Όνομα προφίλ"; +/* Login screen text */ +"set_password_hint" = "Απαιτείται κωδικός πρόσβασης για την προστασία των δεδομένων σας. Διατηρήστε το ασφαλές - μόλις χαθεί δεν μπορεί να αποκατασταθεί ο λογαριασμός σας."; +/* PIN screen message shown on log out */ +"pin_logout_message" = "Πάρα πολλές αποτυχημένες προσπάθειες. Έχετε αποσυνδεθεί."; +/* PIN screen screen */ +"pin_touch_id_description" = "Χρησιμοποιήστε το δακτυλικό σας αποτύπωμα ως εναλλακτική για την εισαγωγή ενός PIN."; +/* No contacts placeholder text */ +"contact_no_contacts_add_contact" = "Πρόσθεσε μια επαφή\nή\n"; +/* Contact request confirmation */ +"contact_request_delete_title" = "Διαγραφή αιτήματος επικοινωνίας;"; + +/* Share Tox ID text */ +"show_qr_code" = "Εμφάνιση κωδικού QR"; +/* Add contat placeholder text */ +"add_contact_tox_id_placeholder" = "Εισαγάγετε Tox ID"; +/* Add contat button */ +"add_contact_send" = "Αποστολή"; +/* Add contat placeholder text */ +"add_contact_or_label" = "ή"; +/* Add contat button */ +"add_contact_use_qr" = "Χρήση κωδικού QR"; +/* Status message */ +"status_away" = "Απών"; +/* Add contat default text sended to contact */ +"add_contact_default_message_text" = "Γειά σας! Θα μπορούσατε παρακαλώ να με προσθέσετε στη λίστα επαφών σας;"; +/* Share Tox ID text */ +"show_qr" = "Εμφάνιση QR"; +/* Chat notification toast */ +"chat_new_messages" = "↓ Νέα μηνύματα"; +/* User nickname text */ +"nickname" = "Ψευδώνυμο"; +/* User status message text */ +"status_message" = "Μήνυμα κατάστασης"; +/* User status text */ +"status_title" = "Κατάσταση"; +/* User public key text */ +"public_key" = "Δημόσιο Κλειδί"; +/* User Tox ID text */ +"my_tox_id" = "Το Tox ID μου"; + +/* QR code screen button */ +"qr_close_button" = "Κλείσιμο"; + +/* Chat screen placeholder */ +"chat_no_chats" = "Δεν υπάρχουν συνομιλίες"; +/* Text shown in chat when there are undelivered faux offline messages */ +"chat_pending_faux_offline_messages" = "Τα μηνύματα που δεν έχουν παραδοθεί θα σταλούν όταν τόσο εσείς όσο και ο φίλος σας είστε συνδεδεμένοι."; +/* Profile menu item / screen name */ +"profile_details" = "Λεπτομέρειες Προφίλ"; +/* Item present in the menu on long press on message */ +"chat_more_menu_item" = "Περισσότερα"; +/* Profile button */ +"logout_button" = "Αποσύνδεση"; +/* Chats screen message text */ +"chat_outgoing_file" = "Εξερχόμενο αρχείο:"; +/* Chats screen message text */ +"chat_incoming_file" = "Εισερχόμενο αρχείο:"; +/* Chats screen message text */ +"chat_call_finished" = "Η κλήση ολοκληρώθηκε"; +/* Chats screen message text */ +"chat_unanwered_call" = "Αναπάντητη κλήση"; +/* Chat button */ +"chat_send_button" = "Αποστολή"; +/* Chat call information */ +"chat_call_message" = "Κλήση, "; +/* Chat call information */ +"chat_missed_call_message" = "Αναπάντητη κλήση"; +/* Message shown on chat list when contact is typing */ +"chat_is_typing_text" = "πληκτρολογεί..."; + +/* Status message */ +"status_offline" = "Εκτός σύνδεσης"; +/* Notification text */ +"notification_incoming_file" = "Εισερχόμενο αρχείο"; + +/* Notification text */ +"notification_new_message" = "Νέο μήνυμα"; + +/* Settings menu / screen name */ +"settings_about" = "Σχετικά με"; +/* Status message */ +"status_online" = "Συνδεμένος/η"; +/* Status message */ +"status_busy" = "Απασχολημένος/η"; diff --git a/Antidote/en.lproj/AppStoreLocalizable.strings b/Antidote/en.lproj/AppStoreLocalizable.strings new file mode 100644 index 0000000..d6fbb04 --- /dev/null +++ b/Antidote/en.lproj/AppStoreLocalizable.strings @@ -0,0 +1,54 @@ +/* + AppStoreLocalizable.strings + Antidote + + Created by Dmytro Vorobiov on 08/02/17. + Copyright © 2017 dvor. All rights reserved. +*/ + +/* Name of friend for the App Store screenshot. Should be fully random, no real people here. Can be generated with service like http://www.fakenamegenerator.com/ */ +"app_store_screenshot_friend_female_1" = "Mary Cokley"; +/* Name of friend for the App Store screenshot. Should be fully random, no real people here. Can be generated with service like http://www.fakenamegenerator.com/ */ +"app_store_screenshot_friend_female_2" = "Shirley Knox"; +/* Name of friend for the App Store screenshot. Should be fully random, no real people here. Can be generated with service like http://www.fakenamegenerator.com/ */ +"app_store_screenshot_friend_female_3" = "Jennifer Smith"; +/* Name of friend for the App Store screenshot. Should be fully random, no real people here. Can be generated with service like http://www.fakenamegenerator.com/ */ +"app_store_screenshot_friend_female_4" = "Marina Dixon"; +/* Name of friend for the App Store screenshot. Should be fully random, no real people here. Can be generated with service like http://www.fakenamegenerator.com/ */ +"app_store_screenshot_friend_female_5" = "Carol Ortega"; +/* Name of friend for the App Store screenshot. Should be fully random, no real people here. Can be generated with service like http://www.fakenamegenerator.com/ */ +"app_store_screenshot_friend_male_1" = "Michael Sharpe"; +/* Name of friend for the App Store screenshot. Should be fully random, no real people here. Can be generated with service like http://www.fakenamegenerator.com/ */ +"app_store_screenshot_friend_male_2" = "Charles Donahue"; +/* Name of friend for the App Store screenshot. Should be fully random, no real people here. Can be generated with service like http://www.fakenamegenerator.com/ */ +"app_store_screenshot_friend_male_3" = "Lee Murdock"; +/* Name of friend for the App Store screenshot. Should be fully random, no real people here. Can be generated with service like http://www.fakenamegenerator.com/ */ +"app_store_screenshot_friend_male_4" = "Wayne Henderson"; +/* Name of friend for the App Store screenshot. Should be fully random, no real people here. Can be generated with service like http://www.fakenamegenerator.com/ */ +"app_store_screenshot_friend_male_5" = "Robert Newton"; + +/* Demo conversation for the App Store screenshot */ +"app_store_screenshot_conversation_1" = "Is Antidote really that secure?"; +/* Demo conversation for the App Store screenshot */ +"app_store_screenshot_conversation_2" = "sure, it is peer-to-peer"; +/* Demo conversation for the App Store screenshot */ +"app_store_screenshot_conversation_3" = "And what does that mean? Peer-to-peer? 😄"; +/* Demo conversation for the App Store screenshot */ +"app_store_screenshot_conversation_4" = "you text me directly, the are no servers or things like that"; +/* Demo conversation for the App Store screenshot */ +"app_store_screenshot_conversation_5" = "+ it's encrypted 🔐😎"; +/* Demo conversation for the App Store screenshot */ +"app_store_screenshot_conversation_6" = "Cool!"; +/* Demo conversation for the App Store screenshot */ +"app_store_screenshot_conversation_7" = "I'll give it a go then"; + +/* Demo chat message for the App Store screenshot */ +"app_store_screenshot_chat_message_1" = "😂😂😂"; +/* Demo chat message for the App Store screenshot */ +"app_store_screenshot_chat_message_2" = "dinner tonight?"; +/* Demo chat message for the App Store screenshot */ +"app_store_screenshot_chat_message_3" = "I think I know what you are talking about"; +/* Demo chat message for the App Store screenshot */ +"app_store_screenshot_chat_message_4" = "Sure, thanks!"; +/* Demo chat message for the App Store screenshot */ +"app_store_screenshot_chat_message_5" = "yep"; diff --git a/Antidote/en.lproj/InfoPlist.strings b/Antidote/en.lproj/InfoPlist.strings new file mode 100644 index 0000000..b79a4d0 --- /dev/null +++ b/Antidote/en.lproj/InfoPlist.strings @@ -0,0 +1,16 @@ +/* + InfoPlist.strings + Antidote + + Created by Dmytro Vorobiov on 15/11/16. + Copyright © 2016 dvor. All rights reserved. +*/ + +/* Camera usage alert description */ +"NSCameraUsageDescription" = "You can use video calls, send photos and videos, scan QR codes."; + +/* Microphone usage alert description */ +"NSMicrophoneUsageDescription" = "You can use audio and video calls."; + +/* Photo library usage alert description */ +"NSPhotoLibraryUsageDescription" = "You can send photos and videos."; \ No newline at end of file diff --git a/Antidote/en.lproj/Localizable.strings b/Antidote/en.lproj/Localizable.strings new file mode 100644 index 0000000..f4933e4 --- /dev/null +++ b/Antidote/en.lproj/Localizable.strings @@ -0,0 +1,410 @@ +/* + Localizable.strings + Antidote + + Created by Dmytro Vorobiov on 08/10/15. + Copyright © 2015 dvor. All rights reserved. +*/ + +/* Login screen text */ +"login_or_label" = "or"; +/* Login screen text */ +"create_account" = "Create Account"; +/* Login screen text */ +"import_profile" = "Import Profile"; +/* Password field */ +"password" = "Password"; +/* Login button */ +"log_in" = "Log In"; +/* Login screen text */ +"create_profile" = "Create profile"; +/* Login screen text */ +"import_to_antidote" = "Import to Antidote"; +/* Login screen text */ +"create_account_username_title" = "How contacts will see you?"; +/* Login screen text */ +"create_account_username_placeholder" = "Username"; +/* Login screen text */ +"create_account_profile_title" = "How to call this profile?"; +/* Login screen text */ +"create_account_profile_placeholder" = "Profile name"; +/* Login screen text */ +"create_account_profile_hint" = "e.g. Home, iPhone"; +/* Login screen text */ +"set_password_title" = "Set Password"; +/* Login screen text */ +"set_password_hint" = "Password is required to protect your data. Keep it safe - once lost it cannot be restored."; +/* Login button */ +"create_account_next_button" = "Next"; +/* Login button */ +"create_account_go_button" = "Go"; +/* Default status message */ +"default_user_status_message" = "Toxing on Antidote"; + +/* PIN screen text */ +"pin_enter_to_unlock" = "Enter your PIN to unlock"; +/* PIN screen text */ +"pin_set" = "Set PIN"; +/* PIN screen text */ +"pin_confirm" = "Confirm PIN"; +/* PIN screen error */ +"pin_do_not_match" = "PINs did not match. Try again"; +/* PIN screen error */ +"pin_incorrect" = "Incorrect PIN"; +/* PIN screen error details */ +"pin_failed_attempts" = "Failed attempts: %@"; +/* PIN screen message shown on log out */ +"pin_logout_message" = "Too many failed attempts. You have been logged out."; +/* PIN screen screen */ +"pin_enabled" = "Enable PIN"; +/* PIN screen screen */ +"pin_touch_id_enabled" = "Enable Touch ID"; +/* PIN screen screen */ +"pin_description" = "Prevent unauthorized access to Antidote with a PIN."; +/* PIN screen screen */ +"pin_touch_id_description" = "Use your fingerprint as an alternative to entering a PIN."; +/* PIN screen screen */ +"pin_lock_timeout" = "Lock Timeout"; +/* PIN screen screen */ +"pin_lock_immediately" = "Immediately"; +/* PIN screen screen */ +"pin_lock_30_seconds" = "30 Seconds"; +/* PIN screen screen */ +"pin_lock_1_minute" = "1 Minute"; +/* PIN screen screen */ +"pin_lock_2_minutes" = "2 Minutes"; +/* PIN screen screen */ +"pin_lock_5_minutes" = "5 Minutes"; + +/* Label shown when connecting to Tox network */ +"connecting_label" = "Connecting..."; + +/* Tab name and screen name */ +"contacts_title" = "Contacts"; +/* Tab name and screen name */ +"chats_title" = "Chats"; +/* Tab name and screen name */ +"settings_title" = "Settings"; +/* Tab name and screen name */ +"profile_title" = "Profile"; + +/* No contacts placeholder text */ +"contact_no_contacts" = "No contacts"; +/* No contacts placeholder text */ +"contact_no_contacts_add_contact" = "Add a contact\nor\n"; +/* No contacts placeholder text */ +"contact_no_contacts_share_tox_id" = "share your Tox ID"; +/* Contact request section title */ +"contact_requests_section" = "Contact Requests"; +/* Contact last seen status */ +"contact_last_seen" = "Last seen: %@"; +/* Screen name */ +"contact_request" = "Contact Request"; +/* Contact request button */ +"contact_request_decline" = "Decline"; +/* Contact request button */ +"contact_request_accept" = "Accept"; +/* Contact request confirmation */ +"contact_request_delete_title" = "Delete contact request?"; +/* Text shown when contact was deleted */ +"contact_deleted" = "Deleted contact"; + +/* Share Tox ID text */ +"show_qr_code" = "Show QR Code"; +/* Share Tox ID text */ +"copy" = "Copy"; + +/* Add contat screen name */ +"add_contact_title" = "Add Contact"; +/* Add contat button */ +"add_contact_send" = "Send"; +/* Add contat placeholder text */ +"add_contact_tox_id_placeholder" = "Enter Tox ID"; +/* Add contat placeholder text */ +"add_contact_or_label" = "or"; +/* Add contat button */ +"add_contact_use_qr" = "Use QR code"; +/* Add contat placeholder text */ +"add_contact_default_message_title" = "Message"; +/* Add contat default text sended to contact */ +"add_contact_default_message_text" = "Hello! Could you please add me to your contact list?"; +/* Add contat error */ +"add_contact_wrong_qr" = "Wrong QR code. It should contain Tox ID"; + +/* User name text */ +"name" = "Name"; +/* User nickname text */ +"nickname" = "Nickname"; +/* User status message text */ +"status_message" = "Status Message"; +/* User status text */ +"status_title" = "Status"; +/* User Tox ID text */ +"my_tox_id" = "My Tox ID"; +/* User public key text */ +"public_key" = "Public Key"; +/* Share Tox ID text */ +"show_qr" = "Show QR"; +/* Profile menu item / screen name */ +"profile_details" = "Profile Details"; +/* Profile button */ +"logout_button" = "Log Out"; + +/* QR code screen button */ +"qr_close_button" = "Close"; + +/* Chat screen placeholder */ +"chat_no_chats" = "No chats"; +/* Chats screen message text */ +"chat_outgoing_file" = "Outgoing file:"; +/* Chats screen message text */ +"chat_incoming_file" = "Incoming file:"; +/* Chats screen message text */ +"chat_call_finished" = "Call finished"; +/* Chats screen message text */ +"chat_unanwered_call" = "Unanswered call"; +/* Chat button */ +"chat_send_button" = "Send"; +/* Chat notification toast */ +"chat_new_messages" = "↓ New messages"; +/* Chat call information */ +"chat_call_message" = "Call, "; +/* Chat call information */ +"chat_missed_call_message" = "Missed call"; +/* Item present in the menu on long press on message */ +"chat_more_menu_item" = "More"; +/* Message shown on chat list when contact is typing */ +"chat_is_typing_text" = "is typing..."; +/* Text shown in chat when there are undelivered faux offline messages */ +"chat_pending_faux_offline_messages" = "Undelivered messages will be send when both you and friend are online."; + +/* Status message */ +"status_offline" = "Offline"; +/* Status message */ +"status_online" = "Online"; +/* Status message */ +"status_away" = "Away"; +/* Status message */ +"status_busy" = "Busy"; + +/* Notification text */ +"notification_new_message" = "New message"; +/* Notification text */ +"notification_incoming_contact_request" = "Incoming contact request"; +/* Notification text */ +"notification_is_calling" = "is calling"; +/* Notification text */ +"notification_incoming_file" = "Incoming file"; + +/* Settings menu / screen name */ +"settings_about" = "About"; +/* Settings menu / screen name */ +"settings_faq" = "FAQ"; +/* Settings menu / screen name */ +"settings_advanced_settings" = "Advanced Settings"; +/* About screen menu */ +"settings_antidote_version" = "Antidote Version"; +/* About screen menu */ +"settings_antidote_build" = "Antidote Build"; +/* About screen menu */ +"settings_toxcore_version" = "Toxcore Version"; +/* About screen menu */ +"settings_acknowledgements" = "Acknowledgements"; +/* Settings screen menu */ +"settings_autodownload_images" = "Autodownload files"; +/* Settings screen menu */ +"settings_autodownload_images_description" = "Automatically download incoming files."; +/* Settings screen menu */ +"settings_notifications_message_preview" = "Notification Preview"; +/* Settings screen menu */ +"settings_notifications_description" = "When application goes to background, you will still receive notifications up to 10 minutes."; +/* Settings screen menu */ +"settings_udp_enabled" = "Enable UDP"; +/* Settings screen menu */ +"settings_restore_default" = "Restore Default Settings"; +/* Settings screen autodownload images option */ +"settings_never" = "Never"; +/* Settings screen autodownload images option */ +"settings_wifi" = "Wi-Fi"; +/* Settings screen autodownload images option */ +"settings_using_wifi" = "Using Wi-Fi"; +/* Settings screen autodownload images option */ +"settings_always" = "Always"; + +/* Profile settings menu */ +"change_password" = "Change Password"; +/* Profile settings menu */ +"delete_password" = "Delete Password"; +/* Profile settings menu */ +"old_password" = "Old Password"; +/* Change password text */ +"new_password" = "New Password"; +/* Change password text */ +"repeat_password" = "Repeat Password"; +/* Change password button */ +"change_password_done" = "Done"; +/* Change password error */ +"password_is_empty_error" = "Password should be non-empty"; +/* Change password error */ +"wrong_old_password" = "Wrong password"; +/* Change password error */ +"passwords_do_not_match" = "Passwords do not match"; + +/* Source of photo to take */ +"photo_from_camera" = "Camera"; +/* Source of photo to take */ +"photo_from_photo_library" = "Photo Library"; +/* Error while converting avatar image */ +"change_avatar_error_convert_image" = "Cannot convert image"; + +/* Alert text when sending file to contacts */ +"file_send_to_contact" = "Send to contact"; + +/* Profile menu item */ +"export_profile" = "Export Profile"; +/* Profile menu item */ +"delete_profile" = "Delete Profile"; +/* Delete profile confirmation */ +"delete_profile_confirmation_title_1" = "Delete this profile?"; +/* Delete profile confirmation */ +"delete_profile_confirmation_title_2" = "Are you sure?"; +/* Delete profile confirmation */ +"delete_profile_confirmation_message" = "This operation cannot be undone"; + +/* Call screen text */ +"call_incoming" = "Incoming call"; +/* Call screen text */ +"call_ended" = "Call ended"; +/* Call screen text */ +"call_reaching" = "Reaching..."; + +/* File message text */ +"chat_file_cancelled" = "Cancelled"; +/* File message text */ +"chat_waiting" = "Waiting..."; +/* File message text */ +"chat_paused" = "Paused"; + +/* Deleting chat confirmation */ +"delete_chat_title" = "Delete this chat and message history?"; +/* Deleting contat confirmation */ +"delete_contact_title" = "Delete this contact?\nYour chat history will be lost."; +/* Deleting contat request confirmation */ +"delete_contact_request_title" = "Delete this contact request?"; +/* Deleting single message in chat */ +"delete_single_message" = "Delete Message"; +/* Deleting multiple messages in chat. */ +"delete_multiple_messages" = "Delete Messages"; +/* Deleting all messages in chat. */ +"delete_all_messages" = "Delete All"; +/* Delete button */ +"alert_delete" = "Delete"; +/* Delete button */ +"alert_cancel" = "Cancel"; + +/* Error while creating new profile */ +"login_enter_username_and_profile" = "Please enter both username and profile name."; +/* Error while creating new profile */ +"login_profile_already_exists" = "Profile with given name already exists"; + +/* General error title */ +"error_title" = "Error"; +/* General error button */ +"error_ok_button" = "OK"; +/* General error button */ +"error_retry_button" = "Retry"; +/* Error */ +"error_contact_not_connected" = "Contact isn't online"; +/* Error */ +"error_too_many_files" = "Too many active file transfers"; +/* Error */ +"error_internal_message" = "Internal error"; +/* Error */ +"error_wrong_password_title" = "Wrong password"; +/* Error */ +"error_wrong_password_message" = "Password contains wrong symbols."; +/* Error */ +"error_import_not_exist_title" = "Cannot import tox save file"; +/* Error */ +"error_import_not_exist_message" = "File does not exist."; +/* Error */ +"error_decrypt_title" = "Cannot decrypt tox save file"; +/* Error */ +"error_decrypt_empty_data_message" = "Some input data was empty."; +/* Error */ +"error_decrypt_bad_format_message" = "File has bad format or is corrupted."; +/* Error */ +"error_decrypt_wrong_password_message" = "Password is wrong or file is corrupted."; +/* Error */ +"error_general_unknown_message" = "Unknown error occurred."; +/* Error */ +"error_general_no_memory_message" = "Not enough memory."; +/* Error */ +"error_general_bind_port_message" = "Was unable to bind to a port."; +/* Error */ +"error_general_profile_encrypted_message" = "Profile is encrypted."; +/* Error */ +"error_general_bad_format_message" = "File has bad format or is corrupted."; +/* Error */ +"error_proxy_title" = "Proxy error"; +/* Error */ +"error_proxy_invalid_address_message" = "Proxy address has invalid format."; +/* Error */ +"error_proxy_invalid_port_message" = "Proxy port is invalid."; +/* Error */ +"error_proxy_host_not_resolved_message" = "Proxy host could not be resolved."; + +/* Error */ +"error_name_too_long" = "Name is too long."; +/* Error */ +"error_status_message_too_long" = "Status message is too long"; + +/* Error */ +"error_contact_request_too_long" = "Message is too long"; +/* Error */ +"error_contact_request_no_message" = "No message specified"; +/* Error */ +"error_contact_request_own_key" = "Cannot add myself to contact list"; +/* Error */ +"error_contact_request_already_sent" = "Contact request was already sent"; +/* Error */ +"error_contact_request_bad_checksum" = "Bad checksum, please check entered Tox ID"; +/* Error */ +"error_contact_request_new_nospam" = "Bad nospam value, please check entered Tox ID"; + +/* Call error */ +"call_error_already_in_call" = "Already in a call"; +/* Call error */ +"call_error_contact_is_offline" = "Contact is offline"; +/* Call error */ +"call_error_no_active_call" = "There is no active call"; + +/* Error while using color theme */ +"theme_error_cannot_open" = "Cannot open theme, wrong format"; + +/* Tab chats badge ending */ +"accessibility_chats_ending" = "unread chats"; +/* Avatar button label in settings */ +"accessibility_avatar_button_label" = "Avatar"; +/* Avatar button hint in settings */ +"accessibility_avatar_button_hint" = "Sets or removes avatar."; +/* Chat button label in contact screen */ +"accessibility_chat_button_label" = "Chat"; +/* Chat button hint in contact screen */ +"accessibility_chat_button_hint" = "Opens chat dialog."; +/* Call button label in contact screen */ +"accessibility_call_button_label" = "Audio call"; +/* Call button hint in contact screen */ +"accessibility_call_button_hint" = "Makes audio call."; +/* Video button label in contact screen */ +"accessibility_video_button_label" = "Video call"; +/* Video button hint in contact screen */ +"accessibility_video_button_hint" = "Makes video call."; +/* Tap to copy hint */ +"accessibility_show_copy_hint" = "Shows copy menu."; +/* Tap to edit value hint */ +"accessibility_edit_value_hint" = "Edits value."; +/* Incoming message label */ +"accessibility_incoming_message_label" = "Message"; +/* Outgoing message label */ +"accessibility_outgoing_message_label" = "Your message"; diff --git a/Antidote/en.lproj/import-profile.html b/Antidote/en.lproj/import-profile.html new file mode 100644 index 0000000..7f2b2f3 --- /dev/null +++ b/Antidote/en.lproj/import-profile.html @@ -0,0 +1,10 @@ + +

To import your Tox profile:

+ +
    +
  1. Send the ".tox" file to your device using any app (Mail, Dropbox, etc.).
  2. +
  3. Use "Open In" menu for this file.
  4. +
  5. Select Antidote in a list of available apps.
  6. +
  7. Check the name of your new profile and press OK.
  8. +
+
diff --git a/Antidote/enm.lproj/Localizable.strings b/Antidote/enm.lproj/Localizable.strings new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/Antidote/enm.lproj/Localizable.strings @@ -0,0 +1 @@ + diff --git a/Antidote/es.lproj/AppStoreLocalizable.strings b/Antidote/es.lproj/AppStoreLocalizable.strings new file mode 100644 index 0000000000000000000000000000000000000000..3f83883781ab40037320a8d4bc9e212b89188067 GIT binary patch literal 7612 zcmeI1%Wl&^6oyBLRTqdyFx?;(NNBkffugEv78Kfos07O@O`MC8I#Did!yEBN+0aJ; zzW+={nTUo(7s!z;%l3FYmow*|bMf!rzshdQC2oT=arjPl)91|(PBtl=310P-;COhYtUy*tBra6fsItNx(0KcyD8VIyWp--`aFHL`TD%; zP`ae1&)A83?%udE*B!3gZkL(;TnD@#&|fmNT$^zc_k(kXwrZCk#ifl|qP&mPJ?@Lv zBYR4bJ*D=NYs1FgVjjuub#lUrFL)63C~ zl-u+eGmqM+JV7e25zW!G=bmY2$jq9h&-_n$mr;`ZsbP_@_LQ1|p^@19dZ&>Otf#cB zF?)Q2*2~$Fe)W_xlJ;Io?`^lqm=(@VcTDZj^rU^zwH8zA-xbJ# zYu=FCiICI2?|_{!l^6JEJNvr84t>au^M>7v2)hr+m~nK>GKa`}ihX)tQrKQT@p~EJ z=e?$4b`9*RAa{-T%nIAfsqMXruv1i5rlc(96D7s+7IlT)<;Ct+Wh%<8+8~u0c8Y&O zQu$kfUH-6(bCrWRR?1cMy-+o8S)+DRpqHcXgoWkB*~$?ZX@4Dq*3iDB>d0K!T>fk> z&QZSM9jD|ZlJY%QeFN(obyQ?359@K#|*qml{XjE zC&m_J#=i(-aTMZz#QfZqUAYVIAkN}8DVAA>LyH3Yw2WD<1uNs38!;+J9L?7vK1yGGx+*Rzml5XAsOxhL&#|vvpB2Y3L|A*qEMO`|&SwJ)oW+ER zt=mHvpI7KY?<%wVH|wdB*h5dzz=YN43*_2%foDh?>;`d=b?RgZ+9iP*RmLli?pe&h zI(ok@ZdF`@+6F#3W+H>0*Hd$`cYMMsWjBw_Y82bVfljfPz|2-=4}Vr>57u;-yvD}` zhE}|+zE&Ttso&d;)^Z49{{KM>{PeFN_&@O|E!G)!df-xSi*vz)$XZ4mHDk~JcbxN5 zoDqFvDVF10Wp?i-oU5!Z->ZqEmi&@fOL-gNq(~qB8Lf`W`CeZfqYmf0Ppj-w)^nF~ zpWI9TdcsPA-wwWb%nt0)()-+mr*ryD(9n8f9>=KDC{ywAL%JFL!y5%HE!#z2tTT=x KQ+D!Tj?o{Mwm*gd literal 0 HcmV?d00001 diff --git a/Antidote/es.lproj/InfoPlist.strings b/Antidote/es.lproj/InfoPlist.strings new file mode 100644 index 0000000000000000000000000000000000000000..6c333a86e6042a9b313f0a4b40846fa9afa0f57c GIT binary patch literal 978 zcmbu7K~KU!5QX2_U(xhP42X$bj0XZ26E&#O#ABfqNT4NcY2r`vPpaSSrcg~U*uzd| zW@p~ad)@D^fqDvb#tC$*RPV|((?)9*D%E#3CrY)%_jO~Ul3Yw}sf4W0Pm~iyE*FD0 z*9Ug0E#H#6jOZ0>-kknS6`2gQKto+=fE_wJVsed{X-B{9u+$2iK%bmTT~Is1i$O8W zKK_`^H++xPg^Ln)Psmo-*kSjWV|#o46Sm&Eiir9>)e+MY{0Kbjw7D@}p@l==kue6g zyT=Okpl3CaUJf|Z*3OXL8&0SA{@Gj@f}iR?aQqX2bQ+?O2V zYW){uBZHE&+-TS8KuDh literal 0 HcmV?d00001 diff --git a/Antidote/es.lproj/Localizable.strings b/Antidote/es.lproj/Localizable.strings new file mode 100644 index 0000000..29b4782 --- /dev/null +++ b/Antidote/es.lproj/Localizable.strings @@ -0,0 +1,415 @@ +/* + Localizable.strings + Antidote + + Created by Dmytro Vorobiov on 08/10/15. + Copyright © 2015 dvor. All rights reserved. +*/ + +/* + Translation is done with Transifex service. + See https://www.transifex.com/antidote/antidote-ios/ +*/ + +/* Login screen text */ +"login_or_label" = "o"; +/* Login screen text */ +"create_account" = "Crear cuenta"; +/* Login screen text */ +"import_profile" = "Importar perfil"; +/* Password field */ +"password" = "Contraseña"; +/* Login button */ +"log_in" = "Iniciar sesión"; +/* Login screen text */ +"create_profile" = "Crear perfil"; +/* Login screen text */ +"import_to_antidote" = "Importar a Antidote"; +/* Login screen text */ +"create_account_username_title" = "¿Cómo te verán los contactos?"; +/* Login screen text */ +"create_account_username_placeholder" = "Nombre de usuario"; +/* Login screen text */ +"create_account_profile_title" = "¿Qué nombre desea ponerle a este perfil?"; +/* Login screen text */ +"create_account_profile_placeholder" = "Nombre del perfil"; +/* Login screen text */ +"create_account_profile_hint" = "p.ej. Casa, iPhone"; +/* Login screen text */ +"set_password_title" = "Establecer contraseña"; +/* Login screen text */ +"set_password_hint" = "La contraseña es necesaria para protejer tus datos. Guárdala en un lugar seguro, si se pierde no se puede recuperar."; +/* Login button */ +"create_account_next_button" = "Siguiente"; +/* Login button */ +"create_account_go_button" = "Ir"; +/* Default status message */ +"default_user_status_message" = "\"Toxing\" en Antidote"; + +/* PIN screen text */ +"pin_enter_to_unlock" = "Introducir PIN para desbloquear"; +/* PIN screen text */ +"pin_set" = "Establecer PIN"; +/* PIN screen text */ +"pin_confirm" = "Confirmar PIN"; +/* PIN screen error */ +"pin_do_not_match" = "Los PIN son diferentes, inténtelo de nuevo"; +/* PIN screen error */ +"pin_incorrect" = "PIN incorrecto"; +/* PIN screen error details */ +"pin_failed_attempts" = "Intentos fallidos: %@"; +/* PIN screen message shown on log out */ +"pin_logout_message" = "Demasiados intentos fallidos. Has sido desconectado."; +/* PIN screen screen */ +"pin_enabled" = "Habilitar PIN"; +/* PIN screen screen */ +"pin_touch_id_enabled" = "Habilitar Touch ID"; +/* PIN screen screen */ +"pin_description" = "Evite el acceso no autorizado a Antidote con un PIN."; +/* PIN screen screen */ +"pin_touch_id_description" = "Use su huella digital como alternativa a ingresar un PIN."; +/* PIN screen screen */ +"pin_lock_timeout" = "Tiempo de autobloqueo"; +/* PIN screen screen */ +"pin_lock_immediately" = "Ahora mismo"; +/* PIN screen screen */ +"pin_lock_30_seconds" = "30 segundos"; +/* PIN screen screen */ +"pin_lock_1_minute" = "1 minuto"; +/* PIN screen screen */ +"pin_lock_2_minutes" = "2 minutos"; +/* PIN screen screen */ +"pin_lock_5_minutes" = "5 minutos"; + +/* Label shown when connecting to Tox network */ +"connecting_label" = "Conectando..."; + +/* Tab name and screen name */ +"contacts_title" = "Contactos"; +/* Tab name and screen name */ +"chats_title" = "Chatear"; +/* Tab name and screen name */ +"settings_title" = "Ajustes"; +/* Tab name and screen name */ +"profile_title" = "Perfil"; + +/* No contacts placeholder text */ +"contact_no_contacts" = "Sin contactos"; +/* No contacts placeholder text */ +"contact_no_contacts_add_contact" = "Añadir un contacto\no\n"; +/* No contacts placeholder text */ +"contact_no_contacts_share_tox_id" = "compartir su Tox ID"; +/* Contact request section title */ +"contact_requests_section" = "Solicitudes de contacto"; +/* Contact last seen status */ +"contact_last_seen" = "Visto por última vez: %@"; +/* Screen name */ +"contact_request" = "Solicitud de contacto"; +/* Contact request button */ +"contact_request_decline" = "Rechazar"; +/* Contact request button */ +"contact_request_accept" = "Aceptar"; +/* Contact request confirmation */ +"contact_request_delete_title" = "¿Eliminar solicitud de contacto?"; +/* Text shown when contact was deleted */ +"contact_deleted" = "Contacto eliminado"; + +/* Share Tox ID text */ +"show_qr_code" = "Mostrar código QR"; +/* Share Tox ID text */ +"copy" = "Copiar"; + +/* Add contat screen name */ +"add_contact_title" = "Añadir contacto"; +/* Add contat button */ +"add_contact_send" = "Enviar"; +/* Add contat placeholder text */ +"add_contact_tox_id_placeholder" = "Introducir Tox ID"; +/* Add contat placeholder text */ +"add_contact_or_label" = "o"; +/* Add contat button */ +"add_contact_use_qr" = "Utilizar código QR"; +/* Add contat placeholder text */ +"add_contact_default_message_title" = "Mensaje"; +/* Add contat default text sended to contact */ +"add_contact_default_message_text" = "¡Hola! ¿Me añades a tu lista de contactos?"; +/* Add contat error */ +"add_contact_wrong_qr" = "Código QR erróneo. El código debe contener un Tox ID"; + +/* User name text */ +"name" = "Nombre"; +/* User nickname text */ +"nickname" = "Nombre para mostrar"; +/* User status message text */ +"status_message" = "Mensaje de estado"; +/* User status text */ +"status_title" = "Estado"; +/* User Tox ID text */ +"my_tox_id" = "Mi Tox ID"; +/* User public key text */ +"public_key" = "Clave pública"; +/* Share Tox ID text */ +"show_qr" = "Mostrar QR"; +/* Profile menu item / screen name */ +"profile_details" = "Detalles del perfil"; +/* Profile button */ +"logout_button" = "Cerrar sesión"; + +/* QR code screen button */ +"qr_close_button" = "Cerrar"; + +/* Chat screen placeholder */ +"chat_no_chats" = "Sin chats"; +/* Chats screen message text */ +"chat_outgoing_file" = "Archivo saliente:"; +/* Chats screen message text */ +"chat_incoming_file" = "Archivo entrante:"; +/* Chats screen message text */ +"chat_call_finished" = "Llamada finalizada"; +/* Chats screen message text */ +"chat_unanwered_call" = "Llamada sin respuesta"; +/* Chat button */ +"chat_send_button" = "Enviar"; +/* Chat notification toast */ +"chat_new_messages" = "↓ Nuevos mensajes"; +/* Chat call information */ +"chat_call_message" = "Llamada, "; +/* Chat call information */ +"chat_missed_call_message" = "Llamada perdida"; +/* Item present in the menu on long press on message */ +"chat_more_menu_item" = "Más"; + +/* Status message */ +"status_offline" = "Sin conexión"; +/* Status message */ +"status_online" = "Conectado"; +/* Status message */ +"status_away" = "Ausente"; +/* Status message */ +"status_busy" = "Ocupado"; + +/* Notification text */ +"notification_new_message" = "Nuevo mensaje"; +/* Notification text */ +"notification_incoming_contact_request" = "Recibiendo solicitud de contacto"; +/* Notification text */ +"notification_is_calling" = "está llamando"; +/* Notification text */ +"notification_incoming_file" = "Archivo entrante"; + +/* Settings menu / screen name */ +"settings_about" = "Acerca de"; +/* Settings menu / screen name */ +"settings_faq" = "FAQ"; +/* Settings menu / screen name */ +"settings_advanced_settings" = "Ajustes avanzados"; +/* About screen menu */ +"settings_antidote_version" = "Versión de Antidote"; +/* About screen menu */ +"settings_antidote_build" = "Compilación de Antidote"; +/* About screen menu */ +"settings_toxcore_version" = "Versión de Toxcore"; +/* About screen menu */ +"settings_acknowledgements" = "Reconocimientos"; +/* Settings screen menu */ +"settings_autodownload_images" = "Descarga automática de archivos"; +/* Settings screen menu */ +"settings_autodownload_images_description" = "Descarga automáticamente los archivos entrantes."; +/* Settings screen menu */ +"settings_notifications_message_preview" = "Previsualización de notificaciones"; +/* Settings screen menu */ +"settings_notifications_description" = "Cuando la aplicación pasa a segundo plano, se seguirán recibiendo notificaciones hasta 10 minutos después."; +/* Settings screen menu */ +"settings_udp_enabled" = "Habilitar UDP"; +/* Settings screen menu */ +"settings_restore_default" = "Restaurar ajustes por defecto"; +/* Settings screen autodownload images option */ +"settings_never" = "Nunca"; +/* Settings screen autodownload images option */ +"settings_wifi" = "Wi-Fi"; +/* Settings screen autodownload images option */ +"settings_using_wifi" = "Utilizando Wi-Fi"; +/* Settings screen autodownload images option */ +"settings_always" = "Siempre"; + +/* Profile settings menu */ +"change_password" = "Cambiar contraseña"; +/* Profile settings menu */ +"delete_password" = "Eliminar contraseña"; +/* Profile settings menu */ +"old_password" = "Contraseña anterior"; +/* Change password text */ +"new_password" = "Contraseña nueva"; +/* Change password text */ +"repeat_password" = "Repetir contraseña"; +/* Change password button */ +"change_password_done" = "Hecho"; +/* Change password error */ +"password_is_empty_error" = "La contraseña no puede estar vacía"; +/* Change password error */ +"wrong_old_password" = "Contraseña errónea"; +/* Change password error */ +"passwords_do_not_match" = "Las contraseñas no concuerdan"; + +/* Source of photo to take */ +"photo_from_camera" = "Cámara"; +/* Source of photo to take */ +"photo_from_photo_library" = "Biblioteca fotográfica"; +/* Error while converting avatar image */ +"change_avatar_error_convert_image" = "No es posible convertir la imagen"; + +/* Alert text when sending file to contacts */ +"file_send_to_contact" = "Enviar a contacto"; + +/* Profile menu item */ +"export_profile" = "Exportar perfil"; +/* Profile menu item */ +"delete_profile" = "Borrar perfil"; +/* Delete profile confirmation */ +"delete_profile_confirmation_title_1" = "¿Desea borrar este perfil?"; +/* Delete profile confirmation */ +"delete_profile_confirmation_title_2" = "¿Está seguro?"; +/* Delete profile confirmation */ +"delete_profile_confirmation_message" = "Esta operación no se puede deshacer"; + +/* Call screen text */ +"call_incoming" = "Llamada entrante"; +/* Call screen text */ +"call_ended" = "Llamada finalizada"; +/* Call screen text */ +"call_reaching" = "Llamando..."; + +/* File message text */ +"chat_file_cancelled" = "Cancelada"; +/* File message text */ +"chat_waiting" = "Esperando..."; +/* File message text */ +"chat_paused" = "En pausa"; + +/* Deleting chat confirmation */ +"delete_chat_title" = "¿Borrar este chat y el historial de mensajes?"; +/* Deleting contat confirmation */ +"delete_contact_title" = "¿Eliminar este contacto?\nSu historial de chat será eliminado."; +/* Deleting contat request confirmation */ +"delete_contact_request_title" = "¿Eliminar la solicitud de contacto?"; +/* Deleting single message in chat */ +"delete_single_message" = "Eliminar mensaje"; +/* Deleting multiple messages in chat. */ +"delete_multiple_messages" = "Eliminar mensajes"; +/* Deleting all messages in chat. */ +"delete_all_messages" = "Eliminar todo"; +/* Delete button */ +"alert_delete" = "Eliminar"; +/* Delete button */ +"alert_cancel" = "Cancelar"; + +/* Error while creating new profile */ +"login_enter_username_and_profile" = "Por favor, introduzca el nombre de usuario y el nombre de perfil."; +/* Error while creating new profile */ +"login_profile_already_exists" = "Ya existe un perfil con ese nombre"; + +/* General error title */ +"error_title" = "Error"; +/* General error button */ +"error_ok_button" = "Ok"; +/* General error button */ +"error_retry_button" = "Reintentar"; +/* Error */ +"error_contact_not_connected" = "El contacto no está conectado"; +/* Error */ +"error_too_many_files" = "Demasiadas transferencias de archivos activas"; +/* Error */ +"error_internal_message" = "Error interno"; +/* Error */ +"error_wrong_password_title" = "Contraseña errónea"; +/* Error */ +"error_wrong_password_message" = "La contraseña contiene símbolos no permitidos."; +/* Error */ +"error_import_not_exist_title" = "No se ha podido importar el archivo de tox"; +/* Error */ +"error_import_not_exist_message" = "El archivo no existe."; +/* Error */ +"error_decrypt_title" = "No se ha podido descifrar el archivo de tox"; +/* Error */ +"error_decrypt_empty_data_message" = "Algunos datos de entrada estaban vacíos."; +/* Error */ +"error_decrypt_bad_format_message" = "El archivo tiene un formato incorrecto o está dañado."; +/* Error */ +"error_decrypt_wrong_password_message" = "La contraseña es incorrecta o el archivo está corrupto."; +/* Error */ +"error_general_unknown_message" = "Error desconocido."; +/* Error */ +"error_general_no_memory_message" = "Memoria insuficiente."; +/* Error */ +"error_general_bind_port_message" = "Error en la conexión al puerto."; +/* Error */ +"error_general_profile_encrypted_message" = "El perfil está cifrado."; +/* Error */ +"error_general_bad_format_message" = "El archivo está mal formateado o está corrupto."; +/* Error */ +"error_proxy_title" = "Error de proxy"; +/* Error */ +"error_proxy_invalid_address_message" = "La dirección de proxy tiene un formato incorrecto."; +/* Error */ +"error_proxy_invalid_port_message" = "El puerto del proxy no es válido."; +/* Error */ +"error_proxy_host_not_resolved_message" = "No se pudo resolver el proxy."; + +/* Error */ +"error_name_too_long" = "El nombre es demasiado largo."; +/* Error */ +"error_status_message_too_long" = "El mensaje de estado es demasiado largo"; + +/* Error */ +"error_contact_request_too_long" = "El mensaje es demasiado largo"; +/* Error */ +"error_contact_request_no_message" = "No se especificó ningún mensaje"; +/* Error */ +"error_contact_request_own_key" = "No se puede añadir a uno mismo a la lista de contactos"; +/* Error */ +"error_contact_request_already_sent" = "La solicitud de contacto fue enviada previamente"; +/* Error */ +"error_contact_request_bad_checksum" = "Fallo en el checksum, por favor compruebe la Tox ID"; +/* Error */ +"error_contact_request_new_nospam" = "Valor de no spam erróneo, por favor compruebe la Tox ID"; + +/* Call error */ +"call_error_already_in_call" = "Ya está en una llamada"; +/* Call error */ +"call_error_contact_is_offline" = "El contacto está desconectado"; +/* Call error */ +"call_error_no_active_call" = "No hay una llamada activa"; + +/* Error while using color theme */ +"theme_error_cannot_open" = "No se puede abrir el tema, formato incorrecto"; + +/* Tab chats badge ending */ +"accessibility_chats_ending" = "chats sin leer"; +/* Avatar button label in settings */ +"accessibility_avatar_button_label" = "Avatar"; +/* Avatar button hint in settings */ +"accessibility_avatar_button_hint" = "Establece o elimina el avatar."; +/* Chat button label in contact screen */ +"accessibility_chat_button_label" = "Chat"; +/* Chat button hint in contact screen */ +"accessibility_chat_button_hint" = "Abre un chat."; +/* Call button label in contact screen */ +"accessibility_call_button_label" = "Llamada de voz"; +/* Call button hint in contact screen */ +"accessibility_call_button_hint" = "Hacer una llamada."; +/* Video button label in contact screen */ +"accessibility_video_button_label" = "Videollamada"; +/* Video button hint in contact screen */ +"accessibility_video_button_hint" = "Realiza una videollamada."; +/* Tap to copy hint */ +"accessibility_show_copy_hint" = "Muestra el menú de copia."; +/* Tap to edit value hint */ +"accessibility_edit_value_hint" = "Edita el valor."; +/* Incoming message label */ +"accessibility_incoming_message_label" = "Message"; +/* Outgoing message label */ +"accessibility_outgoing_message_label" = "Tu mensaje"; +/* Message shown on chat list when contact is typing */ +"chat_is_typing_text" = "está escribiendo…"; +/* Text shown in chat when there are undelivered faux offline messages */ +"chat_pending_faux_offline_messages" = "Los mensajes no entregados se enviarán cuando tu y tu amigo estéis conectados."; diff --git a/Antidote/es.lproj/import-profile.html b/Antidote/es.lproj/import-profile.html new file mode 100644 index 0000000..c654cd4 --- /dev/null +++ b/Antidote/es.lproj/import-profile.html @@ -0,0 +1,9 @@ + +

Para importar su perfil de Tox:

+ +
    +
  1. Enviar el archivo ".tox" a su dispositivo utilizando cualquier app (Mail, Dropbox, etc.).
  2. +
  3. Usar el menú “Abrir en“ con este archivo.
  4. +
  5. Seleccionar Antidote en la lista de aplicaciones disponibles.
  6. +
  7. Compruebe el nombre de su nuevo perfil y pulse OK.
  8. +
diff --git a/Antidote/fr.lproj/AppStoreLocalizable.strings b/Antidote/fr.lproj/AppStoreLocalizable.strings new file mode 100644 index 0000000000000000000000000000000000000000..1e2a7bb8de0c65bf45a806a938c75367ac179b46 GIT binary patch literal 7690 zcmeI1%}!H66vt1DD;CB_7}=1ZfZzv4(-7p#7&Rmix1_We+6ZlJ3yN>#8+9XFuE+;eJwjwJO8$&-lo;{O<%L7hW%^4Qq}wF+GF3&bYHh)Jz1r#xA(qZ zTVqYNPSw-a+QA;$Gh5JoN%uut*3NOSHH~-lJv1CzL+b?ls%uGenHNOGsjoS&_Nu5p z(sMMs=Wm&4&(wRWd)?Qb)jrT2W%5oOA8QP14s<{86*5r<9|yjE(B2K76J-|?=>@G{ z(>IxZEwvl^qOX0JL;FNjMTxM-fxjQQbh_G^UE13JfyP>DL4W301o57!r{ib@-=8s7 zUh^-JGHV{{-qOW-V8U*nBr|A+y2yP~R5BZsKX?m?_OX}2ouXya2$-&s80nPxA$vbkfS$65A=(A(BK)r1paSLUC^ zImeGIFU?%YR8IU9AMGwjGPk?D2D2_S84I#ZPW{wsy0TB|8PtmKxi_uE+@wZv9Tnph zidE5-*203Qrv4E`KeZS%m&y!1J!x;vGj3`aX!6RK@0lD4q_L4o9vs3SrwOW9HJiDR zLr1l`&V=%rMvx81@S}Lld7BfTcux9weiz>0&Z!E#>+Yu*S<$tvel&VcV{P53?C~B) zD}&qTX&jmyT}VB3Uz`Wmcq*5iF*$D%adTP3j48JXbfu{|)IDcBD@KBR8NWexdF?Wu zRq4m`vm&F^m8ne7A1jivjtdr(DbLh*-gmBYeS^b>aoq?zhU|&V*{tQz4XB zdO6>=T@&t2C~nIMH?LhcPo;x+dg|>FL!#N)(CVpoQyJ|I`MoL*HZ&hkf=-jGR=pDc zzvEz}V($_a<8iPuxOJXi*V$dMxk+PM-G0g=MeiJad{0=Bb^a@67n{E{mPP#}0`YHE z^s-e&uAIl{TZwD*;AQc+F|vJDYvkL-kknS6`2gQKto+=fE_wJVsed{X-B{9u+$2iK%bmTT~Is1i$O8W zKK_`^H++xPg^Ln)Psmo-*kSjWV|#o46Sm&Eiir9>)e+MY{0Kbjw7D@}p@l==kue6g zyT=Okpl3CaUJf|Z*3OXL8&0SA{@Gj@f}iR?aQqX2bQ+?O2V zYW){uBZHE&+-TS8KuDh literal 0 HcmV?d00001 diff --git a/Antidote/fr.lproj/Localizable.strings b/Antidote/fr.lproj/Localizable.strings new file mode 100644 index 0000000..df3d70c --- /dev/null +++ b/Antidote/fr.lproj/Localizable.strings @@ -0,0 +1,415 @@ +/* + Localizable.strings + Antidote + + Created by Dmytro Vorobiov on 08/10/15. + Copyright © 2015 dvor. All rights reserved. +*/ + +/* + Translation is done with Transifex service. + See https://www.transifex.com/antidote/antidote-ios/ +*/ + +/* Login screen text */ +"login_or_label" = "ou"; +/* Login screen text */ +"create_account" = "Créer un compte"; +/* Login screen text */ +"import_profile" = "Importer un profil"; +/* Password field */ +"password" = "Mot de passe"; +/* Login button */ +"log_in" = "Se connecter"; +/* Login screen text */ +"create_profile" = "Créer un profil"; +/* Login screen text */ +"import_to_antidote" = "Importer vers Antidote"; +/* Login screen text */ +"create_account_username_title" = "Comment les contacts vont-ils vous voir ?"; +/* Login screen text */ +"create_account_username_placeholder" = "Nom d'utilisateur"; +/* Login screen text */ +"create_account_profile_title" = "Comment appeler ce profil ?"; +/* Login screen text */ +"create_account_profile_placeholder" = "Nom du profil"; +/* Login screen text */ +"create_account_profile_hint" = "par exemple, Principal, iPhone"; +/* Login screen text */ +"set_password_title" = "Définir un mot de passe"; +/* Login screen text */ +"set_password_hint" = "Un mot de passe est requis pour protéger vos données. Gardez le en sécurité − une fois perdu il ne pourra pas être restauré."; +/* Login button */ +"create_account_next_button" = "Suivant"; +/* Login button */ +"create_account_go_button" = "Aller"; +/* Default status message */ +"default_user_status_message" = "Je toxe sur Antidote"; + +/* PIN screen text */ +"pin_enter_to_unlock" = "Entrez votre PIN pour déverrouiller"; +/* PIN screen text */ +"pin_set" = "Définir un code PIN"; +/* PIN screen text */ +"pin_confirm" = "Confirmez le code PIN"; +/* PIN screen error */ +"pin_do_not_match" = "Les codes PIN ne correspondent pas. Réessayez"; +/* PIN screen error */ +"pin_incorrect" = "PIN incorrect"; +/* PIN screen error details */ +"pin_failed_attempts" = "Tentatives échouées : %@"; +/* PIN screen message shown on log out */ +"pin_logout_message" = "Trop de tentatives ratées. Vous avez été déconnecté(e)."; +/* PIN screen screen */ +"pin_enabled" = "Activer le code PIN"; +/* PIN screen screen */ +"pin_touch_id_enabled" = "Activer Touch ID"; +/* PIN screen screen */ +"pin_description" = "Empêcher les accès non autorisés à Antidote avec un code PIN."; +/* PIN screen screen */ +"pin_touch_id_description" = "Utilisez votre empreinte digitale comme alternative au code PIN."; +/* PIN screen screen */ +"pin_lock_timeout" = "Délais de verrouillage"; +/* PIN screen screen */ +"pin_lock_immediately" = "Immédiatement"; +/* PIN screen screen */ +"pin_lock_30_seconds" = "30 secondes"; +/* PIN screen screen */ +"pin_lock_1_minute" = "1 minute"; +/* PIN screen screen */ +"pin_lock_2_minutes" = "2 minutes"; +/* PIN screen screen */ +"pin_lock_5_minutes" = "5 minutes"; + +/* Label shown when connecting to Tox network */ +"connecting_label" = "Chargement..."; + +/* Tab name and screen name */ +"contacts_title" = "Contacts"; +/* Tab name and screen name */ +"chats_title" = "Conversations"; +/* Tab name and screen name */ +"settings_title" = "Réglages"; +/* Tab name and screen name */ +"profile_title" = "Profil"; + +/* No contacts placeholder text */ +"contact_no_contacts" = "Il n'y a pas de contacts"; +/* No contacts placeholder text */ +"contact_no_contacts_add_contact" = "Ajouter un contact\nou\n"; +/* No contacts placeholder text */ +"contact_no_contacts_share_tox_id" = "Partager votre identité Tox"; +/* Contact request section title */ +"contact_requests_section" = "Invitations"; +/* Contact last seen status */ +"contact_last_seen" = "Vu à : %@"; +/* Screen name */ +"contact_request" = "Invitation"; +/* Contact request button */ +"contact_request_decline" = "Décliner"; +/* Contact request button */ +"contact_request_accept" = "Accepter"; +/* Contact request confirmation */ +"contact_request_delete_title" = "Vous voulez bien supprimer l'invitation ?"; +/* Text shown when contact was deleted */ +"contact_deleted" = "Contact supprimé"; + +/* Share Tox ID text */ +"show_qr_code" = "Afficher le code QR"; +/* Share Tox ID text */ +"copy" = "Copier"; + +/* Add contat screen name */ +"add_contact_title" = "Ajouter des contacts"; +/* Add contat button */ +"add_contact_send" = "Envoyer"; +/* Add contat placeholder text */ +"add_contact_tox_id_placeholder" = "Saisir votre identité Tox"; +/* Add contat placeholder text */ +"add_contact_or_label" = "ou"; +/* Add contat button */ +"add_contact_use_qr" = "Utiliser le code QR"; +/* Add contat placeholder text */ +"add_contact_default_message_title" = "Message"; +/* Add contat default text sended to contact */ +"add_contact_default_message_text" = "Salut ! Pourriez-vous m'ajouter à votre liste de contacts ?"; +/* Add contat error */ +"add_contact_wrong_qr" = "Le code QR est mauvais. Il devrait contenir une identité Tox"; + +/* User name text */ +"name" = "Nom"; +/* User nickname text */ +"nickname" = "Pseudonyme"; +/* User status message text */ +"status_message" = "Message de statut"; +/* User status text */ +"status_title" = "Statut"; +/* User Tox ID text */ +"my_tox_id" = "Mon identité Tox"; +/* User public key text */ +"public_key" = "Clé publique"; +/* Share Tox ID text */ +"show_qr" = "Afficher le QR"; +/* Profile menu item / screen name */ +"profile_details" = "Détails du Profil"; +/* Profile button */ +"logout_button" = "Se déconnecter"; + +/* QR code screen button */ +"qr_close_button" = "Quitter"; + +/* Chat screen placeholder */ +"chat_no_chats" = "Il n'y a pas de conversations"; +/* Chats screen message text */ +"chat_outgoing_file" = "Fichier sortant :"; +/* Chats screen message text */ +"chat_incoming_file" = "Fichier entrant :"; +/* Chats screen message text */ +"chat_call_finished" = "Appel terminé"; +/* Chats screen message text */ +"chat_unanwered_call" = "Appel manqué"; +/* Chat button */ +"chat_send_button" = "Envoie"; +/* Chat notification toast */ +"chat_new_messages" = "↓ Nouveaux messages"; +/* Chat call information */ +"chat_call_message" = "Appel, "; +/* Chat call information */ +"chat_missed_call_message" = "Appel manqué"; +/* Item present in the menu on long press on message */ +"chat_more_menu_item" = "Plus"; + +/* Status message */ +"status_offline" = "Hors ligne"; +/* Status message */ +"status_online" = "En ligne"; +/* Status message */ +"status_away" = "Absent(e)"; +/* Status message */ +"status_busy" = "Occupé(e)"; + +/* Notification text */ +"notification_new_message" = "Nouveau message"; +/* Notification text */ +"notification_incoming_contact_request" = "Nouvelle invitation"; +/* Notification text */ +"notification_is_calling" = "appelle"; +/* Notification text */ +"notification_incoming_file" = "Fichier entrant"; + +/* Settings menu / screen name */ +"settings_about" = "À propos"; +/* Settings menu / screen name */ +"settings_faq" = "FAQ"; +/* Settings menu / screen name */ +"settings_advanced_settings" = "Réglages Avancés"; +/* About screen menu */ +"settings_antidote_version" = "Version Antidote"; +/* About screen menu */ +"settings_antidote_build" = "Build Antidote"; +/* About screen menu */ +"settings_toxcore_version" = "Version Toxcore"; +/* About screen menu */ +"settings_acknowledgements" = "Remerciements"; +/* Settings screen menu */ +"settings_autodownload_images" = "Télécharger automatiquement les fichiers"; +/* Settings screen menu */ +"settings_autodownload_images_description" = "Télécharger automatiquement les fichiers entrants."; +/* Settings screen menu */ +"settings_notifications_message_preview" = "Aperçu des notifications"; +/* Settings screen menu */ +"settings_notifications_description" = "Lorsque l'application sera en arrière-plan, vous recevrez encore des notifications pendant 10 minutes."; +/* Settings screen menu */ +"settings_udp_enabled" = "Activer UDP"; +/* Settings screen menu */ +"settings_restore_default" = "Restaurer les Réglages par Défaut"; +/* Settings screen autodownload images option */ +"settings_never" = "Jamais"; +/* Settings screen autodownload images option */ +"settings_wifi" = "Wi-Fi"; +/* Settings screen autodownload images option */ +"settings_using_wifi" = "Utilise le Wi-Fi"; +/* Settings screen autodownload images option */ +"settings_always" = "Toujours"; + +/* Profile settings menu */ +"change_password" = "Changer de mot de passe"; +/* Profile settings menu */ +"delete_password" = "Supprimer le mot de passe"; +/* Profile settings menu */ +"old_password" = "Ancien mot de passe"; +/* Change password text */ +"new_password" = "Nouveau mot de pass"; +/* Change password text */ +"repeat_password" = "Mot de passe encore"; +/* Change password button */ +"change_password_done" = "Fini"; +/* Change password error */ +"password_is_empty_error" = "Le mot de pass ne devrait pas être vide"; +/* Change password error */ +"wrong_old_password" = "Mauvais mot de passe"; +/* Change password error */ +"passwords_do_not_match" = "Les mots de passe ne se ressemblent pas"; + +/* Source of photo to take */ +"photo_from_camera" = "Appareil photo"; +/* Source of photo to take */ +"photo_from_photo_library" = "Photothèque"; +/* Error while converting avatar image */ +"change_avatar_error_convert_image" = "Impossible de convertir l'image"; + +/* Alert text when sending file to contacts */ +"file_send_to_contact" = "Envoyer à un contact"; + +/* Profile menu item */ +"export_profile" = "Exporter le Profil"; +/* Profile menu item */ +"delete_profile" = "Supprimer le Profil"; +/* Delete profile confirmation */ +"delete_profile_confirmation_title_1" = "Vous voulez bien supprimer ce profil ?"; +/* Delete profile confirmation */ +"delete_profile_confirmation_title_2" = "Confirmez-vous ?"; +/* Delete profile confirmation */ +"delete_profile_confirmation_message" = "Cette opération ne peut pas être annulée"; + +/* Call screen text */ +"call_incoming" = "Appel entrant"; +/* Call screen text */ +"call_ended" = "Appel terminé"; +/* Call screen text */ +"call_reaching" = "En attente…"; + +/* File message text */ +"chat_file_cancelled" = "Annulé"; +/* File message text */ +"chat_waiting" = "En attente…"; +/* File message text */ +"chat_paused" = "Pause"; + +/* Deleting chat confirmation */ +"delete_chat_title" = "Vous voulez bien supprimer cette conversation et l'historique des messages ?"; +/* Deleting contat confirmation */ +"delete_contact_title" = "Vous voulez bien supprimer ce contact ?\nL'historique de la conversation va être supprimée."; +/* Deleting contat request confirmation */ +"delete_contact_request_title" = "Vous voulez bien supprimer cette invitation ?"; +/* Deleting single message in chat */ +"delete_single_message" = "Supprimer le message"; +/* Deleting multiple messages in chat. */ +"delete_multiple_messages" = "Supprimer les messages"; +/* Deleting all messages in chat. */ +"delete_all_messages" = "Tout supprimer"; +/* Delete button */ +"alert_delete" = "Supprimer"; +/* Delete button */ +"alert_cancel" = "Annuler"; + +/* Error while creating new profile */ +"login_enter_username_and_profile" = "Veuillez saisir un nom d'utilisateur et un nom de profil."; +/* Error while creating new profile */ +"login_profile_already_exists" = "Un profil de ce nom existe déjà"; + +/* General error title */ +"error_title" = "Erreur"; +/* General error button */ +"error_ok_button" = "OK"; +/* General error button */ +"error_retry_button" = "Essayer de nouveau"; +/* Error */ +"error_contact_not_connected" = "Le contact n'est pas connecté"; +/* Error */ +"error_too_many_files" = "Trop de transferts de fichiers actifs"; +/* Error */ +"error_internal_message" = "Erreur interne"; +/* Error */ +"error_wrong_password_title" = "Mauvais mot de passe"; +/* Error */ +"error_wrong_password_message" = "Le mot de passe contient de mauvais symboles."; +/* Error */ +"error_import_not_exist_title" = "Impossible d'importer le fichier tox"; +/* Error */ +"error_import_not_exist_message" = "Le fichier n'existe pas."; +/* Error */ +"error_decrypt_title" = "Impossible de décrypter le fichier tox"; +/* Error */ +"error_decrypt_empty_data_message" = "Certaines données d'entrée étaient vides."; +/* Error */ +"error_decrypt_bad_format_message" = "Le fichier a un mauvais format ou est corrompu."; +/* Error */ +"error_decrypt_wrong_password_message" = "Le mot de passe est mauvais ou le fichier est corrompu."; +/* Error */ +"error_general_unknown_message" = "Une erreur inconnue s'est produite."; +/* Error */ +"error_general_no_memory_message" = "Il n'y a pas assez de mémoire."; +/* Error */ +"error_general_bind_port_message" = "Impossible de se lier à un port."; +/* Error */ +"error_general_profile_encrypted_message" = "Le profil est chiffré."; +/* Error */ +"error_general_bad_format_message" = "Le fichier a un mauvais format ou est corrompu."; +/* Error */ +"error_proxy_title" = "Erreur proxy"; +/* Error */ +"error_proxy_invalid_address_message" = "L'adresse proxy a un format invalide."; +/* Error */ +"error_proxy_invalid_port_message" = "Le port proxy est invalide."; +/* Error */ +"error_proxy_host_not_resolved_message" = "L'hôte proxy n'a pas pû être résolu."; + +/* Error */ +"error_name_too_long" = "Le nom est trop long."; +/* Error */ +"error_status_message_too_long" = "Le message de statut est trop long"; + +/* Error */ +"error_contact_request_too_long" = "Le message est trop long"; +/* Error */ +"error_contact_request_no_message" = "Aucun message spécifié"; +/* Error */ +"error_contact_request_own_key" = "Je ne peux pas m'ajouter à ma liste de contacts"; +/* Error */ +"error_contact_request_already_sent" = "L'invitation a déjà été envoyée"; +/* Error */ +"error_contact_request_bad_checksum" = "Mauvaise somme de contrôle, veuillez vérifier l'identité Tox saisie"; +/* Error */ +"error_contact_request_new_nospam" = "Mauvais nospam, veuillez vous assurer d'avoir saisi la bonne identité Tox"; + +/* Call error */ +"call_error_already_in_call" = "Déjà participant à un appel"; +/* Call error */ +"call_error_contact_is_offline" = "Le contact est déconnecté"; +/* Call error */ +"call_error_no_active_call" = "Il n'y a pas d'appel actif"; + +/* Error while using color theme */ +"theme_error_cannot_open" = "Impossible d'ouvrir le thème, mauvais format"; + +/* Tab chats badge ending */ +"accessibility_chats_ending" = "discussions non lues"; +/* Avatar button label in settings */ +"accessibility_avatar_button_label" = "Avatar"; +/* Avatar button hint in settings */ +"accessibility_avatar_button_hint" = "Définit ou supprime l'avatar."; +/* Chat button label in contact screen */ +"accessibility_chat_button_label" = "Discussion"; +/* Chat button hint in contact screen */ +"accessibility_chat_button_hint" = "Ouvre la boîte de dialogue."; +/* Call button label in contact screen */ +"accessibility_call_button_label" = "Appel audio"; +/* Call button hint in contact screen */ +"accessibility_call_button_hint" = "Effectue un appel audio."; +/* Video button label in contact screen */ +"accessibility_video_button_label" = "Appel vidéo"; +/* Video button hint in contact screen */ +"accessibility_video_button_hint" = "Effectue un appel vidéo."; +/* Tap to copy hint */ +"accessibility_show_copy_hint" = "Affiche le menu de copie."; +/* Tap to edit value hint */ +"accessibility_edit_value_hint" = "Modifie la valeur."; +/* Incoming message label */ +"accessibility_incoming_message_label" = "Message"; +/* Outgoing message label */ +"accessibility_outgoing_message_label" = "Votre message"; +/* Message shown on chat list when contact is typing */ +"chat_is_typing_text" = "écrit…"; +/* Text shown in chat when there are undelivered faux offline messages */ +"chat_pending_faux_offline_messages" = "Les messages non distribués seront envoyés lorsque vous et votre ami(e) serez en ligne."; diff --git a/Antidote/fr.lproj/import-profile.html b/Antidote/fr.lproj/import-profile.html new file mode 100644 index 0000000..bc36255 --- /dev/null +++ b/Antidote/fr.lproj/import-profile.html @@ -0,0 +1,9 @@ + +

Pour importer votre fichier Tox:

+ +
    +
  1. Envoyer le fichier ".tox" vers votre appareil en utilisant n'importe quelle application (Mail, Dropbox, etc.).
  2. +
  3. Utiliser le menu "Ouvrir Dans" pour ce fichier.
  4. +
  5. Sélectionner Antidote de la liste des applications disponibles.
  6. +
  7. Vérifier le nom de votre nouveau profil et appuyer sur OK.
  8. +
diff --git a/Antidote/iPadFriendsButton.swift b/Antidote/iPadFriendsButton.swift new file mode 100644 index 0000000..2b093be --- /dev/null +++ b/Antidote/iPadFriendsButton.swift @@ -0,0 +1,91 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit +import SnapKit + +private struct Constants { + static let BadgeHorizontalOffset = 5.0 + static let BadgeMinimumWidth = 22.0 + static let BadgeHeight: CGFloat = 18.0 + static let BadgeRightOffset = -10.0 +} + +class iPadFriendsButton: UIView { + var didTapHandler: (() -> Void)? + + var badgeText: String? { + didSet { + badgeLabel.text = badgeText + badgeContainer.isHidden = (badgeText == nil) + } + } + + fileprivate var badgeContainer: UIView! + fileprivate var badgeLabel: UILabel! + fileprivate var button: UIButton! + + init(theme: Theme) { + super.init(frame: CGRect.zero) + + createViews(theme) + installConstraints() + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +extension iPadFriendsButton { + @objc func buttonPressed() { + didTapHandler?() + } +} + +private extension iPadFriendsButton { + func createViews(_ theme: Theme) { + badgeContainer = UIView() + badgeContainer.backgroundColor = theme.colorForType(.TabBadgeBackground) + badgeContainer.layer.masksToBounds = true + badgeContainer.layer.cornerRadius = Constants.BadgeHeight / 2 + addSubview(badgeContainer) + + badgeLabel = UILabel() + badgeLabel.textColor = theme.colorForType(.TabBadgeText) + badgeLabel.textAlignment = .center + badgeLabel.backgroundColor = .clear + badgeLabel.font = UIFont.antidoteFontWithSize(14.0, weight: .light) + badgeContainer.addSubview(badgeLabel) + + button = UIButton(type: .system) + button.contentHorizontalAlignment = .left + button.contentEdgeInsets.left = 20.0 + button.titleEdgeInsets.left = 20.0 + button.titleLabel?.font = UIFont.systemFont(ofSize: 18.0) + button.setTitle(String(localized: "contacts_title"), for: UIControlState()) + button.setImage(UIImage(named: "tab-bar-friends"), for: UIControlState()) + button.addTarget(self, action: #selector(iPadFriendsButton.buttonPressed), for: .touchUpInside) + addSubview(button) + } + + func installConstraints() { + badgeContainer.snp.makeConstraints { + $0.trailing.equalTo(self).offset(Constants.BadgeRightOffset) + $0.centerY.equalTo(self) + $0.width.greaterThanOrEqualTo(Constants.BadgeMinimumWidth) + $0.height.equalTo(Constants.BadgeHeight) + } + + badgeLabel.snp.makeConstraints { + $0.leading.equalTo(badgeContainer).offset(Constants.BadgeHorizontalOffset) + $0.trailing.equalTo(badgeContainer).offset(-Constants.BadgeHorizontalOffset) + $0.centerY.equalTo(badgeContainer) + } + + button.snp.makeConstraints { + $0.edges.equalTo(self) + } + } +} diff --git a/Antidote/iPadNavigationView.swift b/Antidote/iPadNavigationView.swift new file mode 100644 index 0000000..b3ff6dc --- /dev/null +++ b/Antidote/iPadNavigationView.swift @@ -0,0 +1,73 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit +import SnapKit + +private struct Constants { + static let Width = 200.0 + static let Height = 34.0 + static let Offset = 12.0 +} + +class iPadNavigationView: UIView { + var avatarView: ImageViewWithStatus! + var label: UILabel! + + var didTapHandler: (() -> Void)? + + fileprivate var button: UIButton! + + init(theme: Theme) { + super.init(frame: CGRect(x: 0.0, y: 0.0, width: Constants.Width, height: Constants.Height)) + + createViews(theme) + installConstraints() + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +extension iPadNavigationView { + @objc func buttonPressed() { + didTapHandler?() + } +} + +private extension iPadNavigationView { + func createViews(_ theme: Theme) { + avatarView = ImageViewWithStatus() + avatarView.userStatusView.theme = theme + addSubview(avatarView) + + label = UILabel() + label.font = UIFont.systemFont(ofSize: 22.0) + addSubview(label) + + button = UIButton() + button.addTarget(self, action: #selector(iPadNavigationView.buttonPressed), for: .touchUpInside) + addSubview(button) + } + + func installConstraints() { + avatarView.snp.makeConstraints { + $0.top.equalTo(self) + $0.leading.equalTo(self) + $0.size.equalTo(Constants.Height) + } + + label.snp.makeConstraints { + $0.leading.equalTo(avatarView.snp.trailing).offset(Constants.Offset) + $0.trailing.equalTo(self) + $0.top.equalTo(self) + $0.bottom.equalTo(self) + } + + button.snp.makeConstraints { + $0.edges.equalTo(self) + } + } +} diff --git a/Antidote/icons8-key-1024.png b/Antidote/icons8-key-1024.png new file mode 100644 index 0000000000000000000000000000000000000000..8ca885e53469ce8a53d8ae898265cb11d5df67be GIT binary patch literal 36420 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 C8;{ul literal 0 HcmV?d00001 diff --git a/Antidote/isotoxin_Calltone.aac b/Antidote/isotoxin_Calltone.aac new file mode 100644 index 0000000000000000000000000000000000000000..9756d55aa106a806df4038de4207bdfd83153823 GIT binary patch literal 60757 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 literal 0 HcmV?d00001 diff --git a/Antidote/isotoxin_Hangup.aac b/Antidote/isotoxin_Hangup.aac new file mode 100644 index 0000000000000000000000000000000000000000..0f913c544285ba5d19681837f9cd9491cc6b3742 GIT binary patch literal 38229 zcmeI5cU+Utmhhj1&`T1Up@-g)B26KNCRIU@CZGtYfJjxO6Cgl9x-=0K6_GAY1Vso< zngR+|R8WvEO=*hqCZH1U@9y4r_kQl~UE%qI%y~#=GT-OSoHOUlz}kudMy!677fFuH z;aI~1+t)7wipiK?<^NK_eeDO-{R)F*00O{61o0DtXI)`lt}xGcrgg&O!S5@kzD-h| zyP%=_=-i&Y2w35mr*e_%anxK!K{3~C3M*@tFwJ$Bma36Kxpi{qc5{ZZt=WH zH4cuO+>i`!8|%r`}At4s~Fa z*B=)^tO)+BXF1K~VmIgh&>=+Di&VQWpHDA*K)40imL#o43NudUbXdm$R7wfU#>p)y1wrwgQjW@8^`VHd#sTLR$twlCDXmkT*dvyJlEDMRoCl|Dlj3Kd$n45dZe?tM=Nnc5E6sjM&19vx zupxe%6;EZ#0hOnDwut(udB;yPtN&*@{V)HbgPTxQh>bDQ>=8{s$xi351cCT!lZKMg zHN72Z9o%={bTTY}da9colc9WIg~@HEgw58kVp!UqY1hFB*zlpS_O+4|Htl&m>}ttkM?=uo{_H~G3!$%DJN zeu|{(EnOtTY^v(U_}3GcA*d=E^q$VE#_eGDpV6Q<-1^ z#~RAsa~C_YFjLDYCM>9KI}Rjjgi!hmR4Wd`qzYnI(HMF&R?;)w2s_j4Cv}~>F(Av$ zl_E)OeF89vPh4{GB6I3n!=!`XQuOe2416J}b&D5&SSo`3|2h6yBas2N;LvgD6>05+Ve_3^*%RKZgt5CP|_?EU9yPWxQ(SdpRJm(RT)=JLs2k%A_urx=?XwY zPyOlRn2vk9t<3OT5TD?cP`y6=YOm-0<=@ZBFkN_WR~_q2qchvY7kien;|}kGR{p)q z-_>jazv8o?Eo%~vGqYP6DFBc_9bAVxB92H3OD&qK$8YJF;=ZXs?po}0~jfuRN z)aMc!bX1RV#~+2AdvQnmZrBH9(}_L>isR$Fksg&#v$lz@GyL&`9rH`tbX9*)HM0~6 z$Q8Y=b_m$@r7y?Mvwt7$?Q*l~fXQXJarVlA$1PzO$-uiCD;7US=D6S4HdMbz5(+1O z2!9#>tfqokf~wNo0GwXTHY){-30{pVzrI8tKpC7-ZI`7spDsmE*7O}Wp8Cd3Y+HX) zrhfx<-Tvc=Z(szA^Ch56O1vx_(H%#qC73h7{0;A)=b-AT`VrAxJP7~qyGuOB1a=3! z`#$1=gfVe}{q8|zR&^pF58*1}7CWv_i!#}ns#Jdk?tNLWkyz_iyEex^4o~bmfhuD< z$|U=P9i5v)Vns`P8OGxCqISE>)%h&W%vq%W-ZdjtdSqqd`$Y-kdRqCZZEgKcWgLjo z=J@{w6~;oa|IY@)*dAf|ouVLF_N?GiOwrZ(QVO{fEc}dGq5idoeIwbF<}+)*)wk7! zCqDsz@asX9_3@7(-Xv%$jG(D)+z|Q|m*%A}@8zRuwSXd|xJW<&Fp$;(yE{Oo7c@k{ zHb~vzza5|Y$&vUfzbX7mRdGaNhZDfg%X9(bj?U+u7JX($D>m*+i%W~I0V<;p zN&JrQme-bjb$J0C=#Bw8%Ou!{SmhSHHnJ-9#HgwdvHOhPIj{gH=f%~x7?H=8^5Qb6 zubQ|H4VKRK&vkdQjMZf(hac&+9X_*jy3(Y*tf*n`M%6Ch!obL-TWWgnz8W9~-B-+6 zn#JPD-vqdgZ$Y5ME|b`QC8Eq2ZH0(IskzWHQVd*Q7_Ow~YUN99K|3aUSr~-OQ$i7o zR{{ATBe$uqx0Xb<9RMP-UsunM5~=;)fLd;a2zc*N1+acQvcJOS;GGbSM}a$#kg~j{ z4{~?V2P}arjXF6)l=rtYslQ+n3S{o2(vPg_=JzP&GhPEPJ3%x4jsjroK3JA$WPSg6$H;?E1t>3WDL+`X6h=*yaF@ z9e{u$)j?SjiO=_^?3}DlMjOxMS!q@Mke9NB`?k?>fP;onD5a)05CeGEEgd>;+Ye#v7j&D4*Kg;iYzW7Cx<2(9qtKXXPW>6Iyn1?bqzrWC}3flJqRZ&WPFxn93sxw4= zvGUw8+g5=SNtl_`U>SLx&g*~~X2o)7#?_srj>>|wvhfl2_z6bW%y`Bs-FAV4mf9ET z>#MgW&h=jZm{d38e{iI@cmfK&qs=wZvaSD2JrCE&$i9qOo}oo)KD3!VVQ&y%oQBcH zOzFO(0hr4Kp9(h>_YL|6V3riOHv#=pq|Nvr4nw>Nw-x71Mj6EnIz25Dm{3h_p)0?w*P#O9 z2u3iE*u8m~DkW-7%`&>dRhwmZmTZ(UX4iD7@XcWXcf+8(jM|WN?b9LOJMrLjx9v0l z2~nUKAo2eL5+i!y}$GXHhzk)+;sQV_DeE+LD!E zDDksq~4_IbpeeZ=$ z_aY}=oO6bqnXLPM4?N2x-KLoq_U_|~rCI%(xn=tp8VV+7gQXmw`?|3mW%=hl(tMGS zDas(VZ`Nc&T@Qpk&ZwVQ2p^6p5BM7K!4jg7`TgWR-S;mPcQ5E0Cc)i8|J|P0Mo^Vt z|NXHxnGblxJiDsEG4|C#_g?SP(XrynTz#r)a^QLscZ9+V9`=)*v3elm(i5?9rhrkTg;SeiCt79UQ) zhp~+xnrNT|>NYn6ve-FO)LH{mdAH+zq?$tJqeCigmVb?Z4y-g0>aclTsFq^gC?ljC z(KHOuwVMSn+C&^wJ``mu=py(reRUw;z`{pu`~WQWyjM2l?iD&x`P+KJYu8&u9Pa^aam0Uj)-Q^%Hxv` z9BH?7^5F^g`SaQR$2}w&|ACijc-Uz8Q^{ zekmsEnU%VlGPdIE$tZKx$b^LjK4ZbhwhdRiC~-(^j%@J zlmUqp4iS25CoIZ&3$grwne>;-(yHT!N2K^ft+xGrQVmfIBb9!ZfBF9$I5hDdBbbm? z9Rw5t2jj2ELpHwZ@ zRTYWkFql8Df7n3zle5*XwY< zo_d&$x$*!I5>XX+`|6%wTK#ZxnWMf>-K)kV?NiodbLe1s2ZEsbRYQFc_Zy#0N)EpA0>K9a{ zfE&+mCP-%oRNt?cNEQ0rYyn2%)?=!bnM0Tz?ZdZ2Q$+xJt~Z*(o?NN-=dV+2r>-`M z0stLyBU44R|39JXBMF+iyo*l9?NaxR+ZN>}PwBuF)MP_`{$}*#+#Y<(m$?B-$(81O zlbh!$3%3)jq&z9yH>8cMD$!JJP=z<@BLjwB9q|vzY#!;oze7`U5Q*Q&rX*Dy6t!-~ zTm_i>v>2&8e2g1zb!YOJY}b!)FZ%+%X`z!O)nPEL7InfF7VEB63|Ab~a8;!ed~W$5V$AJ!!%WS-b}FT}H>5!Z z)89);TiZ(I&HO)(5K$#$st8bzysjNBDZoJV-`zW(j~kS*pA^Wsc7(%kg2Hc}17SF< zeN(UnRt%a?JGIo6=O0NMA@gjn*Tg*N808LmTOCsfH3M~h?N);Lw|ymbRi$YjKx`vB zMq5jJ3wRkBGO7>{^dE>lq!`??d`J9k!lG#&+<>NBCd*#B+Wz>KU9+_aWrhf~13a?r0VkRAS79sR3-R_5 zp)p@Tk=q997eGRRVs?F$Z{8vq|7hY}*q}IDGRkZWd2)eKZp7%6qzmdUy3-z-dG^2= z@-?=EXZjLrVS^8&x9!s=L&9pcnpFC2sVYL#Oimd8Ga*Xz1^r~bN9H0yFAp7?7d(h0 zZ!*t)`P~nh+I+zwD-R z>HFl}ZMMI$O&~}lPSwVyDuSxQ^H4kZbFR@jUsh{5Q(e)o$)XMvsb?=+QKE(SYS>4s zQ7+)bwpsqhvXWH#0hPG^-#AnW1H{>LP&<%4)O@AXv@7q8nk%J;xu=n!ZcoB2(A+RD zek_kJIzj)F`unhe?OXsUOJEn~r?}~=;~3`2}Su+?{I$~B=P^(Bh_#h zeQ_$3)|34$7;>eixEU=ze%P7N09p>Cgha^n5m1~&dZi9cGhaDn#|JsIL(-V_f|K;) z7kh`>G_Hxxw!aN6yyYos{;-ci*bsw$2SD7^dD1{7B&*84_G zFV*4V>|(x}DRZnXCm2L%Y`b%R#vFc^xqaCHExY$af321y0@hiXm-f ztCmTestu^wgh_Qgo${C(O@5?M)RQ`~t`=x)-?=ZVpN0Vl&B;s#$%?)0;k?bumYn4C zlq~0^3hvkQ+zQ;e-=v6pjku)PzJR~A|1dmZr^+ajqgVQd&&TrjKq`8r1LXc5oo;A$ zDqB@5X4^*nrZjGpzllGEznUrn)e*qHp+hIsj0!E7fbzNrDx43JNFAaZOMA(awmpyj zL`Qrj^N}VMf0X~SsRE;qL^Se{#T^EY1$;`;Q#Z;7U-qYhl(U7sv%L?ve(0#e*$eiM z3wTtYH_>Q;GHmY${*9_EQ6jPb8%fn?-UO$LlG~u0TMYx;P`RAsA#ef52RKm{JQQYi z9aweDYEAGvdBvdb5M?;6qa0=9WTby?0su+k1u{b)uQHxGacL?heSUYl^5fh0T*Bkt zG`ykpm>K-7m})_@EPogRJ$&00$(!M6B)q& z@f=Az2*Uq5RQ)Tc%9o7VXNsd=lM|$8yvo4EoUM9U<$Msx;t}s`R$^##3X1CTxdeEV za^snKS3qhz5cnHUq6hSs_#YG_&RM$)0Ery%*NnbhQFG|%$sM5w>U$Ofzyf6EAuv$# zr>c;1CJ|HSGG$Zb_UC{eUUvWjb+C|Cxg}^nan7%%xbV@yju&3ewm@s13()2H0&?JB z#4Q@$;NXGZLXV{19sA|+8v2QTKsmeTttKd>~9rwdYQ;1UZ$BUsma=DkfUp?jM zVY$UPHQwmgnia$FY23~kK1FVKE)>Cw1SrA-Q+6h zfPA(9FV}Q_x8h1XmcejG<=D#sz)aqq4b1El%R);Y)jit&;ErAXagRWhyUJH%z)uLx zG6#~+C~;3Oy2Tjxt>+IXNz%Pd|37vEs;#&P4detEfi{5U0j%)RB)-ldn)MiI6Evu_@s>^B_ty6p1Ke*9fmDJ#DRvxu{Gda|<0hWvA}*H!0K(Yb zHUpK~}=(kRbf8TXjuwe`{@eiPfefirLnWi+>a>?-vMS<1$Tm{Jymthe=L#nP=8{HkH(c0%AMOX4dTlJH~G|NjA1Awo$K%;Z#1)U`tc4ayKYq3xSkf&&SO z#1!6+iqgVW_ICxUoIU&OcDOSDqTEGod2)ev;7%r3iNlsWluRw+vR`Y=EipYbkYCou z2UiXNu7LX(BN=fK`=ct|bG(veYj%e+r;4*_@pg)YB*{^#sq`JIw``qjEs@iXbGt+Q zV*lr_P5(a*3G7`aEUJVAaSxiZ%aBNB7&#TAJ4kH4M3EX}8T{4$RgTdU&hTWgHT2t! zaedQQCJd%jns?t+hF9H1G{-b*DDHM=ytwhi|HlFARCD#kSsGg~*?19T`qRQRnBd{uL&j7jO5Bo^aFX)T3AI z!Go#H?+B&z-^Ua=>cMD2AApb;2^bAT0DibiKt@`TaOmhH^PSW_pB*jU1Ec;0_%`+k z&g}b+w9W^2e#7YZ22QdiH&H)U!r>YQEucsOBPOc23#o)(yp4%>Opd zjrKR4D#B^Ny_-v7aw=7gd-J8b8lu?(r_aq@oD??@&JG_M#Y^TF zYl}?o8VbD1!9P!?`U(c&SCbVGQ9ExX*KL)kEG2r2^Xb|HSgxGDRplo)OodtH$R145 z2|Z@|1h6^;!_3H%aFx33f#K-}st-@&%#OZ^L41i$>`^j1cnTxlMdfCc#7~v`b}FTo z+wYBdlHp{y&*P^_J;O#2oaTp>wfv*|J+xe?8RiakA2s#NMi(-Yr@vkP_W(-x79{pR z8oai)20$b9`B-oo$9S=rcg2W0W117`OtxI{BQWiJrPYg{a%xUUo!E1FZRq7GB?^rr ziKgBeH^|LPJGoR;FOI)q4c!G(rbuMI!Qyi0YHkOP`AAuH)@jpV|J|ikW3RPPd{3eK zK~3LJ6%|icI)aA6ygd)##r4?`{FG#}Gh#F`RAxr%ZOH;Ytb>;&;unr3NN1gJr{6bs zk4q9CL9Nqr!GU~)XZSkA+)O+o7j$@4!ROqE=76&?y%*SuD#`*(9^X8>Qy>ku6D2MC z(m;XAlNApt($?pQ9g^eGuX&|FSbXzRnKNH{`md+Ixm7i4V^&SAk%NI7f$T;Gh&QXUAP)th!?_^E z&kAy<1!eJ|gY7b-=%l^I$%4mY8`flxnZMAzE2?loP#NON(@RfJy~EzZOs{-}2LS3C zSRy7Wq18#>q__k8rkq(J(`sevMsgnf-hMV_(mNlay)W&X`S~CD{`DY9TOgTKaqE++ zclALWBm~F~l>{z`qd98vz+B)-d&V2ED|G#d?P$JtJy$Wqz3?#3nDjd7X{Dof_ikzG zP0<5Jn68K!cF3~}-Qf*d`2%^KlJByoMB1q#+{Pm+9UhkhGC>);kH%W;m3}PmYi7M_ ztEx4K01%U~>H%55bgX;+p}M;JPc=27dD|3+ZJWw8 zjYq7#(0E=3 zL9s@AM_95&q7-uo%FlkOGMm~je!q~W%$XUGt7QFyi!Y21@zHhC$lGVJi)k($euMas zHRm__VoqKk$4 zBbV%&I`)%dV)Kpx;tyBaPbBMhoq^z-joF4r$o2@o`|@u2_T%?;b55b<7!f2Kf&^?1 z<%CfUD?9}J=0cg~5lk4^wW|sGn7wI<7@?GaJ61~F9ySXyrIDq1X7+h9z)A1B zl`1ngzeQiQ^P<*Cs!BnMVg^cmE=?q}c(uBHHQ*>~weR-OWm{#vXz3KzPKL$Vzv<`y zsJM};BCh`l@jn7ohG*_9RFHNc8%=PkK;bdBDaX<5L50F$?;V`wzjE^#BxQ1(j&-%yo4T?lYbv1U?G{i3k?Kt9=yJ(o-sQ0Ed z2BU^61`xCo6d^!DC}oTM8;?SKQgUVw?sR2xa_4y;B^QdvaHIdC?+S#&6w&f_J&JU1hQZ&_yrR7QL6$MB|Vdp#IRX7is2+Ct(~0q6RT$PDgx@9{1_HS zuDd)sN;K(CmTFEx(NTggo{fpdqH?c8 z!*KeQ_pUcQOQ`m57r4=8j!1GG$QILsWTrXRf^RCW$7w%LS?+u=%t3zRxEG>!|)m_3$4zMiT#zqYPeK#y}O! z4l5xcfS6de5xGt*nHT=%$2achazB7rcZGXBK6HylhDua&A^+_zw`<&%XPpefCz)T( zWxL0fr~0Zw4CaQO3l>`6g7#6VWtx^wYP4KBk`{mJCSz%w`miw z4w5|qY3gA|3 zRlpj|wx1mGk$i9}C9CaLRR!85F(5(2018U1E`MS9)Ek)-|8{Nk+qbX(_%Z(p@7T2eVS_Zy#b89}v@ev8C0o(YD6!h81u#zl zl=k5nmL9yzoST_FicVGIr=n=2FE492j^#FY9MWN^qS6st8dPv^djcx)u${rNVLx_`Z(_w%{5uW@mNh!-r2`RcCs$I63G- z@{F<>k{SW&UG12W_yMU{^Rc%A$2@|^*mL!Fo}-!Q#N<8$%5M}jo9)ecKUV1fZb`kq z->j>L>Eqb_g{JQk2b=P;yG|x>rD$t}Wv_<-gg`sOJ6zEak)?5jLfhF2Sgb*`fSQ4- z3h4200+5~H7Hx^Je0fHiir2?hirV4YrNd5RPgzIX;}A^fzWlIq*O21wT#mAH?b59D zE;*5xT8d_NynXiHr}EEz^2btjJ^oLGih&}3rhhW$jF(H<+sZ50h~9g3`JnQ9p*5#8XM6>}h3+jnQuxYavj08ipX>a;?9&@7 zRigcmL$7NpYsM)=1eD^A^D{m8K8r33{)#tN*4I`g zR;yKs7&u+kKxzC9dwrzLuk~;kPjMxN1_ExPF8T6CnB#r2X$nRF_DpWtFz2M&1z1$9 zvYfOb2HiDFZJ2|0L`o;<>d>)jq&-{v)HS%aRytLwbQ9q>TI5WgTyr#k?)zTUnjCeq z$HS}k*n2_dw?{vz6`9LIYt-WO4NtYc7=4OKQm=96dAj4JnlEECP8yx^F#2Iy7A-{A z_@MC&`QLdqn@iPrG$2h(RpTtELlL_>ZCpQ^@JR!_$6llE83f)tU&qF2pL6E4>^M#S z@pD%BP1i5ne)ULjzp3c~M}4h~i#h50clD|tmMCu*GTtv|FGuzq;JauUicN4{bl^0ssI2 literal 0 HcmV?d00001 diff --git a/Antidote/isotoxin_NewMessage.aac b/Antidote/isotoxin_NewMessage.aac new file mode 100644 index 0000000000000000000000000000000000000000..90af8097c4374b6f7511e9701131f3a5fcffb2a8 GIT binary patch literal 8874 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 +

To import your Tox profile:

+ +
    +
  1. Send the ".tox" file to your device using any app (Mail, Dropbox, etc.).
  2. +
  3. Use "Open In" menu for this file.
  4. +
  5. Select Antidote in a list of available apps.
  6. +
  7. Check the name of your new profile and press OK.
  8. +
+
diff --git a/Antidote/lt.lproj/InfoPlist.strings b/Antidote/lt.lproj/InfoPlist.strings new file mode 100644 index 0000000000000000000000000000000000000000..9c184dfdde5f09f729beee1a3216357091704d77 GIT binary patch literal 1074 zcmb`G%}&Bl5Jo??CcZ<{B{3i-x-l*YB*sJyYINUPga&8{EhPFzzNC6)s)D2|VR5H3 z)0s0rz5V=XtEoT-oIqE~^rBn?O_i!psg}zHR;Cep71zZo@g>BT8se?|JuR>z_a*RR zy(0UX@ho|lV?7~Fi^${r2N7plth=^Yj9Z_wF9>KFrtDB$|dUpC8k4<2` zSFBLCdeA26@t4!D%?!!C;DoyLIw?%6nPDxzw`<=apznxkZ|)25Ot5F{aH+#a>hB62 z5myjZH0;Zz&RNo-ZQgj6W2_W=o7iqxOw_Q+E6#*YGO{e+Sa-TdPOuZa1v?CNzOlg@ zqHHtvwZ_QIC)s6_b;SK`G-lo@bJ(4%+erP6x2GQXtff=zpNW0f3%~cf%)aJc|DpbO K{(anwYW6R% +

Norėdami importuoti savo Tox profilį:

+ +
    +
  1. Siųskite ".tox" failą į savo įrenginį, naudodami bet kurią programą (Paštą, Dropbox ir t.t.).
  2. +
  3. Šiam failui naudokite meniu "Atverti naudojant".
  4. +
  5. Prieinamų programų sąraše pasirinkite Antidote.
  6. +
  7. Patikrinkite savo naujojo profilio pavadinimą ir spauskite Gerai.
  8. +
diff --git a/Antidote/nb.lproj/AppStoreLocalizable.strings b/Antidote/nb.lproj/AppStoreLocalizable.strings new file mode 100644 index 0000000..d6fbb04 --- /dev/null +++ b/Antidote/nb.lproj/AppStoreLocalizable.strings @@ -0,0 +1,54 @@ +/* + AppStoreLocalizable.strings + Antidote + + Created by Dmytro Vorobiov on 08/02/17. + Copyright © 2017 dvor. All rights reserved. +*/ + +/* Name of friend for the App Store screenshot. Should be fully random, no real people here. Can be generated with service like http://www.fakenamegenerator.com/ */ +"app_store_screenshot_friend_female_1" = "Mary Cokley"; +/* Name of friend for the App Store screenshot. Should be fully random, no real people here. Can be generated with service like http://www.fakenamegenerator.com/ */ +"app_store_screenshot_friend_female_2" = "Shirley Knox"; +/* Name of friend for the App Store screenshot. Should be fully random, no real people here. Can be generated with service like http://www.fakenamegenerator.com/ */ +"app_store_screenshot_friend_female_3" = "Jennifer Smith"; +/* Name of friend for the App Store screenshot. Should be fully random, no real people here. Can be generated with service like http://www.fakenamegenerator.com/ */ +"app_store_screenshot_friend_female_4" = "Marina Dixon"; +/* Name of friend for the App Store screenshot. Should be fully random, no real people here. Can be generated with service like http://www.fakenamegenerator.com/ */ +"app_store_screenshot_friend_female_5" = "Carol Ortega"; +/* Name of friend for the App Store screenshot. Should be fully random, no real people here. Can be generated with service like http://www.fakenamegenerator.com/ */ +"app_store_screenshot_friend_male_1" = "Michael Sharpe"; +/* Name of friend for the App Store screenshot. Should be fully random, no real people here. Can be generated with service like http://www.fakenamegenerator.com/ */ +"app_store_screenshot_friend_male_2" = "Charles Donahue"; +/* Name of friend for the App Store screenshot. Should be fully random, no real people here. Can be generated with service like http://www.fakenamegenerator.com/ */ +"app_store_screenshot_friend_male_3" = "Lee Murdock"; +/* Name of friend for the App Store screenshot. Should be fully random, no real people here. Can be generated with service like http://www.fakenamegenerator.com/ */ +"app_store_screenshot_friend_male_4" = "Wayne Henderson"; +/* Name of friend for the App Store screenshot. Should be fully random, no real people here. Can be generated with service like http://www.fakenamegenerator.com/ */ +"app_store_screenshot_friend_male_5" = "Robert Newton"; + +/* Demo conversation for the App Store screenshot */ +"app_store_screenshot_conversation_1" = "Is Antidote really that secure?"; +/* Demo conversation for the App Store screenshot */ +"app_store_screenshot_conversation_2" = "sure, it is peer-to-peer"; +/* Demo conversation for the App Store screenshot */ +"app_store_screenshot_conversation_3" = "And what does that mean? Peer-to-peer? 😄"; +/* Demo conversation for the App Store screenshot */ +"app_store_screenshot_conversation_4" = "you text me directly, the are no servers or things like that"; +/* Demo conversation for the App Store screenshot */ +"app_store_screenshot_conversation_5" = "+ it's encrypted 🔐😎"; +/* Demo conversation for the App Store screenshot */ +"app_store_screenshot_conversation_6" = "Cool!"; +/* Demo conversation for the App Store screenshot */ +"app_store_screenshot_conversation_7" = "I'll give it a go then"; + +/* Demo chat message for the App Store screenshot */ +"app_store_screenshot_chat_message_1" = "😂😂😂"; +/* Demo chat message for the App Store screenshot */ +"app_store_screenshot_chat_message_2" = "dinner tonight?"; +/* Demo chat message for the App Store screenshot */ +"app_store_screenshot_chat_message_3" = "I think I know what you are talking about"; +/* Demo chat message for the App Store screenshot */ +"app_store_screenshot_chat_message_4" = "Sure, thanks!"; +/* Demo chat message for the App Store screenshot */ +"app_store_screenshot_chat_message_5" = "yep"; diff --git a/Antidote/nb.lproj/InfoPlist.strings b/Antidote/nb.lproj/InfoPlist.strings new file mode 100644 index 0000000..b79a4d0 --- /dev/null +++ b/Antidote/nb.lproj/InfoPlist.strings @@ -0,0 +1,16 @@ +/* + InfoPlist.strings + Antidote + + Created by Dmytro Vorobiov on 15/11/16. + Copyright © 2016 dvor. All rights reserved. +*/ + +/* Camera usage alert description */ +"NSCameraUsageDescription" = "You can use video calls, send photos and videos, scan QR codes."; + +/* Microphone usage alert description */ +"NSMicrophoneUsageDescription" = "You can use audio and video calls."; + +/* Photo library usage alert description */ +"NSPhotoLibraryUsageDescription" = "You can send photos and videos."; \ No newline at end of file diff --git a/Antidote/nb.lproj/Localizable.strings b/Antidote/nb.lproj/Localizable.strings new file mode 100644 index 0000000..227bc2b --- /dev/null +++ b/Antidote/nb.lproj/Localizable.strings @@ -0,0 +1,398 @@ + + +/* PIN screen screen */ +"pin_lock_1_minute" = "1 minutt"; +/* PIN screen screen */ +"pin_lock_2_minutes" = "2 minutter"; +/* Tab name and screen name */ +"chats_title" = "Sludringer"; +/* No contacts placeholder text */ +"contact_no_contacts_share_tox_id" = "del din Tox-ID"; +/* Contact request section title */ +"contact_requests_section" = "Kontaktforespørsler"; +/* Screen name */ +"contact_request" = "Kontaktforespørsel"; +/* Status message */ +"status_busy" = "Opptatt"; +/* Incoming message label */ +"accessibility_incoming_message_label" = "Melding"; +/* Deleting contat request confirmation */ +"delete_contact_request_title" = "Slett denne kontaktforespørselen?"; +/* Call button label in contact screen */ +"accessibility_call_button_label" = "Taleanrop"; +/* Call button hint in contact screen */ +"accessibility_call_button_hint" = "Utfører et taleanrop."; +/* Contact request button */ +"contact_request_accept" = "Godta"; +/* Add contat placeholder text */ +"add_contact_default_message_title" = "Melding"; +/* User public key text */ +"public_key" = "Offentlig nøkkel"; + +/* Chat screen placeholder */ +"chat_no_chats" = "Ingen sludringer"; +/* Contact request button */ +"contact_request_decline" = "Avslå"; + +/* Share Tox ID text */ +"show_qr_code" = "Vis QR-kode"; +/* Login screen text */ +"create_profile" = "Opprett profil"; + +/* PIN screen text */ +"pin_enter_to_unlock" = "Skriv inn din PIN for å låse opp"; +/* Add contat button */ +"add_contact_send" = "Send"; +/* Add contat placeholder text */ +"add_contact_tox_id_placeholder" = "Skriv inn Tox-ID"; +/* Add contat placeholder text */ +"add_contact_or_label" = "eller"; +/* Add contat button */ +"add_contact_use_qr" = "Bruk QR-kode"; +/* User nickname text */ +"nickname" = "Kallenavn"; +/* User status message text */ +"status_message" = "Statusmelding"; +/* User Tox ID text */ +"my_tox_id" = "Min Tox-ID."; +/* Chats screen message text */ +"chat_outgoing_file" = "Utgående fil:"; +/* Chats screen message text */ +"chat_incoming_file" = "Innkommende fil:"; +/* Chats screen message text */ +"chat_call_finished" = "Samtale avsluttet"; +/* Delete profile confirmation */ +"delete_profile_confirmation_title_2" = "Er du sikker?"; +/* Deleting all messages in chat. */ +"delete_all_messages" = "Slett alle"; + +/* General error title */ +"error_title" = "Feil"; +/* Login screen text */ +"login_or_label" = "eller"; +/* Login screen text */ +"create_account" = "Opprett konto"; +/* Login screen text */ +"import_profile" = "Importer profil"; +/* Password field */ +"password" = "Passord"; +/* Login screen text */ +"create_account_username_placeholder" = "Brukernavn"; +/* Chats screen message text */ +"chat_unanwered_call" = "Ubesvart samtale"; + +/* Notification text */ +"notification_new_message" = "Ny melding"; + +/* Settings menu / screen name */ +"settings_about" = "Om"; +/* Settings menu / screen name */ +"settings_faq" = "O-S-S"; +/* Settings menu / screen name */ +"settings_advanced_settings" = "Avanserte innstillinger"; +/* About screen menu */ +"settings_antidote_version" = "Antidote-versjon"; +/* About screen menu */ +"settings_toxcore_version" = "Toxcore-versjon"; +/* Login screen text */ +"create_account_username_title" = "Hvordan kontakter vil se deg."; +/* Login screen text */ +"create_account_profile_title" = "Hvordan skal denne profilen ringes?"; +/* Login screen text */ +"set_password_hint" = "Passord krever for å beskytte dataen din. Ta vare på det siden det ikke kan gjenopprettes."; +/* Default status message */ +"default_user_status_message" = "Toksikalerer på Antidote"; +/* PIN screen message shown on log out */ +"pin_logout_message" = "For mange mislykkede forsøk. Du har blitt utlogget."; +/* PIN screen screen */ +"pin_description" = "Forhindre uautorisert tilgang til Antidote med en PIN."; +/* Contact last seen status */ +"contact_last_seen" = "Sist sett: %@"; +/* Add contat default text sended to contact */ +"add_contact_default_message_text" = "Hei. Kan du legge meg til på kontaktlisten din?"; +/* Add contat error */ +"add_contact_wrong_qr" = "Feil QR-kode. Den skal inneholde en Tox-ID."; +/* Chat notification toast */ +"chat_new_messages" = "↓ Nye meldinger"; +/* Chat call information */ +"chat_call_message" = "Anrop, "; +/* Chat call information */ +"chat_missed_call_message" = "Tapt anrop"; +/* Status message */ +"status_online" = "Pålogget"; +/* Status message */ +"status_away" = "Borte"; +/* About screen menu */ +"settings_acknowledgements" = "Bidragsytere"; +/* Profile settings menu */ +"old_password" = "Gammelt passord"; +/* Change password text */ +"new_password" = "Nytt passord"; +/* Error while converting avatar image */ +"change_avatar_error_convert_image" = "Kan ikke konvertere bilde"; +/* Settings screen menu */ +"settings_autodownload_images_description" = "Last ned innkommende bilder automatisk"; +/* Settings screen menu */ +"settings_notifications_message_preview" = "Merknadsforhåndsvisning"; +/* Settings screen menu */ +"settings_notifications_description" = "Når programmer blir relegert til bakgrunnen vil du fremdeles få merknader i 10 minutter."; +/* Settings screen menu */ +"settings_udp_enabled" = "Skru på UDP"; +/* Settings screen autodownload images option */ +"settings_using_wifi" = "Ved bruk av Wi-Fi"; +/* Change password error */ +"password_is_empty_error" = "Passordet kan ikke være tomt"; +/* Change password error */ +"passwords_do_not_match" = "Passordene samsvarer ikke"; +/* Source of photo to take */ +"photo_from_photo_library" = "Bildebibliotek"; +/* Delete profile confirmation */ +"delete_profile_confirmation_message" = "Denne handlingen kan ikke angres"; +/* Error */ +"error_too_many_files" = "For mange aktive filoverføringer"; +/* Error */ +"error_internal_message" = "Intern feil"; +/* Error */ +"error_wrong_password_title" = "Feil passord"; + +/* Error while creating new profile */ +"login_enter_username_and_profile" = "Skriv inn både brukernavn og profilnavn."; +/* Error */ +"error_contact_not_connected" = "Kontakten er ikke pålogget"; +/* Error while creating new profile */ +"login_profile_already_exists" = "Profil med angitt navn finnes allerede."; +/* Error */ +"error_wrong_password_message" = "Passord inneholder ulovlige symboler."; +/* Error */ +"error_general_unknown_message" = "Ukjent feil oppstod."; +/* Error */ +"error_contact_request_new_nospam" = "Feil NoSpam-verdi. Sjekk innskrevet Tox-ID."; + +/* Call error */ +"call_error_already_in_call" = "Allerede i en samtale"; +/* Chat button label in contact screen */ +"accessibility_chat_button_label" = "Sludring"; +/* Chat button hint in contact screen */ +"accessibility_chat_button_hint" = "Åpner sludringsdialogen."; +/* Video button label in contact screen */ +"accessibility_video_button_label" = "Videosamtale"; +/* Video button hint in contact screen */ +"accessibility_video_button_hint" = "Utfører en videosamtale."; +/* Tap to copy hint */ +"accessibility_show_copy_hint" = "Viser kopieringsmenyen."; +/* Tap to edit value hint */ +"accessibility_edit_value_hint" = "Redigerer verdi."; +/* Outgoing message label */ +"accessibility_outgoing_message_label" = "Din melding"; +/* Settings screen menu */ +"settings_autodownload_images" = "Auto-nedlastede bilder"; + +/* Call screen text */ +"call_incoming" = "Innkommende anrop"; +/* Contact request confirmation */ +"contact_request_delete_title" = "Slett kontaktforespørsel?"; +/* PIN screen error */ +"pin_incorrect" = "Feil PIN"; +/* Tab name and screen name */ +"settings_title" = "Innstillinger"; + +/* Deleting chat confirmation */ +"delete_chat_title" = "Slett denne sludringen og meldingshistorikken fra den?"; +/* Settings screen menu */ +"settings_restore_default" = "Gjenopprett forvalgsinnstillinger"; +/* Settings screen autodownload images option */ +"settings_wifi" = "Wi-Fi"; + +/* Profile settings menu */ +"change_password" = "Endre passord"; +/* Profile settings menu */ +"delete_password" = "Slett passord"; +/* Change password text */ +"repeat_password" = "Gjenta passord"; +/* Change password button */ +"change_password_done" = "Ferdig"; +/* Change password error */ +"wrong_old_password" = "Feil passord"; + +/* Alert text when sending file to contacts */ +"file_send_to_contact" = "Send til kontakt"; + +/* Profile menu item */ +"export_profile" = "Eksporter profil"; +/* Profile menu item */ +"delete_profile" = "Slett profil"; +/* Delete profile confirmation */ +"delete_profile_confirmation_title_1" = "Slett denne profilen?"; + +/* File message text */ +"chat_file_cancelled" = "Avbrutt"; +/* File message text */ +"chat_waiting" = "Venter …"; +/* Deleting multiple messages in chat. */ +"delete_multiple_messages" = "Slett meldinger"; +/* Delete button */ +"alert_delete" = "Slett"; +/* Error */ +"error_import_not_exist_message" = "Filen finnes ikke."; +/* Error */ +"error_general_no_memory_message" = "Ikke nok minne."; +/* Login screen text */ +"create_account_profile_placeholder" = "Profilnavn"; +/* Login screen text */ +"set_password_title" = "Sett passord"; +/* Login button */ +"log_in" = "Logg inn"; +/* Login screen text */ +"import_to_antidote" = "Importer til Antidote"; +/* Login screen text */ +"create_account_profile_hint" = "f.eks. Hjemme, iPhone"; +/* Login button */ +"create_account_next_button" = "Neste"; +/* Login button */ +"create_account_go_button" = "Start"; +/* PIN screen text */ +"pin_confirm" = "Bekreft PIN"; +/* PIN screen error */ +"pin_do_not_match" = "PIN stemte ikke overens. Prøv igjen."; +/* PIN screen screen */ +"pin_lock_5_minutes" = "5 minutter"; +/* No contacts placeholder text */ +"contact_no_contacts_add_contact" = "Legg til kontakt\neller\n"; +/* PIN screen text */ +"pin_set" = "Sett PIN"; +/* PIN screen screen */ +"pin_lock_timeout" = "Låsingstidsavbrudd"; +/* PIN screen screen */ +"pin_lock_immediately" = "Umiddelbart"; + +/* Label shown when connecting to Tox network */ +"connecting_label" = "Kobler til …"; + +/* Tab name and screen name */ +"contacts_title" = "Kontakter"; +/* Tab name and screen name */ +"profile_title" = "Profil"; + +/* No contacts placeholder text */ +"contact_no_contacts" = "Ingen kontakter"; +/* Text shown when contact was deleted */ +"contact_deleted" = "Slettet kontakt"; +/* Share Tox ID text */ +"copy" = "Kopier"; + +/* Add contat screen name */ +"add_contact_title" = "Legg til kontakt"; + +/* User name text */ +"name" = "Navn"; +/* User status text */ +"status_title" = "Status"; +/* Share Tox ID text */ +"show_qr" = "Vis QR"; +/* Profile menu item / screen name */ +"profile_details" = "Profildetaljer"; +/* Profile button */ +"logout_button" = "Logg ut"; + +/* QR code screen button */ +"qr_close_button" = "Lukk"; +/* Chat button */ +"chat_send_button" = "Send"; +/* Item present in the menu on long press on message */ +"chat_more_menu_item" = "Mer"; + +/* Status message */ +"status_offline" = "Frakoblet"; +/* About screen menu */ +"settings_antidote_build" = "Antidote-bygg"; +/* Settings screen autodownload images option */ +"settings_never" = "Aldri"; +/* Settings screen autodownload images option */ +"settings_always" = "Alltid"; + +/* Source of photo to take */ +"photo_from_camera" = "Kamera"; +/* Deleting single message in chat */ +"delete_single_message" = "Slett melding"; +/* Delete button */ +"alert_cancel" = "Avbryt"; +/* General error button */ +"error_ok_button" = "OK"; +/* General error button */ +"error_retry_button" = "Gjenta"; +/* PIN screen screen */ +"pin_lock_30_seconds" = "30 sekunder"; +/* PIN screen screen */ +"pin_enabled" = "Skru på PIN"; +/* PIN screen screen */ +"pin_touch_id_enabled" = "Aktiver Touch-ID"; +/* PIN screen error details */ +"pin_failed_attempts" = "Mislykket forsøk: %@"; +/* Error */ +"error_general_bad_format_message" = "Filen har feil format eller er skadet."; +/* Avatar button hint in settings */ +"accessibility_avatar_button_hint" = "Setter eller fjerner avataren."; +/* Error */ +"error_import_not_exist_title" = "Kan ikke importere Tox-lagringsfil."; +/* Error */ +"error_decrypt_title" = "Kan ikke dekryptere Tox-lagringsfil"; +/* Error */ +"error_decrypt_empty_data_message" = "Noe av inndataen var tom."; +/* Error */ +"error_decrypt_bad_format_message" = "Filen har feilaktig eller skadet format."; +/* Error */ +"error_general_bind_port_message" = "Kunne ikke opprette binding til en port."; +/* Error */ +"error_proxy_invalid_port_message" = "Mellomtjenerporten er ugyldig."; +/* Error */ +"error_proxy_host_not_resolved_message" = "Kunne ikke utlede mellomtjenerporten."; + +/* Error */ +"error_name_too_long" = "Navnet er for langt."; +/* Error */ +"error_contact_request_already_sent" = "Kontaktforespørsel allerede sendt."; + +/* Tab chats badge ending */ +"accessibility_chats_ending" = "uleste sludringer"; +/* PIN screen screen */ +"pin_touch_id_description" = "Bruk fingeravtrykket ditt som alternativ til å skive inn PIN."; +/* Notification text */ +"notification_incoming_contact_request" = "Innkommende kontaktforespørsel"; +/* Notification text */ +"notification_is_calling" = "ringer …"; +/* Notification text */ +"notification_incoming_file" = "Innkommende fil"; +/* Call screen text */ +"call_reaching" = "Ringer …"; +/* Deleting contat confirmation */ +"delete_contact_title" = "Slett denne kontakten?\nSludringshistorikken vil gå tapt."; +/* Error */ +"error_general_profile_encrypted_message" = "Profilen er kryptert."; +/* Error */ +"error_proxy_title" = "Mellomtjenerfeil"; +/* File message text */ +"chat_paused" = "På hold"; +/* Error */ +"error_decrypt_wrong_password_message" = "Passordet er galt eller så er filen skadet."; +/* Error */ +"error_contact_request_bad_checksum" = "Feilaktig sjekksum. Sjekk innskrevet Tox-ID."; +/* Error */ +"error_proxy_invalid_address_message" = "Mellomtjeneradressen har ugyldig format."; +/* Error */ +"error_status_message_too_long" = "Statusmeldingen er for lang."; + +/* Error */ +"error_contact_request_too_long" = "Meldingen er for lang."; +/* Error */ +"error_contact_request_no_message" = "Ingen melding angitt."; +/* Error */ +"error_contact_request_own_key" = "Du kan ikke legge til deg selv på kontaktlisten."; +/* Call error */ +"call_error_contact_is_offline" = "Kontakten er frakoblet"; +/* Call error */ +"call_error_no_active_call" = "Det finnes ingen aktiv samtale"; + +/* Error while using color theme */ +"theme_error_cannot_open" = "Kan ikke åpne drakt. Feil format."; +/* Avatar button label in settings */ +"accessibility_avatar_button_label" = "Avatar"; diff --git a/Antidote/nb.lproj/import-profile.html b/Antidote/nb.lproj/import-profile.html new file mode 100644 index 0000000..7f2b2f3 --- /dev/null +++ b/Antidote/nb.lproj/import-profile.html @@ -0,0 +1,10 @@ + +

To import your Tox profile:

+ +
    +
  1. Send the ".tox" file to your device using any app (Mail, Dropbox, etc.).
  2. +
  3. Use "Open In" menu for this file.
  4. +
  5. Select Antidote in a list of available apps.
  6. +
  7. Check the name of your new profile and press OK.
  8. +
+
diff --git a/Antidote/nl.lproj/AppStoreLocalizable.strings b/Antidote/nl.lproj/AppStoreLocalizable.strings new file mode 100644 index 0000000000000000000000000000000000000000..3f83883781ab40037320a8d4bc9e212b89188067 GIT binary patch literal 7612 zcmeI1%Wl&^6oyBLRTqdyFx?;(NNBkffugEv78Kfos07O@O`MC8I#Did!yEBN+0aJ; zzW+={nTUo(7s!z;%l3FYmow*|bMf!rzshdQC2oT=arjPl)91|(PBtl=310P-;COhYtUy*tBra6fsItNx(0KcyD8VIyWp--`aFHL`TD%; zP`ae1&)A83?%udE*B!3gZkL(;TnD@#&|fmNT$^zc_k(kXwrZCk#ifl|qP&mPJ?@Lv zBYR4bJ*D=NYs1FgVjjuub#lUrFL)63C~ zl-u+eGmqM+JV7e25zW!G=bmY2$jq9h&-_n$mr;`ZsbP_@_LQ1|p^@19dZ&>Otf#cB zF?)Q2*2~$Fe)W_xlJ;Io?`^lqm=(@VcTDZj^rU^zwH8zA-xbJ# zYu=FCiICI2?|_{!l^6JEJNvr84t>au^M>7v2)hr+m~nK>GKa`}ihX)tQrKQT@p~EJ z=e?$4b`9*RAa{-T%nIAfsqMXruv1i5rlc(96D7s+7IlT)<;Ct+Wh%<8+8~u0c8Y&O zQu$kfUH-6(bCrWRR?1cMy-+o8S)+DRpqHcXgoWkB*~$?ZX@4Dq*3iDB>d0K!T>fk> z&QZSM9jD|ZlJY%QeFN(obyQ?359@K#|*qml{XjE zC&m_J#=i(-aTMZz#QfZqUAYVIAkN}8DVAA>LyH3Yw2WD<1uNs38!;+J9L?7vK1yGGx+*Rzml5XAsOxhL&#|vvpB2Y3L|A*qEMO`|&SwJ)oW+ER zt=mHvpI7KY?<%wVH|wdB*h5dzz=YN43*_2%foDh?>;`d=b?RgZ+9iP*RmLli?pe&h zI(ok@ZdF`@+6F#3W+H>0*Hd$`cYMMsWjBw_Y82bVfljfPz|2-=4}Vr>57u;-yvD}` zhE}|+zE&Ttso&d;)^Z49{{KM>{PeFN_&@O|E!G)!df-xSi*vz)$XZ4mHDk~JcbxN5 zoDqFvDVF10Wp?i-oU5!Z->ZqEmi&@fOL-gNq(~qB8Lf`W`CeZfqYmf0Ppj-w)^nF~ zpWI9TdcsPA-wwWb%nt0)()-+mr*ryD(9n8f9>=KDC{ywAL%JFL!y5%HE!#z2tTT=x KQ+D!Tj?o{Mwm*gd literal 0 HcmV?d00001 diff --git a/Antidote/nl.lproj/InfoPlist.strings b/Antidote/nl.lproj/InfoPlist.strings new file mode 100644 index 0000000000000000000000000000000000000000..6c333a86e6042a9b313f0a4b40846fa9afa0f57c GIT binary patch literal 978 zcmbu7K~KU!5QX2_U(xhP42X$bj0XZ26E&#O#ABfqNT4NcY2r`vPpaSSrcg~U*uzd| zW@p~ad)@D^fqDvb#tC$*RPV|((?)9*D%E#3CrY)%_jO~Ul3Yw}sf4W0Pm~iyE*FD0 z*9Ug0E#H#6jOZ0>-kknS6`2gQKto+=fE_wJVsed{X-B{9u+$2iK%bmTT~Is1i$O8W zKK_`^H++xPg^Ln)Psmo-*kSjWV|#o46Sm&Eiir9>)e+MY{0Kbjw7D@}p@l==kue6g zyT=Okpl3CaUJf|Z*3OXL8&0SA{@Gj@f}iR?aQqX2bQ+?O2V zYW){uBZHE&+-TS8KuDh literal 0 HcmV?d00001 diff --git a/Antidote/nl.lproj/Localizable.strings b/Antidote/nl.lproj/Localizable.strings new file mode 100644 index 0000000..d01f1dd --- /dev/null +++ b/Antidote/nl.lproj/Localizable.strings @@ -0,0 +1,415 @@ +/* + Localizable.strings + Antidote + + Created by Dmytro Vorobiov on 08/10/15. + Copyright © 2015 dvor. All rights reserved. +*/ + +/* + Translation is done with Transifex service. + See https://www.transifex.com/antidote/antidote-ios/ +*/ + +/* Login screen text */ +"login_or_label" = "of"; +/* Login screen text */ +"create_account" = "Maak een Account"; +/* Login screen text */ +"import_profile" = "Importeer Profiel"; +/* Password field */ +"password" = "Wachtwoord"; +/* Login button */ +"log_in" = "Inloggen"; +/* Login screen text */ +"create_profile" = "Maak een profiel"; +/* Login screen text */ +"import_to_antidote" = "Importeer naar Antidote"; +/* Login screen text */ +"create_account_username_title" = "Hoe zullen je contacten je zien?"; +/* Login screen text */ +"create_account_username_placeholder" = "Gebruikersnaam"; +/* Login screen text */ +"create_account_profile_title" = "Beschrijving van dit profiel?"; +/* Login screen text */ +"create_account_profile_placeholder" = "Profielnaam"; +/* Login screen text */ +"create_account_profile_hint" = "bijv. Thuis, iPhone"; +/* Login screen text */ +"set_password_title" = "Wachtwoord instellen"; +/* Login screen text */ +"set_password_hint" = "Een wachtwoord is vereist om je data te beveiligen. Hou het veilig - je data kan niet worden hersteld als je deze kwijtraakt."; +/* Login button */ +"create_account_next_button" = "Volgende"; +/* Login button */ +"create_account_go_button" = "Ga"; +/* Default status message */ +"default_user_status_message" = "Toxing met Antidote"; + +/* PIN screen text */ +"pin_enter_to_unlock" = "Ontgrendel met je toegangscode"; +/* PIN screen text */ +"pin_set" = "Toegangscode instellen"; +/* PIN screen text */ +"pin_confirm" = "Bevestig toegangscode"; +/* PIN screen error */ +"pin_do_not_match" = "De toegangscodes komen niet overeen. Probeer opnieuw"; +/* PIN screen error */ +"pin_incorrect" = "Verkeerde toegangscode"; +/* PIN screen error details */ +"pin_failed_attempts" = "Failed attempts: %@"; +/* PIN screen message shown on log out */ +"pin_logout_message" = "Too many failed attempts. You have been logged out."; +/* PIN screen screen */ +"pin_enabled" = "Gebruik een toegangscode"; +/* PIN screen screen */ +"pin_touch_id_enabled" = "Gebruik Touch ID"; +/* PIN screen screen */ +"pin_description" = "Prevent unauthorized access to Antidote with a PIN."; +/* PIN screen screen */ +"pin_touch_id_description" = "Use your fingerprint as an alternative to entering a PIN."; +/* PIN screen screen */ +"pin_lock_timeout" = "Lock Timeout"; +/* PIN screen screen */ +"pin_lock_immediately" = "Immediately"; +/* PIN screen screen */ +"pin_lock_30_seconds" = "30 seconden"; +/* PIN screen screen */ +"pin_lock_1_minute" = "1 minuut"; +/* PIN screen screen */ +"pin_lock_2_minutes" = "2 minuten"; +/* PIN screen screen */ +"pin_lock_5_minutes" = "5 minuten"; + +/* Label shown when connecting to Tox network */ +"connecting_label" = "Verbinden..."; + +/* Tab name and screen name */ +"contacts_title" = "Contacten"; +/* Tab name and screen name */ +"chats_title" = "Chats"; +/* Tab name and screen name */ +"settings_title" = "Instellingen"; +/* Tab name and screen name */ +"profile_title" = "Profiel"; + +/* No contacts placeholder text */ +"contact_no_contacts" = "Geen contacten"; +/* No contacts placeholder text */ +"contact_no_contacts_add_contact" = "Voeg contact toe\nof\n"; +/* No contacts placeholder text */ +"contact_no_contacts_share_tox_id" = "deel je Tox ID"; +/* Contact request section title */ +"contact_requests_section" = "Contactverzoek"; +/* Contact last seen status */ +"contact_last_seen" = "Laatst gezien: %@"; +/* Screen name */ +"contact_request" = "Contactverzoek"; +/* Contact request button */ +"contact_request_decline" = "Weiger"; +/* Contact request button */ +"contact_request_accept" = "Accepteer"; +/* Contact request confirmation */ +"contact_request_delete_title" = "Contactverzoek verwijderen?"; +/* Text shown when contact was deleted */ +"contact_deleted" = "Deleted contact"; + +/* Share Tox ID text */ +"show_qr_code" = "QR-code weergeven"; +/* Share Tox ID text */ +"copy" = "Kopiëren"; + +/* Add contat screen name */ +"add_contact_title" = "Contact toevoegen"; +/* Add contat button */ +"add_contact_send" = "Verzenden"; +/* Add contat placeholder text */ +"add_contact_tox_id_placeholder" = "Tox ID"; +/* Add contat placeholder text */ +"add_contact_or_label" = "of"; +/* Add contat button */ +"add_contact_use_qr" = "Gebruik QR-code"; +/* Add contat placeholder text */ +"add_contact_default_message_title" = "Bericht"; +/* Add contat default text sended to contact */ +"add_contact_default_message_text" = "Hallo! Wil je mij toevoegen aan je contactpersonen?"; +/* Add contat error */ +"add_contact_wrong_qr" = "Verkeerde QR-code. Het moet een Tox ID bevatten"; + +/* User name text */ +"name" = "Naam"; +/* User nickname text */ +"nickname" = "Schermnaam"; +/* User status message text */ +"status_message" = "Statusbericht"; +/* User status text */ +"status_title" = "Status"; +/* User Tox ID text */ +"my_tox_id" = "Mijn Tox ID"; +/* User public key text */ +"public_key" = "Publieke sleutel"; +/* Share Tox ID text */ +"show_qr" = "Bekijk QR-code"; +/* Profile menu item / screen name */ +"profile_details" = "Profiel details"; +/* Profile button */ +"logout_button" = "Uitloggen"; + +/* QR code screen button */ +"qr_close_button" = "Sluit"; + +/* Chat screen placeholder */ +"chat_no_chats" = "Geen chats"; +/* Chats screen message text */ +"chat_outgoing_file" = "Uitgaand bestand:"; +/* Chats screen message text */ +"chat_incoming_file" = "Inkomend bestand:"; +/* Chats screen message text */ +"chat_call_finished" = "Gesprek beëindigd"; +/* Chats screen message text */ +"chat_unanwered_call" = "Onbeantwoord gesprek"; +/* Chat button */ +"chat_send_button" = "Stuur"; +/* Chat notification toast */ +"chat_new_messages" = "↓ Nieuwe berichten"; +/* Chat call information */ +"chat_call_message" = "Gesprek,"; +/* Chat call information */ +"chat_missed_call_message" = "Gemist gesprek"; +/* Item present in the menu on long press on message */ +"chat_more_menu_item" = "Meer"; + +/* Status message */ +"status_offline" = "Offline"; +/* Status message */ +"status_online" = "Online"; +/* Status message */ +"status_away" = "Afwezig"; +/* Status message */ +"status_busy" = "Bezig"; + +/* Notification text */ +"notification_new_message" = "Nieuw bericht"; +/* Notification text */ +"notification_incoming_contact_request" = "Inkomend contactverzoek"; +/* Notification text */ +"notification_is_calling" = "belt"; +/* Notification text */ +"notification_incoming_file" = "Inkomend bestand"; + +/* Settings menu / screen name */ +"settings_about" = "Over"; +/* Settings menu / screen name */ +"settings_faq" = "FAQ"; +/* Settings menu / screen name */ +"settings_advanced_settings" = "Geavanceerde instellingen"; +/* About screen menu */ +"settings_antidote_version" = "Antidote Versie"; +/* About screen menu */ +"settings_antidote_build" = "Antitode Build"; +/* About screen menu */ +"settings_toxcore_version" = "Toxcore Versie"; +/* About screen menu */ +"settings_acknowledgements" = "Met dank aan"; +/* Settings screen menu */ +"settings_autodownload_images" = "Download bestanden automatisch"; +/* Settings screen menu */ +"settings_autodownload_images_description" = "Automatisch inkomende bestanden downloaden."; +/* Settings screen menu */ +"settings_notifications_message_preview" = "Notificatie Voorbeeld"; +/* Settings screen menu */ +"settings_notifications_description" = "When application goes to background, you will still receive notifications up to 10 minutes."; +/* Settings screen menu */ +"settings_udp_enabled" = "Gebruik UDP"; +/* Settings screen menu */ +"settings_restore_default" = "Standaardinstellingen herstellen"; +/* Settings screen autodownload images option */ +"settings_never" = "Nooit"; +/* Settings screen autodownload images option */ +"settings_wifi" = "Wi-Fi"; +/* Settings screen autodownload images option */ +"settings_using_wifi" = "Via WiFi"; +/* Settings screen autodownload images option */ +"settings_always" = "Altijd"; + +/* Profile settings menu */ +"change_password" = "Verander wachtwoord"; +/* Profile settings menu */ +"delete_password" = "Verwijder wachtwoord"; +/* Profile settings menu */ +"old_password" = "Oud wachtwoord"; +/* Change password text */ +"new_password" = "Nieuw wachtwoord"; +/* Change password text */ +"repeat_password" = "Herhaal wachtwoord"; +/* Change password button */ +"change_password_done" = "Klaar"; +/* Change password error */ +"password_is_empty_error" = "Password should be non-empty"; +/* Change password error */ +"wrong_old_password" = "Verkeerd wachtwoord"; +/* Change password error */ +"passwords_do_not_match" = "Wachtwoorden komen niet overeen"; + +/* Source of photo to take */ +"photo_from_camera" = "Camera"; +/* Source of photo to take */ +"photo_from_photo_library" = "Fotobibliotheek"; +/* Error while converting avatar image */ +"change_avatar_error_convert_image" = "Kan afbeelding niet converteren"; + +/* Alert text when sending file to contacts */ +"file_send_to_contact" = "Verzend naar contact"; + +/* Profile menu item */ +"export_profile" = "Exporteer profiel"; +/* Profile menu item */ +"delete_profile" = "Verwijder profiel"; +/* Delete profile confirmation */ +"delete_profile_confirmation_title_1" = "Dit profiel verwijderen?"; +/* Delete profile confirmation */ +"delete_profile_confirmation_title_2" = "Weet je het zeker?"; +/* Delete profile confirmation */ +"delete_profile_confirmation_message" = "Deze actie kan niet worden hersteld"; + +/* Call screen text */ +"call_incoming" = "Inkomend gesprek"; +/* Call screen text */ +"call_ended" = "Gesprek beëindigd"; +/* Call screen text */ +"call_reaching" = "Reaching..."; + +/* File message text */ +"chat_file_cancelled" = "Geannuleerd"; +/* File message text */ +"chat_waiting" = "Wachten..."; +/* File message text */ +"chat_paused" = "Gepauzeerd"; + +/* Deleting chat confirmation */ +"delete_chat_title" = "Verwijder deze chat en gesprek geschiedenis?"; +/* Deleting contat confirmation */ +"delete_contact_title" = "Verwijder dit contact?\nJe gesprek geschiedenis zal gewist worden."; +/* Deleting contat request confirmation */ +"delete_contact_request_title" = "Verwijder dit contactverzoek?"; +/* Deleting single message in chat */ +"delete_single_message" = "Wis bericht"; +/* Deleting multiple messages in chat. */ +"delete_multiple_messages" = "Wis berichten"; +/* Deleting all messages in chat. */ +"delete_all_messages" = "Wis alle berichten"; +/* Delete button */ +"alert_delete" = "Verwijder"; +/* Delete button */ +"alert_cancel" = "Annuleren"; + +/* Error while creating new profile */ +"login_enter_username_and_profile" = "Please enter both username and profile name."; +/* Error while creating new profile */ +"login_profile_already_exists" = "Een profiel met deze naam bestaat al"; + +/* General error title */ +"error_title" = "Fout"; +/* General error button */ +"error_ok_button" = "OK"; +/* General error button */ +"error_retry_button" = "Opnieuw"; +/* Error */ +"error_contact_not_connected" = "Contactpersoon is niet online"; +/* Error */ +"error_too_many_files" = "Te veel actieve bestandsoverdrachten"; +/* Error */ +"error_internal_message" = "Interne fout"; +/* Error */ +"error_wrong_password_title" = "Verkeerd wachtwoord"; +/* Error */ +"error_wrong_password_message" = "Wachtwoord bevat ongeldige tekens"; +/* Error */ +"error_import_not_exist_title" = "Kan het opgeslagen tox bestand niet importeren"; +/* Error */ +"error_import_not_exist_message" = "Bestand bestaat niet."; +/* Error */ +"error_decrypt_title" = "Kan het tox bestand niet decoderen"; +/* Error */ +"error_decrypt_empty_data_message" = "Enkele gegevens ontbreken."; +/* Error */ +"error_decrypt_bad_format_message" = "Bestand heeft een verkeerd formaat of is corrupt."; +/* Error */ +"error_decrypt_wrong_password_message" = "Wachtwoord is onjuist of het bestand is corrupt."; +/* Error */ +"error_general_unknown_message" = "Onbekende fout opgetreden."; +/* Error */ +"error_general_no_memory_message" = "Te weinig vrij geheugen."; +/* Error */ +"error_general_bind_port_message" = "Niet gelukt om met een poort te verbinden."; +/* Error */ +"error_general_profile_encrypted_message" = "Profiel is versleuteld."; +/* Error */ +"error_general_bad_format_message" = "Bestand heeft een verkeerd formaat of is corrupt."; +/* Error */ +"error_proxy_title" = "Proxy error"; +/* Error */ +"error_proxy_invalid_address_message" = "Proxy address has invalid format."; +/* Error */ +"error_proxy_invalid_port_message" = "Proxy port is invalid."; +/* Error */ +"error_proxy_host_not_resolved_message" = "Proxy host could not be resolved."; + +/* Error */ +"error_name_too_long" = "Naam is te lang"; +/* Error */ +"error_status_message_too_long" = "Statusbericht is te lang"; + +/* Error */ +"error_contact_request_too_long" = "Bericht is te lang"; +/* Error */ +"error_contact_request_no_message" = "Geen bericht ingevoerd"; +/* Error */ +"error_contact_request_own_key" = "Cannot add myself to contact list"; +/* Error */ +"error_contact_request_already_sent" = "Contactverzoek is al verzonden"; +/* Error */ +"error_contact_request_bad_checksum" = "Verkeerd controlegetal, controleer het ingevoerde Tox ID"; +/* Error */ +"error_contact_request_new_nospam" = "Verkeerd nospam-value, controleer het ingevoerde Tox ID"; + +/* Call error */ +"call_error_already_in_call" = "Reeds in een gesprek."; +/* Call error */ +"call_error_contact_is_offline" = "Contactpersoon is offline"; +/* Call error */ +"call_error_no_active_call" = "Er is geen actief gesprek"; + +/* Error while using color theme */ +"theme_error_cannot_open" = "Kan het thema niet openen, verkeerd formaat"; + +/* Tab chats badge ending */ +"accessibility_chats_ending" = "unread chats"; +/* Avatar button label in settings */ +"accessibility_avatar_button_label" = "Avatar"; +/* Avatar button hint in settings */ +"accessibility_avatar_button_hint" = "Sets or removes avatar."; +/* Chat button label in contact screen */ +"accessibility_chat_button_label" = "Chat"; +/* Chat button hint in contact screen */ +"accessibility_chat_button_hint" = "Opens chat dialog."; +/* Call button label in contact screen */ +"accessibility_call_button_label" = "Audio call"; +/* Call button hint in contact screen */ +"accessibility_call_button_hint" = "Makes audio call."; +/* Video button label in contact screen */ +"accessibility_video_button_label" = "Video call"; +/* Video button hint in contact screen */ +"accessibility_video_button_hint" = "Makes video call."; +/* Tap to copy hint */ +"accessibility_show_copy_hint" = "Shows copy menu."; +/* Tap to edit value hint */ +"accessibility_edit_value_hint" = "Edits value."; +/* Incoming message label */ +"accessibility_incoming_message_label" = "Message"; +/* Outgoing message label */ +"accessibility_outgoing_message_label" = "Your message"; +/* Message shown on chat list when contact is typing */ +"chat_is_typing_text" = "aan het typen..."; +/* Text shown in chat when there are undelivered faux offline messages */ +"chat_pending_faux_offline_messages" = "Niet-bezorgde berichten worden verstuurd zodra jij en je vriend online zijn."; diff --git a/Antidote/nl.lproj/import-profile.html b/Antidote/nl.lproj/import-profile.html new file mode 100644 index 0000000..5d335d3 --- /dev/null +++ b/Antidote/nl.lproj/import-profile.html @@ -0,0 +1,9 @@ + +

To import your Tox profile:

+ +
    +
  1. Send the ".tox" file to your device using any app (Mail, Dropbox, etc.).
  2. +
  3. Use "Open In" menu for this file.
  4. +
  5. Select Antidote in a list of available apps.
  6. +
  7. Check the name of your new profile and press OK.
  8. +
diff --git a/Antidote/old_antidote_logo_with_text.png b/Antidote/old_antidote_logo_with_text.png new file mode 100644 index 0000000000000000000000000000000000000000..722cf84c9724960e8fa8e569c0886548e2f2296b GIT binary patch literal 38036 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νFfs|{+UnIWQ<(t8=Dmxb2+4wjqS=2BwF_jRi@e-Wd|4Fq3MiWCGi&3m9)335 zn}lJkK=>XCUx9vW+hJKh0$oZ;n{i>WIdRFNHR}{bR$}5sNZMSJ2Am8Xsf?*DF=6D; zOX&|i)i(YbeGrIppoksxAeD)HLHLLZ=e4gbdlYL)J@&8MidetrpZibb9ps1r@1&ne zmvI=?Lx3SL0L$Q-)_iQM!C88<765s6`+HV0LLHA;Z)R@Vz6hIZpIfWY=I7t&>h6T7q}+rEI|iefT2dsAKLL6N+~!MoKm6Z ziwoC}^n$1Dp(O z=we1bvfg`S*ZSr=5rgp~kjDgMR-=&^7)+e{gxBizOisjD4w~{ppK@EO^;w#lCFB?p zW%<~Vvg1!!8a zX{6m3-82=Cj4C&J^TOu~yJHuh?4OH0W#vOO27~axX`R(ul@WBHpB^X`X6##D7TQjx zB3rkfZx+ZeLvOLAh%f`#ex~(JmZg)1lRgljPDq-nF`OYYa9cvG%FBKmM|kVH`0OL83e*3xLm;?^&#hR%s4Q;T)cYOy?{%< z4anU-@?%5XdpkT6Iwg!C7rdb^$crVj*&?$og1chTHX9NHi_wjTOPCz|oT8mkGP^tS zgIV+Zf4@jJbBfj+0J8da-VPM$_VykTbJ8Z?9lUYcf7A|kygZB|y<}qEi&L*KFzLVW z7^(oOt+ORj2I~fQDlp&Mpn#w-qGj6NTBuU>stHnlZvsifss)tS6q_!Edn(nhQg0=c zCiRZ2q@&UtgSV4d>Bvd%WhdIRwFVY9DBzL}bHFA#^{$OS$#>s9e)iPs8?XaQS0uk# zlE(5Eigcg2K^U~054SFLmY$VSZHVq(u8r#UyDZVH06_u^pL4`^op%x!)(T>({IJpo zSq5uMcORplvb`d;WofDiDEjq5nM)Ta_i6AiFz{K`0Z!gBZ6u6Vf^GVr?TRc31PoPp zqe#&b6PB}n;e+(`8|%~uUVrg_jr64>+!)A(6vF+XUT5*oPa7bjc{*Zf?< zzc@JKhV4|#@&3J*l)8RrX$aL|X)2c(K)@uF;3lD@Zl_|fwnovb!$QK^6-i@41wUKdp1V)^Fl^a?O|6C>fe0M>ViltCFuQt z$UJ2SY$8LrEznm1YqiN#Il@^lho|o1%QS$|&cn<;o22-=dI=UpsfN&X!SFR1**IKe z{4adBZN+6079eK}6c9J415x%U;S?}1SYr01#9fb}1CPIPa}624l$TvCAslAr6s$7S z7RN^4-IBP}Ny7igW7XE=5lT?L6PR8&s_sqC|Kk{Rh9o?d2ZdOpAE8z2uRH;nXc*N{ zGBS$-#z~*aJ5(3`#D#0tWZ8^Ym@wGDSH9@Wtt15_^UHGNuMqP&we9xbcbl_+w;@*L zwJ-~jR&TRRWy2?%%D!eaoR_6c47J*oKe2hl-_`6*#T_Pf;oC|Lm2 zYl}<7pS);p3Ct^0GF6ZE@Y|q%$$>r>Wym1@yY^D*4w@Y%5^vY`lDTV5DlWpcO;^swjV)xxYNNIZ5Sl z=2uWdu8nA@<^^YxW`N|yn{xD?ILj8^|4xfQ2l_2L zt0DIjW$BdwxJV)pPWaPE4tcW>HMQ|LE`zWQ=f!(-poIB7oL*O-7W|$Y*7utPMCoxd z`0U;tLjuM{ThM*NK2k$D5_TBBeB2tHpwB|i>dl+2pSdae(-C`mB^09Fjll!y#b0BJ zYgX2y#7b)rITdnl;jJ_bIQ~X_VeXLH2opY&)Ml{lV* z{$fDYKzQiD?ykG>n6b9)cS-j1cRWTP3$dB~E6O;z6lsYHyWyiF=B?nvmsKA*;IjL(KHSB!#x%a`2UNR!9pHx809QU%fWOaP2vPGK?0)(br zX{|CDe$85XGd-`KT3oN2nO^Z~O`W!w4ER3BxG84A)YuW7gC7#!r{4BOcfX6qliXwe z=@tHiT))`=nl#&4^9twf3DBx=f{G*F-Q zHR~BzP}Koum6pcg`qi#c=~MUfhb8>k+6$GC7c2%$%FQ)mHd`7dKfT%qi)@{GI4jFz zmRNO|9R0^cCLRjq<@4oxnbmj*ZsycAsWaHVD$E+(+ceI#5cH088u4qPOJuDjeSdKCRs~}$+>DqgE_N;C+!>oPLFq-VbzEIi01#-;5;~-q zo}UAsdF11^_+s7T+F7ae*y$5bu^%6vt62Av zp&Q!k$8Y%679ulO>ue@sD<5G2T*zLfTdfgHNp;GnD;%pLr~b*ZpBV@@(RuO8_iO=pWJ!|K~fW~JdR$< z-UAgfYRp!e6RGIPWoA7+pLIfP(BFqZ<$Q>!`W2K(CE55_L=+B`sq)ESyE_-oAJnc^m$1XC;n&?0afo>v3})f%oJ%?RZ$*t}D9LW~73|(YV5tf9M~s ziTPj`Vst071?)yxS~((QHxEG7d91oIiK56ax5iPpcqWR>f-d7^<|B63V~JEc*|#m1 zX_#;-JxOE#9EI1JC1A_>zx~mhk$0U?Yjae_i@0zn`aj%)bD7e%eK7Z6ChipT~y~IK1!-OphMp zYe4@eBeHKX{&=-Q)XA-C>hJ($qS#ti<#rM^Q-lV>^8x0W9x%^>*s(9`Jip$qUJXby zp%1KQg- z=q91~?KyJ9OhW6&qr*Q(YPDdL4tDT9tHrcsxh+CHEGZ=kcuUJ?Hv0NCiu9VRgkF}G zuu#V}NZr)o=H=R4YNEC~QZQOm?j-D7sT(as5U6n<(0q;s`ut-Q!o=3a#1?gOK>pYw zOu$X(szBFYg#@!EW|bbW2BN5 z+;kwCu3IZKUsne&*XzDK;qdwzzFXTYSvCU5p#IldEM{6*UK@G0DWpuXLne6mH?_Xg z?b>^%na}mYean3RQF%J_u^m4O<=%tH>;#NX2U{HCRua=Y6a1UkO)QW2O|UKxy`#Hl zjFEQEDUc5MVL7?*pmkz?zRlI|%;*-ogsCHq@F&rY1`gg^?R>l!za$UGkc^GDn0V>{ zV=j{RgO6Ra0`~bqlytNVH?7#xQYCS}=y&%_l1(e?jnJzUL-d^n@d^*Hcldx3RN%-Z zlKq8|p?|5?^zU(V;* z>O0^9QBDJt#pe$uwAd^W3lE~OkK*6((77#fHQia~p1QUZ?D-oEin!hs?FPHlJg*1v zfg;)!Y(h_fR?N;R(VthD6L>W$9(s>NREC(t?^Pu^jG6zW4vzQ?CD5j3&;C(hK0CQ1 zRu&6OBZ|)tmczML#rfwh_vwBa?}5=~qMk*vc;D8aTaz93&bX^-j^+bQrAcM_Q5o?; zY$0Q2WmULfqSDy4?9hO8cDeaZHt3qe=Lfo@egNaxJ>^@r5Gpyna)SSl6}p#7 z0g+06KA(B(++jT+*(CRE8d0F^su@s z_`Lu?Ek3=9_sMFoq~S!id+2OeAF_a6$}h`w?*e zweV6Y@A=1((KMHzh8U={J45eMC5yqxIn-#&-4qC{QtL-E@-UlctN9&zf#4Q+q z6g(n$=$5FV;jZg?3SDFIR*T6r>%XwHmJJrT5Zk7$G`cn_zpiGhvW0AyJ)8V za;I8i&6bF07U`%xN0fv4_yk>$e#rb<#;SrBS39w+-c;MGFF{|Fz;vhI0xN<+lu;e( zHGe|T!++!dVlXf#IBnF`GsG9fRrqDTFn5?!pH=>U~>K(rcYjddE@&!V`YvrgK{ zyk4B2*R%8p`UI+mQjQk3VdaNoN7WZG7jw}h%k4nn1Z+JfZ8;_vhoxrq`mEFE99qH!%apKg5 zsV?Zd3NHp|`)e&D=r?a7lZq+fZx689lP9UXE-Z)r^;qxz)(EpE< zC%tVjtx!mgDY@}AI%oyTG;`_K+lBF3uTc!qLc00j`D}>~J5}xtWn5f}`Z$i+Dc@$# zoW3#XyyOqsVP)J&;NNA%ZJa5R?I^ZDK1B>Cj_Xez2-F`$Je@MTQLy)JmNYkq%z8L_ z_eE;&ABS@t?ws{co1YSN^^;P)d*`vG^8|!uO8ewP!UGZC)EqrRgO{ny*eDdA-6$35hS}_uRpTj>D$G8?Zc?591KxlZ7;|Tmocem{TX*qLrpUi7i<(5C+6G3{k&!Gr9G78!o`Vo;b+j#cVFS07 z69SL-78-G+@PNRErk20$$|TDNmN@~lxn}^A(UnnxV#%$PQI=bTz+T zNsk43RnTH4D)s4?(b{+VsDwAcd4=ECiZ2=g8#j)x{D((qB-sC*1MLNFLTpEb5RsRkSP+lP*!JZvHT+7TqF)Y7D+=O4(7bKlhtRu!Y4GQ_-lfiB$AbfA3{i(Qe2h)9fesKM=TS?TD6FTNG64+}Y@ zQis8Hbz}|?kMVir=+T8`RH9qr7;emF#_p{&!*cPOjmE^js%YZT#+q&4?e;jRq*|>0 zmVYmTy*ZH+ZEPAvqdlj=u;=$uFo-wcR5RYdKV7a7QKo$jiTj&?9pPsf$@_Ikj?JUX z^_IQUE|H|jQ>X~Szsne1vP;a*FX*y{PH?y#&Sk-4A2|K#$ZpCw)y@_Nl#@BdFKQGI zxOgT2-<9e9xwhjN(Paq7c#eP69}8X8^fWDcpG5MxQg(X^TgB)KH*_Dm+=!cS(bw%B zwUgOa#9CYvwU7pkJxb<&tBAP83{Ob`(nlltl_2HqJEzs1v(5hBQkw1%4_&v|%v5>| zKxcO5_J6Yqc-4#lA!rK1WnOV{$PVzC*L@(vu}{VfpO`O8EOlf`gkS!onEtNrt_Z!} zfq2iWct@NJfBTi7J-9xAB$dJsn!cKL02NHHt#M< zNaR+8m9=Ccs#tf^NP0LLtJp)hw@KfC9YlPKG(7ykjuZ6_)a}OlY;Jh1y^hB$G zOVWJ~o?k4xUb#!=>ESos_&4jecn8#3Blnmarl|FCrYl9RG63>OF>>dFx_fahBZT5$ z1+c17HWi$5uG*Y(onD@mPwEb4fK|Lh2s{6r$EexSQdKk6SNFG<2qbIhPXc>%k3#}t z&RqfD0cHOqaP7gDnef|1B9=;JAp9Ww{&gQo?Y~;VJsU5kYLha}s_>;p3g63L}S>W(5b1 z96Rr2L|19qX41^wJBTf?K9(@t>DNDtDCb5d(cm(26l^PN`y1guQ{wZ;E8}7Y>)*EJ zl-GAnVkM<6<%~_`seO|Z@xRv1O>>_&@!pBltJRFE*bb8XGD@{ZJfW}@wzJTS0YZ}m zhU=gBPfq8R@+PKzUuYS1owmTpm9irudiGyFfo?scxTf}6vw;DknR2pa>TRp zy&Eqse}gaskG2o8WSyTUcE}tq_Bh8oZ|fw4?rLOb@z-xe-#*eH(k)DHmNE2e=KhoS zt$i_uQ<;RB#8JlfB_(mX?=Si(m!rk;My;hEX#pE*u)XXj#U;B9K+*dJ_RPw3s$Are zTPTz6v~lxhYq9#s^2kwmZUe=Yx-zLbX)q_?>U6OP@CpQ-&36?sBab2qa~X^Ujx*(W zufB8~_IoO#O2u>Ige)`XQ;$W>iU@xY-MW@V&=X&xA2ORM zr^IU-D{vGrJ~BO$%bZ%N(ri*1tUhDM`-dubb>Y)LX=r7LCfpp@eSs7U`d=l)LtZj! z%S<6D?wJqrM%=>U=|sXeWvT-Lp4GG7jE!jRV$Kp6LLO&O_FJhzWS%rGCJ`D)iVSc9#pB%6TWIv9cZ=+HEV9Y(NdZJbpRpK;qt%)8PjdHAQDK&_(l^=JZX%!kb?>M8d^ zz+e<)BD3H;5L0z}X_;o6=8rv*k-@T6o<0wF?}N~n*WUJCZkcyO7XUvK*RgUE^Xtis)zdPu$ zj67T@ELoXavo%}H+!1GS%^9V#yfv-cu9_=(TyQ3A6VoXLIrYT+PAuTld6`|QSs2A% zLSYPkjoG;lNPKossw0{1p9z`lAXBXu6XhCmVd|$dg+G6UHJu6B#S|2f+w)>|9$Rm$ z!e~cYu1jPY7;m;X%zd51>|owW>;$}9u5T*5u-$WY^ibC1wk_v1vH(KZ zr}Yg63*DSERu7sfSz5lEFN(*asCYk7znLPTO&B0X7JTcz;guT^P>-X&wYcS&Qg>%a zgte{xF+Azf0sL>@AVkpXj5pRn`c@EPBbyWOj2HE!00-Zx2!$!y#H<0QmB z%Y{atpxHK}S70_v>2h?pcle2dpMEDh# z+OAK?&UNnHvbTcg{h@}pIzueGNXCXvglclQFHQhGH^F-Q*xnMQC0XRGl*cxKfYo^^Jpu@z$p$I}+{>e&_`mwSrU z1h^%oqUE?9BF0yKcy5YDd|FpA`6~D5`an9htmv5%gt7#+!wXcfMDpl0r-mP~>QW<< zE+%%mgnS6QhovK{R>jt$5Rj|6$POtIi{7_H5w!q!OX4`*6F;Z{aHZzvZ+lH~%Z>Xb zQ80iGR_p(G$al2^rj#bbzvpgwh`YXI`X4wtO_n!wCk141p;E$`#&ve9yBJrRakt8~ zztFMrsG?FbSZoy(!!twF% zK;i(iB$D6!ytHv9T-VL)nV{zybhQ_NN^m0){Go+=yw_4`&~oMPHFxHv4rIeo)?=PR zYO<7?t^)lZc;37{tB^lYfi{maD|W()s(aohYJxj?i{%MPW~vKl-_H@-SNRvD-3|T~ z9gOyHTN6aCY&n`<323T~yqkD+2C@lwL^z%}_&f9+hhL;yGDpWGUAVg0a)?>aHspL% zwTm!OL4D4@#Fo%K;IQkO+jTbaqxyt19htD4$9!zkLy$={pTD73hnnm3+?-(gy;thT z@W@o(IE+)afyQk3?R04SrX@u{F}DMsV@v(mUT{i#HvF)+M>b*EEO@F}EPBSY0msVL zU0ys_{?n(j(@fDM2;>csk&YcLs~bz>iaz`YN z(o2I!V#0`DmV1He7>rhgWwk<(UgM@4d<`oCC%q!F-ZZwc2YYtMJuKng@8?lCPI&{u zBhmP^l7rp(?OLEbO0&LxZnfHW_^-#2PC=A40Rfmw{`s4?yenhz(#XeM8}SdT#Ucfr z`-W-y%{7svr5ZIGI;OnJ{BJ+SKRhrSlW|XfuZq$%wf?GNSvX?{8}W=ZGo)kQVM8=N z(T@B0>s$l2aVh)eG3YlzVS6L)4$yVvdK|*k-6x|{PN7VFoDKJHTrCN;fZ{%48UNPd zeMibjN6KFU{a$vUR~NjguYIC@SBa#1Iz8C9d**jvB{!r0|4bu0P1J;=H8Gcwk;(RFO}$boIcU8G%K643T=X)DDDo`u}{FSsMu z7;|(jEWQ{xPkHfvY!y4Y6odK>liDPoPBI%gG&muj9B)x@NYa?k~`yZZikNb{(i!5#%8$Y`XX_uB!%W>W+WDI!u_0vmO*Y1T2 zQZe3q27u3$^7{61vo_pT10``rqlF)IVi-;4;G;Zyw1N;c8bl#8f&F z;!=`Yog7Tmlc*g5!I$j0G>`a2&!CVb&q_|$MaDluh@OTn(g;Akpr_%Iy!n>=IUSc?^5L0Q)pjx2VxQS+C!C+xF#a9vDiUq zIqInuyy}O(P?= zI@OiPnXS1=h|mJ{ZOh$`_)PC^p5$ImYb5$D0OgUVGqlLdt!kLWaQ9R>xD zRx0=lyIJ_xWKF&_r%sh>(dpYK+s|$*#kS)xKRIuk{@J?5_)q9ZjoL_>`Uh_Pm*@}- zf9(5V##tRO59?4Jj#L!&kGo*gO}|4ccdq~(%&1coQj=(T=GkPG_}wFPc=KlW(MWBRaKH^#vP@OBESWRB?`t6ZHl$!TL_-%k&mg_q=ohAoFU^b% z`pwBD73cl=A>hpgRNO(LA;<6GREGorn5e{SUN`GD`sQLVprGe1BmzQX5fwA%frRV; z!fSiLH3#h3AK!ZCmuKL2BH?|$XzlXrajw~4iRTYv3*evlHu6+m5YC*i_EVU}FA-=Y zV1;PmiDa(n_uJa8?dmO372np@K7uw&{Wquh{vV7l%&tK<$(xk_WQ?7|Bf{BXm|6K@ zZWX0$6t6|Xtl!zoDeFQ5PF)hV{)Lm*s#4|gWFFnIh}{%wy3F@_oe>QS9^2T7eIHPh z8E5nSnjQ;+gRLz4Ik6T~%~BD>f_zg=w~Ys#vNiS2f~6Jmbx6k`74sR7R8rW*s;mo2 z*Ys65AS+Ra==nkPf!bPm5a@dkfQ5@9(TonZ2FulShs_m2r9 zFK@ecrugaN2JdqI=Uu4%n_;d7pwRBMf%mf$9wN0ln?wG7!N1Fl)3~{ZR@cAY1zWQy z*kh|A)tJ0}7v@>AT`fIdb%jN7{MvuwR|-to_P-ruE;sdWM^Gr!<}bH6AF5Pv1k1Wp#Osb;5ox*t zvKvnT-@;wskvGjnexh^Z;CODf6j^Il%Uoj?^o%1&PyFcQZd?wW9)PSG;M=I#u+Rlm zYQC4UxlG_`URK+shF%wJs#L7nTSn_KN3pPvy6P=>x>W)@V_ntrD_KBs0oOUlFD7%?$BGCxdH z;ShbXuP7)YFXtlX5++_#`}_?fzbcUU^f^RHMa!~xNrOJiI3pw(7~pw1P4YH2@IEc+ z&B+2W!HC^mz`YPP{%51a!r!96nUpiioR>G$LOxJ6H{LwLnTe+DwReBNpjt&kuCtOF zuAQcBCJIHqq}Shkn6`Xy?QSSH=#)}ESyTHW@8<_r0)n?alhtVuJb{up$@*&Hk_z6f zO?W>_vBW$AX4F7@m0zt~qEeprJmN-eCzat{qJu<(b3_kUMd3JCyxb#TAMSI;1ff+; zD!gQ3FGTp|jTSipS8mPq+V{KP5p95UQV4C7pwX27n7L4 z4Ma3TI?O~hHK8Z}{TGpCz{Cn95ve0jIP0wcf7-j!zoxDdpD-W#e9AAm=RNQHoO`zS=AMVfxd2;$lrw-RQU|0akOr^5Wo&e8E}Q+j z;^B%o7+VAu+xlc7L8OFEIPbjt8p*0?k1bIbrLhN)+n2cAJf zkW;`b4RzLnvbqmwrxl(DL)`F;>kU;h?Lta3bg1BPaaj?xj7s;15zIH_KdJnExM_O# zo^SvWs*B#`8lQ1VaX4@fB&Hz*9DqV2w3u`%#K@bYptvR+OR36WB@aQSF{H%1?X0h& zkXNq!zd=Lq-H|z36~TL4 z_R79eKOw8k|G{o$DD$s?Y4TS-yAJ8TgraR802_&pFK|qe3ldO2M_;8Jh+2#^S5gw^lkaf z3Ooy>)wc&>j_pIjJ^QN+>bV{AsSy04zQE;f81Cned|PrCi?Ohz{du<#N;Lwff4JZO zttO@13o}$XYk`+{cTlW4q75%0f8J-`bh@5DdGmUB)D_=y30zJB7*qU`BuZK0nU4!# zl&uN_@U*0qS>lFK6eoYd`u<uijYl30?#;Hb;~tn z<1{&k@V^#6_4cPd(}hX=d$%?s(tmeZKclG@cW#1k<)!^u4Qvc{Dt1MbSA4#dH5hq8 z;g3>ak2l`@jy>|o>n8DlDIVi(fOl%=mn0YjQ@TvYbdJUVH??Z@H`cc+aqcE|eI@dEjR!37%f( ztu-unWt0uo%rUAcs-TGkmnLpr`b~V0G2E3Rc|WtDs6%&yNaRenY<6!xG4K)Ou154& zZushZ-mQtPEe_i95dcB(qWV0ym>3V?j?y<63@dDxzc2IhBHm~nKNF-;Al?!kq(|cV zFR{=q(rxy${d0sv7q>F&YirL(HI!v6{VyOh(+18dK#Ha5o4ERDNt5;vsl7lafQ9~f z`6pBQT3!2O9SUQ5q2C~W)Yrg7yK|T2l9oi_V0X9ap!jLR)IE?;HW3#37PijkIWH`> z&Wz2gw@boFg+P7dktkjN1SWq+_X$L4u{eMH_*9$rcRrJ!B_xN3hrL*$vn?X#lj39T zG{E%DCp>S75ok~*4~Hi|zUF29_En$`0^a%KVFg3a9pc$euuYFLu+MT3s=y?5zm_Mi z<>CFCxNFMD;u|S;l*1>5aEe2f7ymy%OLLs}jM-cJVkS{xK$qF&YBODw*i}|j+DbZY z7Zo06*X-?&&z+`R~}F9IoS(OWjnC8cqS+!nMYjAggR42t>~AJSKF&8Y=O zvoX&v+D}^{k2(F)dZqHO^UoFYN)pd}@AFQ7T|IJY(I3CyLE#Um9~WZCGp=Nt%XZR8o)Lzmf9u>WHvh zEau(XCqTD{23hdObM>;QJViHD8nb$(mNzmUB}ynj`1!prlWx9tJYLB@g_@G?nNMAF TLhr)}p^98iW6@Qo0#g19fzGvJ literal 0 HcmV?d00001 diff --git a/Antidote/pl.lproj/InfoPlist.strings b/Antidote/pl.lproj/InfoPlist.strings new file mode 100644 index 0000000000000000000000000000000000000000..6c333a86e6042a9b313f0a4b40846fa9afa0f57c GIT binary patch literal 978 zcmbu7K~KU!5QX2_U(xhP42X$bj0XZ26E&#O#ABfqNT4NcY2r`vPpaSSrcg~U*uzd| zW@p~ad)@D^fqDvb#tC$*RPV|((?)9*D%E#3CrY)%_jO~Ul3Yw}sf4W0Pm~iyE*FD0 z*9Ug0E#H#6jOZ0>-kknS6`2gQKto+=fE_wJVsed{X-B{9u+$2iK%bmTT~Is1i$O8W zKK_`^H++xPg^Ln)Psmo-*kSjWV|#o46Sm&Eiir9>)e+MY{0Kbjw7D@}p@l==kue6g zyT=Okpl3CaUJf|Z*3OXL8&0SA{@Gj@f}iR?aQqX2bQ+?O2V zYW){uBZHE&+-TS8KuDh literal 0 HcmV?d00001 diff --git a/Antidote/pl.lproj/Localizable.strings b/Antidote/pl.lproj/Localizable.strings new file mode 100644 index 0000000..c527e59 --- /dev/null +++ b/Antidote/pl.lproj/Localizable.strings @@ -0,0 +1,415 @@ +/* + Localizable.strings + Antidote + + Created by Dmytro Vorobiov on 08/10/15. + Copyright © 2015 dvor. All rights reserved. +*/ + +/* + Translation is done with Transifex service. + See https://www.transifex.com/antidote/antidote-ios/ +*/ + +/* Login screen text */ +"login_or_label" = "lub"; +/* Login screen text */ +"create_account" = "Utwórz konto"; +/* Login screen text */ +"import_profile" = "Importuj profil"; +/* Password field */ +"password" = "Hasło"; +/* Login button */ +"log_in" = "Logowanie"; +/* Login screen text */ +"create_profile" = "Utwórz profil"; +/* Login screen text */ +"import_to_antidote" = "Importuj do Antidote"; +/* Login screen text */ +"create_account_username_title" = "Jak kontakty będą Cie widzieć?"; +/* Login screen text */ +"create_account_username_placeholder" = "Użytkownik"; +/* Login screen text */ +"create_account_profile_title" = "Jak wywołać ten profil?"; +/* Login screen text */ +"create_account_profile_placeholder" = "Nazwa profilu"; +/* Login screen text */ +"create_account_profile_hint" = "np. Dom, Iphone"; +/* Login screen text */ +"set_password_title" = "Ustaw hasło"; +/* Login screen text */ +"set_password_hint" = "Hasło jest wymagane dla ochrony twoich danych. Przechowuj go w bezpiecznym dla Ciebie miejscu. Utracone hasło nie może być odzyskane."; +/* Login button */ +"create_account_next_button" = "Dalej"; +/* Login button */ +"create_account_go_button" = "Idź"; +/* Default status message */ +"default_user_status_message" = "Tox dla Anidote"; + +/* PIN screen text */ +"pin_enter_to_unlock" = "Wprowadź swój kod PIN do odblokowania"; +/* PIN screen text */ +"pin_set" = "Ustaw PIN"; +/* PIN screen text */ +"pin_confirm" = "Potwierdź PIN"; +/* PIN screen error */ +"pin_do_not_match" = "PINy są różne. Spróbuj ponownie"; +/* PIN screen error */ +"pin_incorrect" = "Nieprawidłowy PIN"; +/* PIN screen error details */ +"pin_failed_attempts" = "Nieudane próby: %@"; +/* PIN screen message shown on log out */ +"pin_logout_message" = "Zbyt wiele nieudanych prób. Nastąpiło wylogowanie."; +/* PIN screen screen */ +"pin_enabled" = "Włącz PIN"; +/* PIN screen screen */ +"pin_touch_id_enabled" = "Udostępnij ID"; +/* PIN screen screen */ +"pin_description" = "Zapobiegnij nieuprawnionemu dostępowi do programu aktywując kod PIN."; +/* PIN screen screen */ +"pin_touch_id_description" = "Jako alternatywy do PIN-u odcisku palca."; +/* PIN screen screen */ +"pin_lock_timeout" = "Blokada czasowa"; +/* PIN screen screen */ +"pin_lock_immediately" = "Natychmiast"; +/* PIN screen screen */ +"pin_lock_30_seconds" = "30 sekund"; +/* PIN screen screen */ +"pin_lock_1_minute" = "1 minuta"; +/* PIN screen screen */ +"pin_lock_2_minutes" = "2 minuty"; +/* PIN screen screen */ +"pin_lock_5_minutes" = "5 minut"; + +/* Label shown when connecting to Tox network */ +"connecting_label" = "Łącze ..."; + +/* Tab name and screen name */ +"contacts_title" = "Kontakty"; +/* Tab name and screen name */ +"chats_title" = "Czaty"; +/* Tab name and screen name */ +"settings_title" = "Ustawienia"; +/* Tab name and screen name */ +"profile_title" = "Profil"; + +/* No contacts placeholder text */ +"contact_no_contacts" = "Brak kontaktów"; +/* No contacts placeholder text */ +"contact_no_contacts_add_contact" = "Dodaj kontakt\nlub\n"; +/* No contacts placeholder text */ +"contact_no_contacts_share_tox_id" = "udostępnij swój Tox ID"; +/* Contact request section title */ +"contact_requests_section" = "Zapytania kontaktowe"; +/* Contact last seen status */ +"contact_last_seen" = "Ostatnio widziany: %@"; +/* Screen name */ +"contact_request" = "Prośba kontaktu"; +/* Contact request button */ +"contact_request_decline" = "Odmowa"; +/* Contact request button */ +"contact_request_accept" = "Akceptacja"; +/* Contact request confirmation */ +"contact_request_delete_title" = "Skasować zadanie, prośbę kontaktu?"; +/* Text shown when contact was deleted */ +"contact_deleted" = "Usunięto kontakt"; + +/* Share Tox ID text */ +"show_qr_code" = "Pokaż QR-Kod"; +/* Share Tox ID text */ +"copy" = "Kopiuj"; + +/* Add contat screen name */ +"add_contact_title" = "Dodaj kontakt"; +/* Add contat button */ +"add_contact_send" = "Wyślij"; +/* Add contat placeholder text */ +"add_contact_tox_id_placeholder" = "Wprowadź Tox-ID"; +/* Add contat placeholder text */ +"add_contact_or_label" = "lub"; +/* Add contat button */ +"add_contact_use_qr" = "Użyj kodu QR"; +/* Add contat placeholder text */ +"add_contact_default_message_title" = "Wiadomość"; +/* Add contat default text sended to contact */ +"add_contact_default_message_text" = "Cześć, witaj! Czy możesz dodać mnie do listy twoich kontaktów?"; +/* Add contat error */ +"add_contact_wrong_qr" = "Niepoprawny kod QR. Powinien on zawierać Tox ID"; + +/* User name text */ +"name" = "Nazwisko"; +/* User nickname text */ +"nickname" = "Ksywka"; +/* User status message text */ +"status_message" = "Status wiadomości"; +/* User status text */ +"status_title" = "Status"; +/* User Tox ID text */ +"my_tox_id" = "Mój Tox ID"; +/* User public key text */ +"public_key" = "Klucz publiczny"; +/* Share Tox ID text */ +"show_qr" = "Pokaż kod QR"; +/* Profile menu item / screen name */ +"profile_details" = "Dane profilu"; +/* Profile button */ +"logout_button" = "Wyloguj się"; + +/* QR code screen button */ +"qr_close_button" = "Zamknij"; + +/* Chat screen placeholder */ +"chat_no_chats" = "Brak czatów"; +/* Chats screen message text */ +"chat_outgoing_file" = "Wysyłany plik:"; +/* Chats screen message text */ +"chat_incoming_file" = "Odbierany plik:"; +/* Chats screen message text */ +"chat_call_finished" = "Rozmowa zakończona"; +/* Chats screen message text */ +"chat_unanwered_call" = "Rozmowa nieodebrana"; +/* Chat button */ +"chat_send_button" = "Wyślij"; +/* Chat notification toast */ +"chat_new_messages" = "↓ Nowa wiadomość"; +/* Chat call information */ +"chat_call_message" = "Połączenie, "; +/* Chat call information */ +"chat_missed_call_message" = "Rozmowa nieodebrana"; +/* Item present in the menu on long press on message */ +"chat_more_menu_item" = "Więcej"; + +/* Status message */ +"status_offline" = "Niedostępny"; +/* Status message */ +"status_online" = "Dostępny"; +/* Status message */ +"status_away" = "Zaraz wracam"; +/* Status message */ +"status_busy" = "Zajęty"; + +/* Notification text */ +"notification_new_message" = "Nowa wiadomość"; +/* Notification text */ +"notification_incoming_contact_request" = "Nadchodząca prośba kontaktu"; +/* Notification text */ +"notification_is_calling" = "telefonuje"; +/* Notification text */ +"notification_incoming_file" = "Nadchodzący plik"; + +/* Settings menu / screen name */ +"settings_about" = "O nas"; +/* Settings menu / screen name */ +"settings_faq" = "Najczęstsze pytania"; +/* Settings menu / screen name */ +"settings_advanced_settings" = "Ustawienia zaawansowane"; +/* About screen menu */ +"settings_antidote_version" = "Wersja programu Antidote"; +/* About screen menu */ +"settings_antidote_build" = "Wersja kompilacji Antidote"; +/* About screen menu */ +"settings_toxcore_version" = "Wersja Toxcore"; +/* About screen menu */ +"settings_acknowledgements" = "Podziękowania"; +/* Settings screen menu */ +"settings_autodownload_images" = "Automatycznie pobieranie plików"; +/* Settings screen menu */ +"settings_autodownload_images_description" = "Automatycznie pobieraj przychodzące pliki."; +/* Settings screen menu */ +"settings_notifications_message_preview" = "Przegląd powiadomień"; +/* Settings screen menu */ +"settings_notifications_description" = "Jeżeli aplikacja będzie działa w tle, to masz możliwość odbioru powiadomień jeszcze przez okres 10-u minut."; +/* Settings screen menu */ +"settings_udp_enabled" = "Uruchom transmisje poprzez UDP"; +/* Settings screen menu */ +"settings_restore_default" = "Przywróć domyślne ustawienia"; +/* Settings screen autodownload images option */ +"settings_never" = "Nigdy"; +/* Settings screen autodownload images option */ +"settings_wifi" = "Wi-Fi"; +/* Settings screen autodownload images option */ +"settings_using_wifi" = "Użyj do połączeń internetu bezprzewodowego Wi-Fi"; +/* Settings screen autodownload images option */ +"settings_always" = "Zawsze"; + +/* Profile settings menu */ +"change_password" = "Zmień hasło"; +/* Profile settings menu */ +"delete_password" = "Usuń Hasło"; +/* Profile settings menu */ +"old_password" = "Stare Hasło"; +/* Change password text */ +"new_password" = "Nowe Hasło"; +/* Change password text */ +"repeat_password" = "Powtórz hasło"; +/* Change password button */ +"change_password_done" = "Zakończ"; +/* Change password error */ +"password_is_empty_error" = "Ta wartość nie może być pusta"; +/* Change password error */ +"wrong_old_password" = "Niepoprawne hasło"; +/* Change password error */ +"passwords_do_not_match" = "Hasło nie jest identyczne"; + +/* Source of photo to take */ +"photo_from_camera" = "Aparat"; +/* Source of photo to take */ +"photo_from_photo_library" = "Biblioteka zdjęć"; +/* Error while converting avatar image */ +"change_avatar_error_convert_image" = "Brak możliwości przekształcenia obrazu"; + +/* Alert text when sending file to contacts */ +"file_send_to_contact" = "Wyślij do osoby"; + +/* Profile menu item */ +"export_profile" = "Eksportuj profil"; +/* Profile menu item */ +"delete_profile" = "Skasuj profil"; +/* Delete profile confirmation */ +"delete_profile_confirmation_title_1" = "Czy skasować profil?"; +/* Delete profile confirmation */ +"delete_profile_confirmation_title_2" = "Czy na pewno?"; +/* Delete profile confirmation */ +"delete_profile_confirmation_message" = "Przeprowadzenie niniejszej operacji nie może być cofnięte"; + +/* Call screen text */ +"call_incoming" = "Rozmowa przychodząca"; +/* Call screen text */ +"call_ended" = "Rozmowa zakończona"; +/* Call screen text */ +"call_reaching" = "Ustanawiam połączenie..."; + +/* File message text */ +"chat_file_cancelled" = "Anulowano"; +/* File message text */ +"chat_waiting" = "Oczekuje..."; +/* File message text */ +"chat_paused" = "Wstrzymany"; + +/* Deleting chat confirmation */ +"delete_chat_title" = "Skasować tego czata i jego wiadomości?"; +/* Deleting contat confirmation */ +"delete_contact_title" = "Skasować ten kontakt?\nHistoria korespondencji będzie skasowana."; +/* Deleting contat request confirmation */ +"delete_contact_request_title" = "Skasować to żądanie kontaktu?"; +/* Deleting single message in chat */ +"delete_single_message" = "Skasuj wiadomość"; +/* Deleting multiple messages in chat. */ +"delete_multiple_messages" = "Skasuj wiadomości"; +/* Deleting all messages in chat. */ +"delete_all_messages" = "Skasuj wszystko"; +/* Delete button */ +"alert_delete" = "Usuń"; +/* Delete button */ +"alert_cancel" = "Anuluj"; + +/* Error while creating new profile */ +"login_enter_username_and_profile" = "Wprowadź nazwę użytkownika i nazwę profilu."; +/* Error while creating new profile */ +"login_profile_already_exists" = "Wprowadzona nazwa profilu jest już niestety zajęta"; + +/* General error title */ +"error_title" = "Błąd"; +/* General error button */ +"error_ok_button" = "OK"; +/* General error button */ +"error_retry_button" = "Powtórz"; +/* Error */ +"error_contact_not_connected" = "Osoba jest niedostępna"; +/* Error */ +"error_too_many_files" = "Zbyt duża liczba przesyłanych plików"; +/* Error */ +"error_internal_message" = "Błąd wewnętrzny aplikacji"; +/* Error */ +"error_wrong_password_title" = "Niepoprawne hasło"; +/* Error */ +"error_wrong_password_message" = "Hasło zawiera niedopuszczalne symbole."; +/* Error */ +"error_import_not_exist_title" = "Brak możliwości importu pliku tox"; +/* Error */ +"error_import_not_exist_message" = "Plik nie istnieje."; +/* Error */ +"error_decrypt_title" = "Brak możliwości rozkodowania pliku tox"; +/* Error */ +"error_decrypt_empty_data_message" = "Wprowadzone dane są niepełne."; +/* Error */ +"error_decrypt_bad_format_message" = "Format pliku jest niedozwolony bądź plik jest uszkodzony."; +/* Error */ +"error_decrypt_wrong_password_message" = "Hasło jest niepoprawne lub plik uszkodzony."; +/* Error */ +"error_general_unknown_message" = "Nieznany błąd."; +/* Error */ +"error_general_no_memory_message" = "Brak wystarczającej ilości pamięci."; +/* Error */ +"error_general_bind_port_message" = "Brak możliwości otworzenia portu komunikacji."; +/* Error */ +"error_general_profile_encrypted_message" = "Profil jest zaszyfrowany."; +/* Error */ +"error_general_bad_format_message" = "Plik ma niepoprawny format lub jest uszkodzony."; +/* Error */ +"error_proxy_title" = "Błąd serwera proxy"; +/* Error */ +"error_proxy_invalid_address_message" = "Adres serwera proxy ma niepoprawny format."; +/* Error */ +"error_proxy_invalid_port_message" = "Port proxy jest niepoprawny."; +/* Error */ +"error_proxy_host_not_resolved_message" = "Translacja DNS-IP Proxy hosta jest niemożliwa."; + +/* Error */ +"error_name_too_long" = "Nazwa jest zbyt długa."; +/* Error */ +"error_status_message_too_long" = "Status wiadomości jest zbyt długi"; + +/* Error */ +"error_contact_request_too_long" = "Wiadomość jest zbyt długa"; +/* Error */ +"error_contact_request_no_message" = "Brak określonej wiadomości"; +/* Error */ +"error_contact_request_own_key" = "Dodanie samego siebie do listy kontaktów jest niemożliwe"; +/* Error */ +"error_contact_request_already_sent" = "Zapytanie zostało już wysłane"; +/* Error */ +"error_contact_request_bad_checksum" = "Niepoprawna suma kontrolna, proszę sprawdzić wprowadzony Tox ID"; +/* Error */ +"error_contact_request_new_nospam" = "Niepoprawna wartość nospam, proszę sprawdzić Tox ID"; + +/* Call error */ +"call_error_already_in_call" = "Przeprowadza rozmowę"; +/* Call error */ +"call_error_contact_is_offline" = "Osoba jest aktualnie niedostępna"; +/* Call error */ +"call_error_no_active_call" = "Brak aktywnych połączeń"; + +/* Error while using color theme */ +"theme_error_cannot_open" = "Niniejszy temat graficzny do programu czyli tzw. skórka ma niepoprawny format"; + +/* Tab chats badge ending */ +"accessibility_chats_ending" = "nieodczytane czaty"; +/* Avatar button label in settings */ +"accessibility_avatar_button_label" = "Avatar"; +/* Avatar button hint in settings */ +"accessibility_avatar_button_hint" = "Ustawia lub usuwa awatar."; +/* Chat button label in contact screen */ +"accessibility_chat_button_label" = "Chat"; +/* Chat button hint in contact screen */ +"accessibility_chat_button_hint" = "Otwiera okno dialogowe czatu."; +/* Call button label in contact screen */ +"accessibility_call_button_label" = "Połączenie głosowe"; +/* Call button hint in contact screen */ +"accessibility_call_button_hint" = "Rozpoczyna połączenie głosowe."; +/* Video button label in contact screen */ +"accessibility_video_button_label" = "Połączenie wideo"; +/* Video button hint in contact screen */ +"accessibility_video_button_hint" = "Rozpoczyna połączenie wideo."; +/* Tap to copy hint */ +"accessibility_show_copy_hint" = "Pokazuje menu kopiowania."; +/* Tap to edit value hint */ +"accessibility_edit_value_hint" = "Edytuje wartość."; +/* Incoming message label */ +"accessibility_incoming_message_label" = "Message"; +/* Outgoing message label */ +"accessibility_outgoing_message_label" = "Twoja wiadomość"; +/* Message shown on chat list when contact is typing */ +"chat_is_typing_text" = "pisze..."; +/* Text shown in chat when there are undelivered faux offline messages */ +"chat_pending_faux_offline_messages" = "Niedostarczone wiadomości będą wysyłane, gdy zarówno Ty, jak i znajomy będziecie online."; diff --git a/Antidote/pl.lproj/import-profile.html b/Antidote/pl.lproj/import-profile.html new file mode 100644 index 0000000..90bfb7b --- /dev/null +++ b/Antidote/pl.lproj/import-profile.html @@ -0,0 +1,9 @@ + +

Importuj profil Tox

+ +
    +
  1. Wyślij plik ".tox" do urządzenia używając aplikacji (Mail, Dropbox, itp.).
  2. +
  3. Użyj opcji "Otwórz w" dla tego pliku.
  4. +
  5. Wybierz Antidote z listy dostępnych aplikacji.
  6. +
  7. Wybierz nazwę twojego nowego profilu i wciśnij OK.
  8. +
diff --git a/Antidote/pt-BR.lproj/AppStoreLocalizable.strings b/Antidote/pt-BR.lproj/AppStoreLocalizable.strings new file mode 100644 index 0000000..d6fbb04 --- /dev/null +++ b/Antidote/pt-BR.lproj/AppStoreLocalizable.strings @@ -0,0 +1,54 @@ +/* + AppStoreLocalizable.strings + Antidote + + Created by Dmytro Vorobiov on 08/02/17. + Copyright © 2017 dvor. All rights reserved. +*/ + +/* Name of friend for the App Store screenshot. Should be fully random, no real people here. Can be generated with service like http://www.fakenamegenerator.com/ */ +"app_store_screenshot_friend_female_1" = "Mary Cokley"; +/* Name of friend for the App Store screenshot. Should be fully random, no real people here. Can be generated with service like http://www.fakenamegenerator.com/ */ +"app_store_screenshot_friend_female_2" = "Shirley Knox"; +/* Name of friend for the App Store screenshot. Should be fully random, no real people here. Can be generated with service like http://www.fakenamegenerator.com/ */ +"app_store_screenshot_friend_female_3" = "Jennifer Smith"; +/* Name of friend for the App Store screenshot. Should be fully random, no real people here. Can be generated with service like http://www.fakenamegenerator.com/ */ +"app_store_screenshot_friend_female_4" = "Marina Dixon"; +/* Name of friend for the App Store screenshot. Should be fully random, no real people here. Can be generated with service like http://www.fakenamegenerator.com/ */ +"app_store_screenshot_friend_female_5" = "Carol Ortega"; +/* Name of friend for the App Store screenshot. Should be fully random, no real people here. Can be generated with service like http://www.fakenamegenerator.com/ */ +"app_store_screenshot_friend_male_1" = "Michael Sharpe"; +/* Name of friend for the App Store screenshot. Should be fully random, no real people here. Can be generated with service like http://www.fakenamegenerator.com/ */ +"app_store_screenshot_friend_male_2" = "Charles Donahue"; +/* Name of friend for the App Store screenshot. Should be fully random, no real people here. Can be generated with service like http://www.fakenamegenerator.com/ */ +"app_store_screenshot_friend_male_3" = "Lee Murdock"; +/* Name of friend for the App Store screenshot. Should be fully random, no real people here. Can be generated with service like http://www.fakenamegenerator.com/ */ +"app_store_screenshot_friend_male_4" = "Wayne Henderson"; +/* Name of friend for the App Store screenshot. Should be fully random, no real people here. Can be generated with service like http://www.fakenamegenerator.com/ */ +"app_store_screenshot_friend_male_5" = "Robert Newton"; + +/* Demo conversation for the App Store screenshot */ +"app_store_screenshot_conversation_1" = "Is Antidote really that secure?"; +/* Demo conversation for the App Store screenshot */ +"app_store_screenshot_conversation_2" = "sure, it is peer-to-peer"; +/* Demo conversation for the App Store screenshot */ +"app_store_screenshot_conversation_3" = "And what does that mean? Peer-to-peer? 😄"; +/* Demo conversation for the App Store screenshot */ +"app_store_screenshot_conversation_4" = "you text me directly, the are no servers or things like that"; +/* Demo conversation for the App Store screenshot */ +"app_store_screenshot_conversation_5" = "+ it's encrypted 🔐😎"; +/* Demo conversation for the App Store screenshot */ +"app_store_screenshot_conversation_6" = "Cool!"; +/* Demo conversation for the App Store screenshot */ +"app_store_screenshot_conversation_7" = "I'll give it a go then"; + +/* Demo chat message for the App Store screenshot */ +"app_store_screenshot_chat_message_1" = "😂😂😂"; +/* Demo chat message for the App Store screenshot */ +"app_store_screenshot_chat_message_2" = "dinner tonight?"; +/* Demo chat message for the App Store screenshot */ +"app_store_screenshot_chat_message_3" = "I think I know what you are talking about"; +/* Demo chat message for the App Store screenshot */ +"app_store_screenshot_chat_message_4" = "Sure, thanks!"; +/* Demo chat message for the App Store screenshot */ +"app_store_screenshot_chat_message_5" = "yep"; diff --git a/Antidote/pt-BR.lproj/InfoPlist.strings b/Antidote/pt-BR.lproj/InfoPlist.strings new file mode 100644 index 0000000..b79a4d0 --- /dev/null +++ b/Antidote/pt-BR.lproj/InfoPlist.strings @@ -0,0 +1,16 @@ +/* + InfoPlist.strings + Antidote + + Created by Dmytro Vorobiov on 15/11/16. + Copyright © 2016 dvor. All rights reserved. +*/ + +/* Camera usage alert description */ +"NSCameraUsageDescription" = "You can use video calls, send photos and videos, scan QR codes."; + +/* Microphone usage alert description */ +"NSMicrophoneUsageDescription" = "You can use audio and video calls."; + +/* Photo library usage alert description */ +"NSPhotoLibraryUsageDescription" = "You can send photos and videos."; \ No newline at end of file diff --git a/Antidote/pt-BR.lproj/Localizable.strings b/Antidote/pt-BR.lproj/Localizable.strings new file mode 100644 index 0000000..40a9be4 --- /dev/null +++ b/Antidote/pt-BR.lproj/Localizable.strings @@ -0,0 +1,404 @@ + + +/* Login screen text */ +"login_or_label" = "ou"; +/* Login screen text */ +"create_account_profile_placeholder" = "Nome de perfil"; +/* Login screen text */ +"set_password_hint" = "Uma senha é necessária para proteger seus dados. Mantenha-a segura - uma vez perdida, ela não pode ser restaurada."; +/* PIN screen screen */ +"pin_enabled" = "Ativar PIN"; +/* PIN screen message shown on log out */ +"pin_logout_message" = "Muitas tentativas falhas. Você foi desconectado."; +/* Contact request button */ +"contact_request_decline" = "Recusar"; +/* Add contat placeholder text */ +"add_contact_default_message_title" = "Mensagem"; +/* Login button */ +"log_in" = "Entrar"; +/* Login screen text */ +"create_profile" = "Criar perfil"; +/* Login screen text */ +"create_account_username_title" = "Como os contatos irão te ver?"; +/* Login screen text */ +"create_account_username_placeholder" = "Nome de usuário"; +/* Login screen text */ +"create_account_profile_title" = "Como chamar este perfil?"; +/* Login screen text */ +"set_password_title" = "Definir Senha"; +/* Login button */ +"create_account_next_button" = "Próximo"; +/* Default status message */ +"default_user_status_message" = "Toxing no Antidote"; + +/* PIN screen text */ +"pin_enter_to_unlock" = "Entre seu PIN para desbloquear"; +/* PIN screen text */ +"pin_set" = "Definir PIN"; +/* PIN screen text */ +"pin_confirm" = "Confirmar PIN"; +/* PIN screen error */ +"pin_do_not_match" = "PINs não conferem. Tente novamente"; +/* PIN screen error */ +"pin_incorrect" = "PIN incorreto"; +/* PIN screen screen */ +"pin_touch_id_enabled" = "Ativar Touch ID"; +/* PIN screen screen */ +"pin_description" = "Prevenir acesso não-autorizado ao Antidote com um PIN."; +/* PIN screen screen */ +"pin_lock_timeout" = "Tempo de bloqueio"; +/* PIN screen screen */ +"pin_lock_2_minutes" = "2 minutos"; +/* PIN screen screen */ +"pin_lock_5_minutes" = "5 minutos"; + +/* Label shown when connecting to Tox network */ +"connecting_label" = "Conectando..."; + +/* Tab name and screen name */ +"contacts_title" = "Contatos"; +/* Tab name and screen name */ +"chats_title" = "Conversas"; +/* Tab name and screen name */ +"settings_title" = "Configurações"; +/* Tab name and screen name */ +"profile_title" = "Perfil"; + +/* No contacts placeholder text */ +"contact_no_contacts" = "Sem contatos"; +/* No contacts placeholder text */ +"contact_no_contacts_add_contact" = "Adicionar um contato\nou\n"; +/* No contacts placeholder text */ +"contact_no_contacts_share_tox_id" = "compartilhar seu ID do Tox"; +/* Contact request section title */ +"contact_requests_section" = "Solicitações de contato"; +/* Contact request button */ +"contact_request_accept" = "Aceitar"; + +/* Share Tox ID text */ +"show_qr_code" = "Exibir código QR"; +/* Share Tox ID text */ +"copy" = "Copiar"; + +/* Add contat screen name */ +"add_contact_title" = "Adicionar contato"; +/* Add contat placeholder text */ +"add_contact_or_label" = "ou"; +/* Add contat button */ +"add_contact_use_qr" = "Usar código QR"; +/* Add contat error */ +"add_contact_wrong_qr" = "Código QR inválido. Ele deve conter um ID do Tox"; +/* User Tox ID text */ +"my_tox_id" = "Meu ID do Tox"; +/* User public key text */ +"public_key" = "Chave Pública"; +/* Profile menu item / screen name */ +"profile_details" = "Detalhes do perfil"; +/* Profile button */ +"logout_button" = "Sair"; + +/* QR code screen button */ +"qr_close_button" = "Fechar"; + +/* Chat screen placeholder */ +"chat_no_chats" = "Sem conversas"; +/* Chats screen message text */ +"chat_outgoing_file" = "Arquivo de saída:"; +/* Chats screen message text */ +"chat_incoming_file" = "Arquivo de entrada:"; +/* Login screen text */ +"create_account" = "Criar Conta"; +/* Login screen text */ +"import_profile" = "Importar Perfil"; +/* PIN screen error details */ +"pin_failed_attempts" = "Tentativas erradas: %@"; +/* Password field */ +"password" = "Senha"; +/* Login screen text */ +"import_to_antidote" = "Importar para o Antidote"; +/* Login screen text */ +"create_account_profile_hint" = "ex. Home, iPhone"; +/* Login button */ +"create_account_go_button" = "Ir"; +/* PIN screen screen */ +"pin_lock_30_seconds" = "30 segundos"; +/* PIN screen screen */ +"pin_lock_1_minute" = "1 minuto"; +/* Contact last seen status */ +"contact_last_seen" = "Visto por último: %@"; +/* PIN screen screen */ +"pin_touch_id_description" = "Usar sua impressão digital como uma alternativa ao PIN."; +/* PIN screen screen */ +"pin_lock_immediately" = "Imediatamente"; +/* Screen name */ +"contact_request" = "Solicitações de contato"; +/* Contact request confirmation */ +"contact_request_delete_title" = "Deletar solicitação de contato?"; +/* Add contat placeholder text */ +"add_contact_tox_id_placeholder" = "Entrar ID do Tox"; +/* Text shown when contact was deleted */ +"contact_deleted" = "Contato deletado"; +/* Add contat button */ +"add_contact_send" = "Enviar"; +/* Add contat default text sended to contact */ +"add_contact_default_message_text" = "Olá! Poderia por favor me adicionar à sua lista de contatos?"; +/* User nickname text */ +"nickname" = "Apelido"; +/* User status message text */ +"status_message" = "Mensagem de status"; +/* User status text */ +"status_title" = "Status"; + +/* User name text */ +"name" = "Nome"; +/* Chats screen message text */ +"chat_call_finished" = "Chamada finalizada"; +/* Share Tox ID text */ +"show_qr" = "Exibir QR"; +/* Chats screen message text */ +"chat_unanwered_call" = "Chamada não atendida"; +/* Text shown in chat when there are undelivered faux offline messages */ +"chat_pending_faux_offline_messages" = "Mensagens não entregues serão enviadas quando você e seu contato estiverem online."; + +/* Status message */ +"status_offline" = "Desconectado"; +/* Status message */ +"status_online" = "Online"; +/* Status message */ +"status_away" = "Ausente"; +/* Status message */ +"status_busy" = "Ocupado"; + +/* Notification text */ +"notification_new_message" = "Nova mensagem"; +/* Error */ +"error_internal_message" = "Erro interno"; +/* Error */ +"error_general_bind_port_message" = "Impossível vincular a uma porta."; +/* Error */ +"error_proxy_invalid_port_message" = "Porta de proxy inválida."; +/* Error */ +"error_proxy_host_not_resolved_message" = "Host de proxy não pode ser resolvido."; + +/* Error */ +"error_name_too_long" = "O nome é longo demais."; +/* Error */ +"error_contact_request_already_sent" = "Solicitação de contato já enviada"; +/* Settings screen menu */ +"settings_notifications_message_preview" = "Prévia da notificação"; +/* Source of photo to take */ +"photo_from_photo_library" = "Biblioteca de fotos"; +/* Chat button */ +"chat_send_button" = "Enviar"; +/* Item present in the menu on long press on message */ +"chat_more_menu_item" = "Mais"; +/* Settings menu / screen name */ +"settings_faq" = "FAQ"; +/* About screen menu */ +"settings_acknowledgements" = "Agradecimentos"; +/* Settings screen menu */ +"settings_notifications_description" = "Quando a aplicação fica em plano de fundo, você ainda recebe notificações em até 10 minutos."; +/* Settings screen menu */ +"settings_udp_enabled" = "Ativar UDP"; +/* Settings screen menu */ +"settings_restore_default" = "Restaurar configurações padrão"; +/* Settings screen autodownload images option */ +"settings_using_wifi" = "Usando Wi-Fi"; +/* Settings screen autodownload images option */ +"settings_always" = "Sempre"; + +/* Alert text when sending file to contacts */ +"file_send_to_contact" = "Enviar ao contato"; +/* Chat call information */ +"chat_call_message" = "Chamada, "; +/* Message shown on chat list when contact is typing */ +"chat_is_typing_text" = "está digitando..."; +/* Chat notification toast */ +"chat_new_messages" = "↓ Novas mensagens"; +/* Chat call information */ +"chat_missed_call_message" = "Chamada perdida"; +/* Notification text */ +"notification_incoming_file" = "Recebendo arquivo"; +/* Settings menu / screen name */ +"settings_advanced_settings" = "Configurações avançadas"; +/* About screen menu */ +"settings_antidote_version" = "Versão do Antidote"; +/* About screen menu */ +"settings_antidote_build" = "Compilação do Antidote"; +/* Notification text */ +"notification_incoming_contact_request" = "Recebendo solicitação de contato"; +/* Notification text */ +"notification_is_calling" = "está em chamada"; +/* Settings screen menu */ +"settings_autodownload_images" = "Baixar arquivos automaticamente"; + +/* Profile settings menu */ +"change_password" = "Trocar senha"; +/* Change password error */ +"wrong_old_password" = "Senha incorreta"; + +/* Source of photo to take */ +"photo_from_camera" = "Câmera"; +/* Error while converting avatar image */ +"change_avatar_error_convert_image" = "Impossível converter imagem"; +/* Delete profile confirmation */ +"delete_profile_confirmation_message" = "Esta operação não pode ser desfeita"; + +/* Settings menu / screen name */ +"settings_about" = "Sobre"; +/* About screen menu */ +"settings_toxcore_version" = "Versão do Toxcore"; +/* Settings screen menu */ +"settings_autodownload_images_description" = "Baixar automaticamente os arquivos recebidos."; +/* Delete profile confirmation */ +"delete_profile_confirmation_title_2" = "Você tem certeza?"; +/* Change password error */ +"password_is_empty_error" = "A senha não deve ser vazia"; +/* Settings screen autodownload images option */ +"settings_never" = "Nunca"; +/* Profile settings menu */ +"delete_password" = "Deletar senha"; +/* Change password text */ +"new_password" = "Nova senha"; +/* Change password text */ +"repeat_password" = "Repita a senha"; +/* Settings screen autodownload images option */ +"settings_wifi" = "Wi-Fi"; +/* Profile settings menu */ +"old_password" = "Senha antiga"; +/* Change password button */ +"change_password_done" = "Concluído"; +/* Change password error */ +"passwords_do_not_match" = "As senhas não coincidem"; + +/* Profile menu item */ +"export_profile" = "Exportar perfil"; +/* Profile menu item */ +"delete_profile" = "Deletar perfil"; +/* Delete profile confirmation */ +"delete_profile_confirmation_title_1" = "Deletar este perfil?"; + +/* File message text */ +"chat_file_cancelled" = "Cancelado"; +/* File message text */ +"chat_waiting" = "Aguardando..."; +/* File message text */ +"chat_paused" = "Pausado"; +/* Call screen text */ +"call_reaching" = "Contatando..."; + +/* Call screen text */ +"call_incoming" = "Recebendo chamada"; +/* Call screen text */ +"call_ended" = "Chamada finalizada"; +/* Deleting contat confirmation */ +"delete_contact_title" = "Deletar este contato?\nO histórico de mensagens será perdido."; +/* Error */ +"error_too_many_files" = "Há transferências de arquivos ativas demais"; +/* Error */ +"error_wrong_password_title" = "Senha incorreta"; + +/* Deleting chat confirmation */ +"delete_chat_title" = "Deletar esta conversa e o histórico de mensagens?"; +/* Deleting contat request confirmation */ +"delete_contact_request_title" = "Deletar esta solicitação de contato?"; +/* Deleting single message in chat */ +"delete_single_message" = "Deletar mensagem"; +/* Deleting multiple messages in chat. */ +"delete_multiple_messages" = "Deletar mensagens"; +/* Delete button */ +"alert_cancel" = "Cancelar"; +/* General error button */ +"error_ok_button" = "OK"; +/* Error */ +"error_wrong_password_message" = "A senha contém símbolos incorretos."; +/* Deleting all messages in chat. */ +"delete_all_messages" = "Deletar tudo"; +/* Delete button */ +"alert_delete" = "Deletar"; +/* Error while creating new profile */ +"login_profile_already_exists" = "Um perfil com este nome já existe"; + +/* General error title */ +"error_title" = "Erro"; + +/* Error while creating new profile */ +"login_enter_username_and_profile" = "Por favor insira o nome de usuário e o nome de perfil."; +/* General error button */ +"error_retry_button" = "Tentar novamente"; +/* Error */ +"error_contact_not_connected" = "O contato não está online"; +/* Error */ +"error_decrypt_empty_data_message" = "Alguns dados de entrada estavam vazios."; +/* Error */ +"error_decrypt_wrong_password_message" = "A senha está incorreta ou o arquivo está corrompido."; +/* Error */ +"error_general_unknown_message" = "Ocorreu um erro desconhecido."; +/* Error */ +"error_general_no_memory_message" = "Não há memória o suficiente."; +/* Error */ +"error_general_profile_encrypted_message" = "O perfil está criptografado."; +/* Error */ +"error_import_not_exist_title" = "Arquivo de salvamento do Tox não pôde ser importado"; +/* Error */ +"error_import_not_exist_message" = "O arquivo não existe."; +/* Error */ +"error_decrypt_bad_format_message" = "O arquivo tem o formato errado ou está corrompido."; + +/* Error */ +"error_contact_request_too_long" = "A mensagem é longa demais"; +/* Error */ +"error_contact_request_no_message" = "Nenhuma mensagem especificada"; +/* Error */ +"error_decrypt_title" = "O arquivo de salvamento do Tox não pode ser descriptografado"; +/* Error */ +"error_general_bad_format_message" = "O arquivo tem o formato errado ou está corrompido."; +/* Error */ +"error_proxy_title" = "Erro de proxy"; +/* Error */ +"error_proxy_invalid_address_message" = "Endereço de proxy tem um formato inválido."; +/* Error */ +"error_contact_request_bad_checksum" = "Checksum incorreto, por favor cheque o ID do Tox inserido"; +/* Error */ +"error_status_message_too_long" = "A mensagem de status é longa demais"; +/* Error */ +"error_contact_request_own_key" = "Não é possível adicionar si mesmo à lista de contatos"; +/* Error */ +"error_contact_request_new_nospam" = "Valor incorreto de nospam, por favor cheque o ID do Tox inserido"; +/* Call error */ +"call_error_contact_is_offline" = "O contato está offline"; +/* Call error */ +"call_error_no_active_call" = "Não há nenhuma chamada ativa"; +/* Avatar button hint in settings */ +"accessibility_avatar_button_hint" = "Define ou remove o avatar."; +/* Chat button label in contact screen */ +"accessibility_chat_button_label" = "Conversa"; +/* Chat button hint in contact screen */ +"accessibility_chat_button_hint" = "Abre a caixa de diálogo do chat."; +/* Tap to edit value hint */ +"accessibility_edit_value_hint" = "Edita o valor."; + +/* Call error */ +"call_error_already_in_call" = "Já em chamada"; + +/* Error while using color theme */ +"theme_error_cannot_open" = "O tema não pôde ser aberto, o formato está incorreto"; +/* Tap to copy hint */ +"accessibility_show_copy_hint" = "Exibe o menu de cópia."; + +/* Tab chats badge ending */ +"accessibility_chats_ending" = "conversas não lidas"; +/* Avatar button label in settings */ +"accessibility_avatar_button_label" = "Avatar"; +/* Video button label in contact screen */ +"accessibility_video_button_label" = "Chamada de vídeo"; +/* Video button hint in contact screen */ +"accessibility_video_button_hint" = "Faz uma chamada de vídeo."; +/* Incoming message label */ +"accessibility_incoming_message_label" = "Mensagem"; +/* Call button label in contact screen */ +"accessibility_call_button_label" = "Chamada de áudio"; +/* Call button hint in contact screen */ +"accessibility_call_button_hint" = "Faz uma chamada de áudio."; +/* Outgoing message label */ +"accessibility_outgoing_message_label" = "Sua mensagem"; diff --git a/Antidote/pt-BR.lproj/import-profile.html b/Antidote/pt-BR.lproj/import-profile.html new file mode 100644 index 0000000..7f2b2f3 --- /dev/null +++ b/Antidote/pt-BR.lproj/import-profile.html @@ -0,0 +1,10 @@ + +

To import your Tox profile:

+ +
    +
  1. Send the ".tox" file to your device using any app (Mail, Dropbox, etc.).
  2. +
  3. Use "Open In" menu for this file.
  4. +
  5. Select Antidote in a list of available apps.
  6. +
  7. Check the name of your new profile and press OK.
  8. +
+
diff --git a/Antidote/pt.lproj/AppStoreLocalizable.strings b/Antidote/pt.lproj/AppStoreLocalizable.strings new file mode 100644 index 0000000000000000000000000000000000000000..3f83883781ab40037320a8d4bc9e212b89188067 GIT binary patch literal 7612 zcmeI1%Wl&^6oyBLRTqdyFx?;(NNBkffugEv78Kfos07O@O`MC8I#Did!yEBN+0aJ; zzW+={nTUo(7s!z;%l3FYmow*|bMf!rzshdQC2oT=arjPl)91|(PBtl=310P-;COhYtUy*tBra6fsItNx(0KcyD8VIyWp--`aFHL`TD%; zP`ae1&)A83?%udE*B!3gZkL(;TnD@#&|fmNT$^zc_k(kXwrZCk#ifl|qP&mPJ?@Lv zBYR4bJ*D=NYs1FgVjjuub#lUrFL)63C~ zl-u+eGmqM+JV7e25zW!G=bmY2$jq9h&-_n$mr;`ZsbP_@_LQ1|p^@19dZ&>Otf#cB zF?)Q2*2~$Fe)W_xlJ;Io?`^lqm=(@VcTDZj^rU^zwH8zA-xbJ# zYu=FCiICI2?|_{!l^6JEJNvr84t>au^M>7v2)hr+m~nK>GKa`}ihX)tQrKQT@p~EJ z=e?$4b`9*RAa{-T%nIAfsqMXruv1i5rlc(96D7s+7IlT)<;Ct+Wh%<8+8~u0c8Y&O zQu$kfUH-6(bCrWRR?1cMy-+o8S)+DRpqHcXgoWkB*~$?ZX@4Dq*3iDB>d0K!T>fk> z&QZSM9jD|ZlJY%QeFN(obyQ?359@K#|*qml{XjE zC&m_J#=i(-aTMZz#QfZqUAYVIAkN}8DVAA>LyH3Yw2WD<1uNs38!;+J9L?7vK1yGGx+*Rzml5XAsOxhL&#|vvpB2Y3L|A*qEMO`|&SwJ)oW+ER zt=mHvpI7KY?<%wVH|wdB*h5dzz=YN43*_2%foDh?>;`d=b?RgZ+9iP*RmLli?pe&h zI(ok@ZdF`@+6F#3W+H>0*Hd$`cYMMsWjBw_Y82bVfljfPz|2-=4}Vr>57u;-yvD}` zhE}|+zE&Ttso&d;)^Z49{{KM>{PeFN_&@O|E!G)!df-xSi*vz)$XZ4mHDk~JcbxN5 zoDqFvDVF10Wp?i-oU5!Z->ZqEmi&@fOL-gNq(~qB8Lf`W`CeZfqYmf0Ppj-w)^nF~ zpWI9TdcsPA-wwWb%nt0)()-+mr*ryD(9n8f9>=KDC{ywAL%JFL!y5%HE!#z2tTT=x KQ+D!Tj?o{Mwm*gd literal 0 HcmV?d00001 diff --git a/Antidote/pt.lproj/InfoPlist.strings b/Antidote/pt.lproj/InfoPlist.strings new file mode 100644 index 0000000000000000000000000000000000000000..6c333a86e6042a9b313f0a4b40846fa9afa0f57c GIT binary patch literal 978 zcmbu7K~KU!5QX2_U(xhP42X$bj0XZ26E&#O#ABfqNT4NcY2r`vPpaSSrcg~U*uzd| zW@p~ad)@D^fqDvb#tC$*RPV|((?)9*D%E#3CrY)%_jO~Ul3Yw}sf4W0Pm~iyE*FD0 z*9Ug0E#H#6jOZ0>-kknS6`2gQKto+=fE_wJVsed{X-B{9u+$2iK%bmTT~Is1i$O8W zKK_`^H++xPg^Ln)Psmo-*kSjWV|#o46Sm&Eiir9>)e+MY{0Kbjw7D@}p@l==kue6g zyT=Okpl3CaUJf|Z*3OXL8&0SA{@Gj@f}iR?aQqX2bQ+?O2V zYW){uBZHE&+-TS8KuDh literal 0 HcmV?d00001 diff --git a/Antidote/pt.lproj/Localizable.strings b/Antidote/pt.lproj/Localizable.strings new file mode 100644 index 0000000..895844b --- /dev/null +++ b/Antidote/pt.lproj/Localizable.strings @@ -0,0 +1,415 @@ +/* + Localizable.strings + Antidote + + Created by Dmytro Vorobiov on 08/10/15. + Copyright © 2015 dvor. All rights reserved. +*/ + +/* + Translation is done with Transifex service. + See https://www.transifex.com/antidote/antidote-ios/ +*/ + +/* Login screen text */ +"login_or_label" = "ou"; +/* Login screen text */ +"create_account" = "Criar Conta"; +/* Login screen text */ +"import_profile" = "Importar Perfil"; +/* Password field */ +"password" = "Palavra-Passe"; +/* Login button */ +"log_in" = "Entrar"; +/* Login screen text */ +"create_profile" = "Criar Perfil"; +/* Login screen text */ +"import_to_antidote" = "Importar para Antidote"; +/* Login screen text */ +"create_account_username_title" = "Como os contactos irão vê-lo?"; +/* Login screen text */ +"create_account_username_placeholder" = "Nome de Utilizador"; +/* Login screen text */ +"create_account_profile_title" = "Que nome deve ter este perfil"; +/* Login screen text */ +"create_account_profile_placeholder" = "Nome do perfil"; +/* Login screen text */ +"create_account_profile_hint" = "exemplo: Casa, iPhone"; +/* Login screen text */ +"set_password_title" = "Set Password"; +/* Login screen text */ +"set_password_hint" = "Password is required to protect your data. Keep it safe - once lost it cannot be restored."; +/* Login button */ +"create_account_next_button" = "Next"; +/* Login button */ +"create_account_go_button" = "Ir"; +/* Default status message */ +"default_user_status_message" = "Toxing com Antidote"; + +/* PIN screen text */ +"pin_enter_to_unlock" = "Enter your PIN to unlock"; +/* PIN screen text */ +"pin_set" = "Set PIN"; +/* PIN screen text */ +"pin_confirm" = "Confirm PIN"; +/* PIN screen error */ +"pin_do_not_match" = "PINs did not match. Try again"; +/* PIN screen error */ +"pin_incorrect" = "Incorrect PIN"; +/* PIN screen error details */ +"pin_failed_attempts" = "Failed attempts: %@"; +/* PIN screen message shown on log out */ +"pin_logout_message" = "Too many failed attempts. You have been logged out."; +/* PIN screen screen */ +"pin_enabled" = "Enable PIN"; +/* PIN screen screen */ +"pin_touch_id_enabled" = "Enable Touch ID"; +/* PIN screen screen */ +"pin_description" = "Prevent unauthorized access to Antidote with a PIN."; +/* PIN screen screen */ +"pin_touch_id_description" = "Use your fingerprint as an alternative to entering a PIN."; +/* PIN screen screen */ +"pin_lock_timeout" = "Lock Timeout"; +/* PIN screen screen */ +"pin_lock_immediately" = "Immediately"; +/* PIN screen screen */ +"pin_lock_30_seconds" = "30 Seconds"; +/* PIN screen screen */ +"pin_lock_1_minute" = "1 Minute"; +/* PIN screen screen */ +"pin_lock_2_minutes" = "2 Minutes"; +/* PIN screen screen */ +"pin_lock_5_minutes" = "5 Minutes"; + +/* Label shown when connecting to Tox network */ +"connecting_label" = "Ligando"; + +/* Tab name and screen name */ +"contacts_title" = "Contactos"; +/* Tab name and screen name */ +"chats_title" = "Conversas"; +/* Tab name and screen name */ +"settings_title" = "Configurações"; +/* Tab name and screen name */ +"profile_title" = "Perfil"; + +/* No contacts placeholder text */ +"contact_no_contacts" = "Nenhum contacto"; +/* No contacts placeholder text */ +"contact_no_contacts_add_contact" = "Adiciona contacto\nou\n"; +/* No contacts placeholder text */ +"contact_no_contacts_share_tox_id" = "partilha o teu Tox ID"; +/* Contact request section title */ +"contact_requests_section" = "Pedidos"; +/* Contact last seen status */ +"contact_last_seen" = "Online ontem a: %@"; +/* Screen name */ +"contact_request" = "Pedido de Contacto"; +/* Contact request button */ +"contact_request_decline" = "Rejeitar"; +/* Contact request button */ +"contact_request_accept" = "Aceitar"; +/* Contact request confirmation */ +"contact_request_delete_title" = "Rejeita o pedido"; +/* Text shown when contact was deleted */ +"contact_deleted" = "Deleted contact"; + +/* Share Tox ID text */ +"show_qr_code" = "Mostra o código QR"; +/* Share Tox ID text */ +"copy" = "Copiar"; + +/* Add contat screen name */ +"add_contact_title" = "Adicionar Contacto"; +/* Add contat button */ +"add_contact_send" = "Enviar"; +/* Add contat placeholder text */ +"add_contact_tox_id_placeholder" = "Introduza Tox ID"; +/* Add contat placeholder text */ +"add_contact_or_label" = "ou"; +/* Add contat button */ +"add_contact_use_qr" = "Usa Código QR"; +/* Add contat placeholder text */ +"add_contact_default_message_title" = "Mensagem"; +/* Add contat default text sended to contact */ +"add_contact_default_message_text" = "Olá! Podias por favor adicionar-me a tua lista de contactos?"; +/* Add contat error */ +"add_contact_wrong_qr" = "Código QR Errado. Deve conter o Tox ID"; + +/* User name text */ +"name" = "Nome"; +/* User nickname text */ +"nickname" = "Alcunha"; +/* User status message text */ +"status_message" = "Mensagem de Estado"; +/* User status text */ +"status_title" = "Estado"; +/* User Tox ID text */ +"my_tox_id" = "Tox ID"; +/* User public key text */ +"public_key" = "Chave Pública"; +/* Share Tox ID text */ +"show_qr" = "Mostra QR"; +/* Profile menu item / screen name */ +"profile_details" = "Detalhes Perfil"; +/* Profile button */ +"logout_button" = "Desligar"; + +/* QR code screen button */ +"qr_close_button" = "Fechar"; + +/* Chat screen placeholder */ +"chat_no_chats" = "Sem conversas"; +/* Chats screen message text */ +"chat_outgoing_file" = "Enviar ficheiro"; +/* Chats screen message text */ +"chat_incoming_file" = "Receber ficheiro"; +/* Chats screen message text */ +"chat_call_finished" = "Chamada terminada"; +/* Chats screen message text */ +"chat_unanwered_call" = "Chamada não atendida"; +/* Chat button */ +"chat_send_button" = "Enviar"; +/* Chat notification toast */ +"chat_new_messages" = "Novas mensagens"; +/* Chat call information */ +"chat_call_message" = "Chamada, "; +/* Chat call information */ +"chat_missed_call_message" = "Chamada perdida"; +/* Item present in the menu on long press on message */ +"chat_more_menu_item" = "More"; + +/* Status message */ +"status_offline" = "Indisponível"; +/* Status message */ +"status_online" = "Disponível"; +/* Status message */ +"status_away" = "Ausente"; +/* Status message */ +"status_busy" = "Ocupado"; + +/* Notification text */ +"notification_new_message" = "Mensagem nova"; +/* Notification text */ +"notification_incoming_contact_request" = "Pedido de contacto recebido"; +/* Notification text */ +"notification_is_calling" = "a ligar"; +/* Notification text */ +"notification_incoming_file" = "Receber ficheiro?"; + +/* Settings menu / screen name */ +"settings_about" = "Acerca"; +/* Settings menu / screen name */ +"settings_faq" = "FAQ"; +/* Settings menu / screen name */ +"settings_advanced_settings" = "Configurações avançadas"; +/* About screen menu */ +"settings_antidote_version" = "Versão Antidote"; +/* About screen menu */ +"settings_antidote_build" = "Antidote Build"; +/* About screen menu */ +"settings_toxcore_version" = "Versão Toxcore"; +/* About screen menu */ +"settings_acknowledgements" = "Acknowledgements"; +/* Settings screen menu */ +"settings_autodownload_images" = "Descarregar imagens automaticamente"; +/* Settings screen menu */ +"settings_autodownload_images_description" = "Descarregar automaticamente os ficheiros recebidos."; +/* Settings screen menu */ +"settings_notifications_message_preview" = "Pre-visualização de notificações"; +/* Settings screen menu */ +"settings_notifications_description" = "Quando a aplicação fica em segundo plano, as notificações ficarão activas durante 10 minutos"; +/* Settings screen menu */ +"settings_udp_enabled" = "Enable UDP"; +/* Settings screen menu */ +"settings_restore_default" = "Restaurar definições iniciais"; +/* Settings screen autodownload images option */ +"settings_never" = "Nunca"; +/* Settings screen autodownload images option */ +"settings_wifi" = "Wi-Fi"; +/* Settings screen autodownload images option */ +"settings_using_wifi" = "A usar Wi-Fi"; +/* Settings screen autodownload images option */ +"settings_always" = "Sempre"; + +/* Profile settings menu */ +"change_password" = "Alterar Palavra-Passe"; +/* Profile settings menu */ +"delete_password" = "Apagar Palavra-Passe"; +/* Profile settings menu */ +"old_password" = "Palavra-Passe Antiga"; +/* Change password text */ +"new_password" = "Nova Palavra-Passe"; +/* Change password text */ +"repeat_password" = "Repete Palavra-Passe"; +/* Change password button */ +"change_password_done" = "Terminado"; +/* Change password error */ +"password_is_empty_error" = "Palavra-Passe não pode estar vazia"; +/* Change password error */ +"wrong_old_password" = "Palavra-Passe errada"; +/* Change password error */ +"passwords_do_not_match" = "Palavras-Passe não coincidem"; + +/* Source of photo to take */ +"photo_from_camera" = "Câmara"; +/* Source of photo to take */ +"photo_from_photo_library" = "Fotografias"; +/* Error while converting avatar image */ +"change_avatar_error_convert_image" = "Não é possivel converter imagem"; + +/* Alert text when sending file to contacts */ +"file_send_to_contact" = "Envia a contacto"; + +/* Profile menu item */ +"export_profile" = "Exportar Perfil"; +/* Profile menu item */ +"delete_profile" = "Apagar Perfil"; +/* Delete profile confirmation */ +"delete_profile_confirmation_title_1" = "Apagar este Perfil?"; +/* Delete profile confirmation */ +"delete_profile_confirmation_title_2" = "Confirmar?"; +/* Delete profile confirmation */ +"delete_profile_confirmation_message" = "Não é possível refazer esta operação"; + +/* Call screen text */ +"call_incoming" = "A receber chamada"; +/* Call screen text */ +"call_ended" = "Chamada terminada"; +/* Call screen text */ +"call_reaching" = "A ligar/ A conectar"; + +/* File message text */ +"chat_file_cancelled" = "Cancelada"; +/* File message text */ +"chat_waiting" = "Em espera"; +/* File message text */ +"chat_paused" = "Em pausa"; + +/* Deleting chat confirmation */ +"delete_chat_title" = "Apagar esta conversa e o histórico de mensagens?"; +/* Deleting contat confirmation */ +"delete_contact_title" = "Apagar este contacto?\nO histórico de mensagens será apagado."; +/* Deleting contat request confirmation */ +"delete_contact_request_title" = "Rejeitar pedido?"; +/* Deleting single message in chat */ +"delete_single_message" = "Delete Message"; +/* Deleting multiple messages in chat. */ +"delete_multiple_messages" = "Delete Messages"; +/* Deleting all messages in chat. */ +"delete_all_messages" = "Delete All"; +/* Delete button */ +"alert_delete" = "Apagar"; +/* Delete button */ +"alert_cancel" = "Cancelar"; + +/* Error while creating new profile */ +"login_enter_username_and_profile" = "Insira o nome de utilizador e o nome do perfil"; +/* Error while creating new profile */ +"login_profile_already_exists" = "Nome escolhido já existe"; + +/* General error title */ +"error_title" = "Erro"; +/* General error button */ +"error_ok_button" = "OK"; +/* General error button */ +"error_retry_button" = "Tentar de novo"; +/* Error */ +"error_contact_not_connected" = "Contacto não está disponivel"; +/* Error */ +"error_too_many_files" = "Demasiadas transferências activas"; +/* Error */ +"error_internal_message" = "Erro interno"; +/* Error */ +"error_wrong_password_title" = "Palavra-Passe errada"; +/* Error */ +"error_wrong_password_message" = "Palavra-Passe contêm simbolos errados"; +/* Error */ +"error_import_not_exist_title" = "Não é possivel importar tox salvar/guardar ficheiro"; +/* Error */ +"error_import_not_exist_message" = "Ficheiro inexistente"; +/* Error */ +"error_decrypt_title" = "Não é possivel decriptar tox salvar/guardar ficheiro"; +/* Error */ +"error_decrypt_empty_data_message" = "Input data vazio"; +/* Error */ +"error_decrypt_bad_format_message" = "Ficheiro corrompido ou no formato errado"; +/* Error */ +"error_decrypt_wrong_password_message" = "Palavra-passe errada ou o ficheiro esta corrompido"; +/* Error */ +"error_general_unknown_message" = "Erro desconhecido"; +/* Error */ +"error_general_no_memory_message" = "Memória insuficiente"; +/* Error */ +"error_general_bind_port_message" = "Incapaz de ligar/conectar a uma porta"; +/* Error */ +"error_general_profile_encrypted_message" = "Perfil está encriptado"; +/* Error */ +"error_general_bad_format_message" = "Ficheiro têm um formato errado ou está corrompido"; +/* Error */ +"error_proxy_title" = "Erro de proxy"; +/* Error */ +"error_proxy_invalid_address_message" = "Proxy têm uma porta incorrecta"; +/* Error */ +"error_proxy_invalid_port_message" = "Porta proxy é inválida"; +/* Error */ +"error_proxy_host_not_resolved_message" = "Não é possivel ligar a proxy host"; + +/* Error */ +"error_name_too_long" = "Nome muito longo"; +/* Error */ +"error_status_message_too_long" = "Mensagem de status é demasiado longa"; + +/* Error */ +"error_contact_request_too_long" = "Mensagem demasiado extensa"; +/* Error */ +"error_contact_request_no_message" = "Nenhuma mensagem especificada"; +/* Error */ +"error_contact_request_own_key" = "Não pode adicionar-se a lista de contactos"; +/* Error */ +"error_contact_request_already_sent" = "Pedido de contacto já foi enviado"; +/* Error */ +"error_contact_request_bad_checksum" = "Má checksum, por favor confirme o Tox ID introduzido"; +/* Error */ +"error_contact_request_new_nospam" = "Má nospam value, por favor confirme o Tox ID introduzido"; + +/* Call error */ +"call_error_already_in_call" = "Numa chamada"; +/* Call error */ +"call_error_contact_is_offline" = "Contacto está indisponível"; +/* Call error */ +"call_error_no_active_call" = "Não existe nenhuma chamada activa"; + +/* Error while using color theme */ +"theme_error_cannot_open" = "Não é possivel abrir theme, formato incorrecto"; + +/* Tab chats badge ending */ +"accessibility_chats_ending" = "unread chats"; +/* Avatar button label in settings */ +"accessibility_avatar_button_label" = "Avatar"; +/* Avatar button hint in settings */ +"accessibility_avatar_button_hint" = "Sets or removes avatar."; +/* Chat button label in contact screen */ +"accessibility_chat_button_label" = "Chat"; +/* Chat button hint in contact screen */ +"accessibility_chat_button_hint" = "Opens chat dialog."; +/* Call button label in contact screen */ +"accessibility_call_button_label" = "Audio call"; +/* Call button hint in contact screen */ +"accessibility_call_button_hint" = "Makes audio call."; +/* Video button label in contact screen */ +"accessibility_video_button_label" = "Video call"; +/* Video button hint in contact screen */ +"accessibility_video_button_hint" = "Makes video call."; +/* Tap to copy hint */ +"accessibility_show_copy_hint" = "Shows copy menu."; +/* Tap to edit value hint */ +"accessibility_edit_value_hint" = "Edits value."; +/* Incoming message label */ +"accessibility_incoming_message_label" = "Message"; +/* Outgoing message label */ +"accessibility_outgoing_message_label" = "Your message"; +/* Message shown on chat list when contact is typing */ +"chat_is_typing_text" = "está a digitar..."; +/* Text shown in chat when there are undelivered faux offline messages */ +"chat_pending_faux_offline_messages" = "Mensagens não entregues serão enviadas quando você e o amigo estiverem online."; diff --git a/Antidote/pt.lproj/import-profile.html b/Antidote/pt.lproj/import-profile.html new file mode 100644 index 0000000..e203a8f --- /dev/null +++ b/Antidote/pt.lproj/import-profile.html @@ -0,0 +1,9 @@ + +

Para importar o seu perfil TOX:

+ +
    +
  1. Envie o ficheiro ".tox" para o seu aparelho usando (Mail, Dropbox, etc)
  2. +
  3. Utilize "Open In" menu para este ficheiro
  4. +
  5. Escolha Antidote na lista de opções
  6. +
  7. Confirme o nome do teu novo perfil e pressiona OK.
  8. +
diff --git a/Antidote/ru.lproj/AppStoreLocalizable.strings b/Antidote/ru.lproj/AppStoreLocalizable.strings new file mode 100644 index 0000000000000000000000000000000000000000..3f83883781ab40037320a8d4bc9e212b89188067 GIT binary patch literal 7612 zcmeI1%Wl&^6oyBLRTqdyFx?;(NNBkffugEv78Kfos07O@O`MC8I#Did!yEBN+0aJ; zzW+={nTUo(7s!z;%l3FYmow*|bMf!rzshdQC2oT=arjPl)91|(PBtl=310P-;COhYtUy*tBra6fsItNx(0KcyD8VIyWp--`aFHL`TD%; zP`ae1&)A83?%udE*B!3gZkL(;TnD@#&|fmNT$^zc_k(kXwrZCk#ifl|qP&mPJ?@Lv zBYR4bJ*D=NYs1FgVjjuub#lUrFL)63C~ zl-u+eGmqM+JV7e25zW!G=bmY2$jq9h&-_n$mr;`ZsbP_@_LQ1|p^@19dZ&>Otf#cB zF?)Q2*2~$Fe)W_xlJ;Io?`^lqm=(@VcTDZj^rU^zwH8zA-xbJ# zYu=FCiICI2?|_{!l^6JEJNvr84t>au^M>7v2)hr+m~nK>GKa`}ihX)tQrKQT@p~EJ z=e?$4b`9*RAa{-T%nIAfsqMXruv1i5rlc(96D7s+7IlT)<;Ct+Wh%<8+8~u0c8Y&O zQu$kfUH-6(bCrWRR?1cMy-+o8S)+DRpqHcXgoWkB*~$?ZX@4Dq*3iDB>d0K!T>fk> z&QZSM9jD|ZlJY%QeFN(obyQ?359@K#|*qml{XjE zC&m_J#=i(-aTMZz#QfZqUAYVIAkN}8DVAA>LyH3Yw2WD<1uNs38!;+J9L?7vK1yGGx+*Rzml5XAsOxhL&#|vvpB2Y3L|A*qEMO`|&SwJ)oW+ER zt=mHvpI7KY?<%wVH|wdB*h5dzz=YN43*_2%foDh?>;`d=b?RgZ+9iP*RmLli?pe&h zI(ok@ZdF`@+6F#3W+H>0*Hd$`cYMMsWjBw_Y82bVfljfPz|2-=4}Vr>57u;-yvD}` zhE}|+zE&Ttso&d;)^Z49{{KM>{PeFN_&@O|E!G)!df-xSi*vz)$XZ4mHDk~JcbxN5 zoDqFvDVF10Wp?i-oU5!Z->ZqEmi&@fOL-gNq(~qB8Lf`W`CeZfqYmf0Ppj-w)^nF~ zpWI9TdcsPA-wwWb%nt0)()-+mr*ryD(9n8f9>=KDC{ywAL%JFL!y5%HE!#z2tTT=x KQ+D!Tj?o{Mwm*gd literal 0 HcmV?d00001 diff --git a/Antidote/ru.lproj/InfoPlist.strings b/Antidote/ru.lproj/InfoPlist.strings new file mode 100644 index 0000000000000000000000000000000000000000..a601fc3322222812163bbc3be74a082d3b56a196 GIT binary patch literal 1028 zcmb`G%}&Bl5QWd;u3Y*A4NIa>2p|zb`B`X0MUC!@tzZI_Kqc{!d`b1Yw<2KJ7+lPB z=5*%FoS}Sv|1Jf7aMqI_yAL?JAe zGe_KH^AXQg_1t99<$fle_)n)3hv literal 0 HcmV?d00001 diff --git a/Antidote/ru.lproj/Localizable.strings b/Antidote/ru.lproj/Localizable.strings new file mode 100644 index 0000000..7318ce2 --- /dev/null +++ b/Antidote/ru.lproj/Localizable.strings @@ -0,0 +1,415 @@ +/* + Localizable.strings + Antidote + + Created by Dmytro Vorobiov on 08/10/15. + Copyright © 2015 dvor. All rights reserved. +*/ + +/* + Translation is done with Transifex service. + See https://www.transifex.com/antidote/antidote-ios/ +*/ + +/* Login screen text */ +"login_or_label" = "или"; +/* Login screen text */ +"create_account" = "Создать аккаунт"; +/* Login screen text */ +"import_profile" = "Импорт профиля"; +/* Password field */ +"password" = "Пароль"; +/* Login button */ +"log_in" = "Войти"; +/* Login screen text */ +"create_profile" = "Создать профиль"; +/* Login screen text */ +"import_to_antidote" = "Импорт профиля"; +/* Login screen text */ +"create_account_username_title" = "Как показывать контакты?"; +/* Login screen text */ +"create_account_username_placeholder" = "Имя"; +/* Login screen text */ +"create_account_profile_title" = "Название профиля?"; +/* Login screen text */ +"create_account_profile_placeholder" = "Профиль"; +/* Login screen text */ +"create_account_profile_hint" = "напр. Home, iPhone"; +/* Login screen text */ +"set_password_title" = "Пароль"; +/* Login screen text */ +"set_password_hint" = "Пароль необходим, чтобы защитить ваши данные. Храните его в безопастности, потому что пароль невозможно восстановить. "; +/* Login button */ +"create_account_next_button" = "Далее"; +/* Login button */ +"create_account_go_button" = "Создать"; +/* Default status message */ +"default_user_status_message" = "Toxing on Antidote"; + +/* PIN screen text */ +"pin_enter_to_unlock" = "Введите PIN-код для разблокировки"; +/* PIN screen text */ +"pin_set" = "Установите PIN-код"; +/* PIN screen text */ +"pin_confirm" = "Подтвердите PIN-код"; +/* PIN screen error */ +"pin_do_not_match" = "PIN-коды не совпадают. Попробуйте снова"; +/* PIN screen error */ +"pin_incorrect" = "Неправильный PIN"; +/* PIN screen error details */ +"pin_failed_attempts" = "Failed attempts: %@"; +/* PIN screen message shown on log out */ +"pin_logout_message" = "Too many failed attempts. You have been logged out."; +/* PIN screen screen */ +"pin_enabled" = "PIN-код включен"; +/* PIN screen screen */ +"pin_touch_id_enabled" = "Touch ID включен"; +/* PIN screen screen */ +"pin_description" = "Предотвратить неавторизованный доступ к Antidote с помощью PIN-кода."; +/* PIN screen screen */ +"pin_touch_id_description" = "Используйте ваш отпечаток пальца как альтернативу вводу PIN."; +/* PIN screen screen */ +"pin_lock_timeout" = " Тайм-аут блокировки"; +/* PIN screen screen */ +"pin_lock_immediately" = "Сразу"; +/* PIN screen screen */ +"pin_lock_30_seconds" = "30 секунд"; +/* PIN screen screen */ +"pin_lock_1_minute" = "1 минута"; +/* PIN screen screen */ +"pin_lock_2_minutes" = "2 минуты"; +/* PIN screen screen */ +"pin_lock_5_minutes" = "5 минут"; + +/* Label shown when connecting to Tox network */ +"connecting_label" = "Соединение..."; + +/* Tab name and screen name */ +"contacts_title" = "Контакты"; +/* Tab name and screen name */ +"chats_title" = "Чаты"; +/* Tab name and screen name */ +"settings_title" = "Настройки"; +/* Tab name and screen name */ +"profile_title" = "Профиль"; + +/* No contacts placeholder text */ +"contact_no_contacts" = "Нет контактов"; +/* No contacts placeholder text */ +"contact_no_contacts_add_contact" = "Добавьте друзей\nили\n"; +/* No contacts placeholder text */ +"contact_no_contacts_share_tox_id" = "дайте им свой Tox ID"; +/* Contact request section title */ +"contact_requests_section" = "Запросы"; +/* Contact last seen status */ +"contact_last_seen" = "Был в сети: %@"; +/* Screen name */ +"contact_request" = "Запрос на добавление"; +/* Contact request button */ +"contact_request_decline" = "Отклонить"; +/* Contact request button */ +"contact_request_accept" = "Принять"; +/* Contact request confirmation */ +"contact_request_delete_title" = "Удалить запрос?"; +/* Text shown when contact was deleted */ +"contact_deleted" = "Deleted contact"; + +/* Share Tox ID text */ +"show_qr_code" = "Показать QR-код"; +/* Share Tox ID text */ +"copy" = "Копировать"; + +/* Add contat screen name */ +"add_contact_title" = "Добавить контакт"; +/* Add contat button */ +"add_contact_send" = "Отправить"; +/* Add contat placeholder text */ +"add_contact_tox_id_placeholder" = "Введите Tox ID"; +/* Add contat placeholder text */ +"add_contact_or_label" = "или"; +/* Add contat button */ +"add_contact_use_qr" = "Сканировать QR-код"; +/* Add contat placeholder text */ +"add_contact_default_message_title" = "Сообщение"; +/* Add contat default text sended to contact */ +"add_contact_default_message_text" = "Привет! Пожалуйста, добавьте меня в список своих контактов?"; +/* Add contat error */ +"add_contact_wrong_qr" = "QR-код должен содержать Tox ID"; + +/* User name text */ +"name" = "Имя"; +/* User nickname text */ +"nickname" = "Псевдоним"; +/* User status message text */ +"status_message" = "Статус"; +/* User status text */ +"status_title" = "Статус подключения"; +/* User Tox ID text */ +"my_tox_id" = "Мой Tox ID"; +/* User public key text */ +"public_key" = "Публичный ключ"; +/* Share Tox ID text */ +"show_qr" = "QR-код"; +/* Profile menu item / screen name */ +"profile_details" = "Детали"; +/* Profile button */ +"logout_button" = "Выйти"; + +/* QR code screen button */ +"qr_close_button" = "Закрыть"; + +/* Chat screen placeholder */ +"chat_no_chats" = "Нет чатов"; +/* Chats screen message text */ +"chat_outgoing_file" = "Исходящий файл:"; +/* Chats screen message text */ +"chat_incoming_file" = "Входящий файл:"; +/* Chats screen message text */ +"chat_call_finished" = "Звонок завершен"; +/* Chats screen message text */ +"chat_unanwered_call" = "Нет ответа"; +/* Chat button */ +"chat_send_button" = "Отпр."; +/* Chat notification toast */ +"chat_new_messages" = "↓ Новые сообщения"; +/* Chat call information */ +"chat_call_message" = "Звонок,"; +/* Chat call information */ +"chat_missed_call_message" = "Пропущенный вызов"; +/* Item present in the menu on long press on message */ +"chat_more_menu_item" = "Ещё"; + +/* Status message */ +"status_offline" = "Не в сети"; +/* Status message */ +"status_online" = "В сети"; +/* Status message */ +"status_away" = "Отсутствую"; +/* Status message */ +"status_busy" = "Не беспокоить"; + +/* Notification text */ +"notification_new_message" = "Новое сообщение"; +/* Notification text */ +"notification_incoming_contact_request" = "Входящий запрос"; +/* Notification text */ +"notification_is_calling" = "звонит"; +/* Notification text */ +"notification_incoming_file" = "Входящий файл"; + +/* Settings menu / screen name */ +"settings_about" = "О приложении"; +/* Settings menu / screen name */ +"settings_faq" = "FAQ"; +/* Settings menu / screen name */ +"settings_advanced_settings" = "Расширенные настройки"; +/* About screen menu */ +"settings_antidote_version" = "Версия"; +/* About screen menu */ +"settings_antidote_build" = "Сборка"; +/* About screen menu */ +"settings_toxcore_version" = "Версия Toxcore"; +/* About screen menu */ +"settings_acknowledgements" = "Лицензии"; +/* Settings screen menu */ +"settings_autodownload_images" = "Загрузка вложений"; +/* Settings screen menu */ +"settings_autodownload_images_description" = "Автоматически загружать входящие вложения."; +/* Settings screen menu */ +"settings_notifications_message_preview" = "Превью уведомлений"; +/* Settings screen menu */ +"settings_notifications_description" = "Вы будете получать уведомления в течении 10 минут после сворачивания Antidote."; +/* Settings screen menu */ +"settings_udp_enabled" = "Использовать UDP"; +/* Settings screen menu */ +"settings_restore_default" = "Сбросить настройки"; +/* Settings screen autodownload images option */ +"settings_never" = "Никогда"; +/* Settings screen autodownload images option */ +"settings_wifi" = "Wi-Fi"; +/* Settings screen autodownload images option */ +"settings_using_wifi" = "При наличии Wi-Fi"; +/* Settings screen autodownload images option */ +"settings_always" = "Всегда"; + +/* Profile settings menu */ +"change_password" = "Изменить пароль"; +/* Profile settings menu */ +"delete_password" = "Удалить пароль"; +/* Profile settings menu */ +"old_password" = "Старый пароль"; +/* Change password text */ +"new_password" = "Новый пароль"; +/* Change password text */ +"repeat_password" = "Подтвердите пароль"; +/* Change password button */ +"change_password_done" = "Готово"; +/* Change password error */ +"password_is_empty_error" = "Пароль не может быть пустым"; +/* Change password error */ +"wrong_old_password" = "Неверный пароль"; +/* Change password error */ +"passwords_do_not_match" = "Пароли не совпадают"; + +/* Source of photo to take */ +"photo_from_camera" = "Камера"; +/* Source of photo to take */ +"photo_from_photo_library" = "Медиатека"; +/* Error while converting avatar image */ +"change_avatar_error_convert_image" = "Ошибка конвертации изображения"; + +/* Alert text when sending file to contacts */ +"file_send_to_contact" = "Отправить контакту"; + +/* Profile menu item */ +"export_profile" = "Экспорт профиля"; +/* Profile menu item */ +"delete_profile" = "Удалить профиль"; +/* Delete profile confirmation */ +"delete_profile_confirmation_title_1" = "Удалить этот профиль?"; +/* Delete profile confirmation */ +"delete_profile_confirmation_title_2" = "Вы уверены?"; +/* Delete profile confirmation */ +"delete_profile_confirmation_message" = "Это действие необратимо"; + +/* Call screen text */ +"call_incoming" = "Входящий вызов"; +/* Call screen text */ +"call_ended" = "Конец вызова"; +/* Call screen text */ +"call_reaching" = "Вызов..."; + +/* File message text */ +"chat_file_cancelled" = "Отменено"; +/* File message text */ +"chat_waiting" = "Ожидание..."; +/* File message text */ +"chat_paused" = "Пауза"; + +/* Deleting chat confirmation */ +"delete_chat_title" = "Удалить чат и историю сообщений?"; +/* Deleting contat confirmation */ +"delete_contact_title" = "Удалить контакт?\nИстория вашего чата будет потеряна."; +/* Deleting contat request confirmation */ +"delete_contact_request_title" = "Удалить запрос?"; +/* Deleting single message in chat */ +"delete_single_message" = "Удалить сообщение"; +/* Deleting multiple messages in chat. */ +"delete_multiple_messages" = "Удалить сообщения"; +/* Deleting all messages in chat. */ +"delete_all_messages" = "Удалить всё"; +/* Delete button */ +"alert_delete" = "Удалить"; +/* Delete button */ +"alert_cancel" = "Отмена"; + +/* Error while creating new profile */ +"login_enter_username_and_profile" = "Имя и профиль должны быть заданы."; +/* Error while creating new profile */ +"login_profile_already_exists" = "Такой профиль уже существует"; + +/* General error title */ +"error_title" = "Ошибка"; +/* General error button */ +"error_ok_button" = "ОК"; +/* General error button */ +"error_retry_button" = "Повторить"; +/* Error */ +"error_contact_not_connected" = "Контакт не в сети"; +/* Error */ +"error_too_many_files" = "Слишком много активных загрузок"; +/* Error */ +"error_internal_message" = "Внутренняя ошибка"; +/* Error */ +"error_wrong_password_title" = "Неверный пароль"; +/* Error */ +"error_wrong_password_message" = "Пароль содержит недопустимые символы."; +/* Error */ +"error_import_not_exist_title" = "Невозможно импортировать файл"; +/* Error */ +"error_import_not_exist_message" = "Файл не существует"; +/* Error */ +"error_decrypt_title" = "Невозможно расшифровать файл"; +/* Error */ +"error_decrypt_empty_data_message" = "Недостаточно данных."; +/* Error */ +"error_decrypt_bad_format_message" = "Файл поврежден или имеет неверный формат."; +/* Error */ +"error_decrypt_wrong_password_message" = "Неверный пароль"; +/* Error */ +"error_general_unknown_message" = "Неизвестная ошибка"; +/* Error */ +"error_general_no_memory_message" = "Недостаточно памяти."; +/* Error */ +"error_general_bind_port_message" = "Порт занят."; +/* Error */ +"error_general_profile_encrypted_message" = "Профиль зашифрован."; +/* Error */ +"error_general_bad_format_message" = "Файл поврежден или имеет неверный формат."; +/* Error */ +"error_proxy_title" = "Ошибка прокси"; +/* Error */ +"error_proxy_invalid_address_message" = "Адрес имеет неверный формат."; +/* Error */ +"error_proxy_invalid_port_message" = "Неверный порт."; +/* Error */ +"error_proxy_host_not_resolved_message" = "Невозможно разрешить адрес."; + +/* Error */ +"error_name_too_long" = "Имя слишком длинное."; +/* Error */ +"error_status_message_too_long" = "Статус слишком длинный"; + +/* Error */ +"error_contact_request_too_long" = "Сообщение слишком длинная"; +/* Error */ +"error_contact_request_no_message" = "Отсутствует сообщение"; +/* Error */ +"error_contact_request_own_key" = "Нельзя добавить себя в Контакты"; +/* Error */ +"error_contact_request_already_sent" = "Запрос уже отправлен"; +/* Error */ +"error_contact_request_bad_checksum" = "Неверная контрольная сумма, перепроверьте Tox ID"; +/* Error */ +"error_contact_request_new_nospam" = "Неверный nospam, перепроверьте Tox ID"; + +/* Call error */ +"call_error_already_in_call" = "Абонент занят"; +/* Call error */ +"call_error_contact_is_offline" = "Абонент не в сети"; +/* Call error */ +"call_error_no_active_call" = "Нет активных звонков"; + +/* Error while using color theme */ +"theme_error_cannot_open" = "Не удалось открыть, тема имеет неверный формат"; + +/* Tab chats badge ending */ +"accessibility_chats_ending" = "непрочитанные чаты"; +/* Avatar button label in settings */ +"accessibility_avatar_button_label" = "аватар"; +/* Avatar button hint in settings */ +"accessibility_avatar_button_hint" = "Установить или удалить аватар."; +/* Chat button label in contact screen */ +"accessibility_chat_button_label" = "Чат"; +/* Chat button hint in contact screen */ +"accessibility_chat_button_hint" = "Открывает чат."; +/* Call button label in contact screen */ +"accessibility_call_button_label" = "Аудио звонок"; +/* Call button hint in contact screen */ +"accessibility_call_button_hint" = "Совершает аудио звонок."; +/* Video button label in contact screen */ +"accessibility_video_button_label" = "Видео звонок"; +/* Video button hint in contact screen */ +"accessibility_video_button_hint" = "Совершает видео звонок."; +/* Tap to copy hint */ +"accessibility_show_copy_hint" = "Показать меню \"копировать\"."; +/* Tap to edit value hint */ +"accessibility_edit_value_hint" = "Редактирует значение."; +/* Incoming message label */ +"accessibility_incoming_message_label" = "Сообщение"; +/* Outgoing message label */ +"accessibility_outgoing_message_label" = "Ваше сообщение"; +/* Message shown on chat list when contact is typing */ +"chat_is_typing_text" = "пишет..."; +/* Text shown in chat when there are undelivered faux offline messages */ +"chat_pending_faux_offline_messages" = "Сообщения будут отправлены, когда вы и ваш друг оба будете онлайн."; diff --git a/Antidote/ru.lproj/import-profile.html b/Antidote/ru.lproj/import-profile.html new file mode 100644 index 0000000..906124e --- /dev/null +++ b/Antidote/ru.lproj/import-profile.html @@ -0,0 +1,9 @@ + +

Чтобы импортировать профиль:

+ +
    +
  1. Отправьте файл .tox на Ваше устройство (используя почту, Dropbox и др.).
  2. +
  3. Нажмите "Открыть в".
  4. +
  5. Выберите Antidote в списке доступных приложений.
  6. +
  7. Проверьте имя нового профиля и нажмите ОК.
  8. +
diff --git a/Antidote/sv.lproj/Localizable.strings b/Antidote/sv.lproj/Localizable.strings new file mode 100644 index 0000000..3fd89d1 --- /dev/null +++ b/Antidote/sv.lproj/Localizable.strings @@ -0,0 +1,34 @@ + + +/* Login screen text */ +"import_profile" = "Importera profil"; +/* Login screen text */ +"set_password_title" = "Välj lösenordet"; +/* Login screen text */ +"login_or_label" = "eller"; +/* Login button */ +"log_in" = "Logga in"; +/* Login screen text */ +"create_profile" = "Skapa konto"; +/* Login screen text */ +"import_to_antidote" = "Importera till Antidote"; +/* Login screen text */ +"create_account_profile_title" = "Hur kallar man denna profil?"; +/* Login screen text */ +"create_account_profile_placeholder" = "Profilnamn"; +/* Login screen text */ +"create_account_profile_hint" = "T.ex. Hem, Iphone"; +/* Login screen text */ +"create_account" = "Skapa konto"; +/* Password field */ +"password" = "Lösenordet"; +/* Login screen text */ +"create_account_username_placeholder" = "Användarnamn"; +/* Login screen text */ +"create_account_username_title" = "Hur vill du se dina kontakter?"; +/* Login screen text */ +"set_password_hint" = "Lösenordet behövs för att skydda din data. Förvara det säkert - om du har förlorat det går det inte att återskapa det."; +/* Login button */ +"create_account_next_button" = "Nästa"; +/* Login button */ +"create_account_go_button" = "Gå"; diff --git a/Antidote/tr.lproj/Localizable.strings b/Antidote/tr.lproj/Localizable.strings new file mode 100644 index 0000000..c188b9c --- /dev/null +++ b/Antidote/tr.lproj/Localizable.strings @@ -0,0 +1,14 @@ + + +/* Login button */ +"log_in" = "giriş yap"; +/* Password field */ +"password" = "Şifre"; +/* Login screen text */ +"create_profile" = "Hesap oluştur"; +/* Login screen text */ +"create_account" = "Hesap oluştur"; +/* Login screen text */ +"import_profile" = "Dosyayı dışarı çıkar"; +/* Login screen text */ +"login_or_label" = "ya da"; diff --git a/Antidote/zgh.lproj/Localizable.strings b/Antidote/zgh.lproj/Localizable.strings new file mode 100644 index 0000000..5a84c69 --- /dev/null +++ b/Antidote/zgh.lproj/Localizable.strings @@ -0,0 +1,404 @@ + + +/* Call screen text */ +"call_reaching" = "ⵉⵇⵇⴰⵔ..."; +/* Login screen text */ +"login_or_label" = "ⵏⵉⵖ"; +/* Login screen text */ +"create_account" = "ⵙⴽⵔ ⴽⵔⴰ ⵏ ⵓⵎⵉⴹⴰⵏ"; +/* Login screen text */ +"import_profile" = "ⵙⵙⴽⵛⵎ ⴽⵔⴰ ⵏ ⵓⵎⵉⴹⴰⵏ"; +/* Password field */ +"password" = "ⵉⵏⵉⴳⵍ ⵏ ⵡⴰⴷⴰⴼ"; +/* Login button */ +"log_in" = "ⴽⵛⵎ"; +/* Login screen text */ +"create_profile" = "ⵙⴽⵔ ⴽⵔⴰ ⵏ ⵓⵎⵉⴹⴰⵏ"; +/* Login screen text */ +"import_to_antidote" = "ⴷⴷⵓ ⵖⵔ antidote"; +/* Login screen text */ +"create_account_username_title" = "ⵎⴰⵎⴽ ⴰ ⵔⴰⴷ ⴽ ⵥⵕⵏ ⵉⵎⴰⵡⴰⴹⵏ ⵏⵏⴽ?"; +/* Login screen text */ +"create_account_username_placeholder" = "ⵉⵙⵎ ⵏ ⵓⵏⵙⵙⵎⵔⵙ"; +/* Login screen text */ +"create_account_profile_title" = "ⵎⴰⵎⴽ ⴰ ⵔⴰⴷ ⵜⵖⵔⴷ ⵉ ⵓⵎⵉⴹⴰⵏ ⴰⴷ?"; +/* Login screen text */ +"create_account_profile_placeholder" = "ⵉⵙⵎ ⵏ ⵓⵎⵉⴹⴰⵏ"; +/* Login screen text */ +"create_account_profile_hint" = "ⵙ ⵓⵎⴷⵢⴰ ⵜⴰⴷⴷⴰⵔⵜ, ⴰⵢⴼⵓⵏ"; +/* Login screen text */ +"set_password_title" = "ⵙⵔⵙ ⵉⵏⵉⴳⵍ ⵏ ⵡⴰⴷⴰⴼ"; +/* Login screen text */ +"set_password_hint" = "ⵉⵡⴰⵜⵜⵙ ⵉⵏⵉⴳⵍ ⵏ ⵡⴰⴷⴰⴼ ⴰⴼⵔⴰⴳ ⵏ ⵜⵎⵓⵛⴰ ⵏⵏⴽ ⵜⵉⵏⵉⵎⴰⵏⵉⵏ. ⵃⴹⵓ ⵜⵏⵜ - ⵎⵛ ⴰⴽ ⴷⴷⴰⵏⵜ ⵓⵔ ⵜⵣⵎⵎⴰⵔⴷ ⴰⴷ ⵜⵔⴰⵔⴷ ⴰⵎⵉⴹⴰⵏ."; +/* Login button */ +"create_account_next_button" = "ⵢⴰⴹⵏ"; +/* Login button */ +"create_account_go_button" = "ⵙⵙⵏⵜ"; +/* Default status message */ +"default_user_status_message" = "ⵜⵜⵎⵢⴰⵡⴰⴹⵖ ⵙ Antidote"; + +/* PIN screen text */ +"pin_enter_to_unlock" = "ⵙⵙⵉⴷⴼ PIN ⵏⵏⴽ ⵉ ⵓⵕⵥⴰⵎ"; +/* PIN screen text */ +"pin_set" = "ⵙⵔⵙ PIN"; +/* PIN screen text */ +"pin_confirm" = "ⵙⴷⴷⵉⴷ PIN"; +/* PIN screen error */ +"pin_do_not_match" = "ⵓⵔ ⵎⵙⴰⵙⴰⵏ ⵡⵓⵟⵟⵓⵏⵏ, ⴰⵍⵙ ⴷⴰⵖ"; +/* PIN screen error */ +"pin_incorrect" = "PIN ⴷ ⴰⵔⵎⵉⴷⵉ"; +/* PIN screen error details */ +"pin_failed_attempts" = "ⵉⵔⵉⵎⵏ ⵉⵏⴳⵓⴼⵏ: %@"; +/* PIN screen message shown on log out */ +"pin_logout_message" = "ⴽⵉⴳⴰⵏ ⵏ ⵉⵔⵉⵎⵏ ⵉⵏⴳⵓⴼⵏ. ⵉⵜⵜⵡⴰⵣⵎⵎⴻⵎ ⵡⵓⴼⵓⵖ ⵏⵏⴽ."; +/* PIN screen screen */ +"pin_enabled" = "ⴰⵙⵎⵀⵍ ⵏ PIN"; +/* PIN screen screen */ +"pin_touch_id_enabled" = "ⴰⵙⵎⵀⵍ ⵏ ⵜⵎⴰⴳⵉⵜ ⵙ ⵓⵙⵍⴰⵢ"; +/* PIN screen screen */ +"pin_description" = "ⵏⵀⵕ ⴰⵡⴰⴹ ⵏⵏⴰ ⵓⵔ ⵉⵜⵜⵓⵙⵙⵓⴳⵔⵏ ⵖⵔ Antidote ⵙ ⵓⵙⵎⵔⵙ ⵏ PIN."; +/* PIN screen screen */ +"pin_touch_id_description" = "ⵙⵎⵔⵙ ⵜⵉⵡⴳⴳⴹⵜ ⴰⵎ ⵜⵉⵎⴽⴽⵉⵙⵉⵜ ⵏ ⵓⵙⵉⴷⴼ ⵏ PIN."; +/* PIN screen screen */ +"pin_lock_timeout" = "ⴰⵣⵎⵣ ⵏ ⵓⵔⴳⴰⵍ"; +/* PIN screen screen */ +"pin_lock_immediately" = "ⴷⵖⵉ"; +/* PIN screen screen */ +"pin_lock_30_seconds" = "30 ⵏ ⵜⵙⵉⵏⵜ"; +/* PIN screen screen */ +"pin_lock_1_minute" = "1 ⵏ ⵜⵓⵙⴷⵉⴷⵜ"; +/* PIN screen screen */ +"pin_lock_2_minutes" = "2 ⵏ ⵜⵓⵙⴷⵉⴷⵉⵏ"; +/* PIN screen screen */ +"pin_lock_5_minutes" = "5 ⵏ ⵜⵓⵙⴷⵉⴷⵉⵏ"; + +/* Label shown when connecting to Tox network */ +"connecting_label" = "ⴳ ⵉⴼⵉⵍⵉ..."; + +/* Tab name and screen name */ +"contacts_title" = "ⵉⵎⴰⵡⴰⴹⵏ"; +/* Tab name and screen name */ +"chats_title" = "ⵉⵎⵙⴰⵡⴰⵍⵏ"; +/* Tab name and screen name */ +"settings_title" = "ⵜⵉⵙⵖⴰⵍ"; +/* Tab name and screen name */ +"profile_title" = "ⴰⵎⵉⴹⴰⵏ"; + +/* No contacts placeholder text */ +"contact_no_contacts" = "ⵓⵔ ⵍⵍⵉⵏ ⵉⵎⴰⵡⴰⴹⵏ"; +/* No contacts placeholder text */ +"contact_no_contacts_add_contact" = "ⵔⵏⵓ ⴽⵔⴰ ⵏ ⵓⵎⴰⵡⴰⴹ\nⵏⵉⵖ\n"; +/* No contacts placeholder text */ +"contact_no_contacts_share_tox_id" = "ⴷⵔⵓ ⴰⵎⵉⴹⴰⵏ ⵏⵏⴽ ⵏ ⵜⵓⴽⵙ"; +/* Contact request section title */ +"contact_requests_section" = "ⵜⴰⵍⴳⴰⵎⵜ ⵏ ⵜⵎⵔⵏⵉⵡⵜ"; +/* Contact last seen status */ +"contact_last_seen" = "ⵜⵉⴳⵉⵔⴰ ⵏⵏⵙ: %@"; +/* Screen name */ +"contact_request" = "ⴰⵙⵉⴳⵔ"; +/* Contact request button */ +"contact_request_decline" = "ⵜⴰⴳⵯⵉⵜ"; +/* Contact request button */ +"contact_request_accept" = "ⵜⴰⵢⵢⵉⵀⵜ"; +/* Contact request confirmation */ +"contact_request_delete_title" = "ⴽⴽⵙ ⴰⵙⵉⴳⵔ?"; +/* Text shown when contact was deleted */ +"contact_deleted" = "ⵉⵜⵜⵡⴰⴽⴽⵙ ⵓⵎⴰⵡⴰⴹ ⴰⴷ"; + +/* Share Tox ID text */ +"show_qr_code" = "ⴼⵙⵔ ⵉⵏⵉⴳⵍ ⵏ QR"; +/* Share Tox ID text */ +"copy" = "ⵙⵙⵏⵖⵍ"; + +/* Add contat screen name */ +"add_contact_title" = "ⵔⵏⵓ ⴽⵔⴰ ⵏ ⵓⵎⴰⵡⴰⴹ"; +/* Add contat button */ +"add_contact_send" = "ⴰⵣⵏ"; +/* Add contat placeholder text */ +"add_contact_tox_id_placeholder" = "ⵙⵙⵉⴷⴼ Tox ID"; +/* Add contat placeholder text */ +"add_contact_or_label" = "ⵏⵉⵖ"; +/* Add contat button */ +"add_contact_use_qr" = "ⵙⵎⵔⵙ ⵉⵏⵉⴳⵍ ⵏ QR"; +/* Add contat placeholder text */ +"add_contact_default_message_title" = "ⵜⴰⴱⵔⴰⵜ"; +/* Add contat default text sended to contact */ +"add_contact_default_message_text" = "ⴰⵣⵓⵍ! ⵉⵙ ⵜⵣⵎⵔⴷ ⴰⴷ ⵢⵉ ⵜⵔⵏⵓⴷ ⴳ ⵜⵍⴳⴰⵎⵜ ⵏ ⵡⴰⵡⴰⴹ ⵏⵏⴽ?"; +/* Add contat error */ +"add_contact_wrong_qr" = "ⵉⵏⵉⴳ ⵏ QR ⴷ ⴰⵔⵎⵉⴷⵉ. ⵉⵅⵚⵚⴰ ⴰⴷ ⴷⵉⴳⵙ ⵢⵉⵍⵉ Tox ID"; + +/* User name text */ +"name" = "ⵉⵙⵎ"; +/* User nickname text */ +"nickname" = "ⵉⵙⵎ ⵏ ⵜⵡⴰⵛⵓⵏⵜ"; +/* User status message text */ +"status_message" = "ⵜⴰⴱⵔⴰⵜ ⵏ ⵡⴰⴷⴷⴰⴷ"; +/* User status text */ +"status_title" = "ⴰⴷⴷⴰⴷ"; +/* User Tox ID text */ +"my_tox_id" = "Tox ID ⵉⵏⵓ"; +/* User public key text */ +"public_key" = "ⵜⴰⵙⴰⵔⵓⵜ ⵜⴰⴳⴷⵓⴷⴰⵏⵜ"; +/* Share Tox ID text */ +"show_qr" = "ⵎⵍ ⵉⵏⵉⴳⵍ ⵏ QR"; +/* Profile menu item / screen name */ +"profile_details" = "ⵉⴼⵔⵓⵔⵉⵜⵏ ⵏ ⵓⵎⵉⴹⴰⵏ"; +/* Profile button */ +"logout_button" = "ⴼⴼⵖ"; + +/* QR code screen button */ +"qr_close_button" = "ⵇⵇⵏ"; + +/* Chat screen placeholder */ +"chat_no_chats" = "ⵓⵔ ⵉⵍⵍⵉ ⴽⵔⴰ ⵏ ⵓⵎⵙⴰⵡⴰⵍ"; +/* Chats screen message text */ +"chat_outgoing_file" = "ⴰⴼⴰⵢⵍⵓ ⵉⴼⴼⵖⵏ:"; +/* Chats screen message text */ +"chat_incoming_file" = "ⴰⴼⴰⵢⵍⵓ ⵓⴽⵛⵉⵎ:"; +/* Chats screen message text */ +"chat_call_finished" = "ⵜⵙⵎⴷ ⵜⵖⵓⵔⵉ"; +/* Chats screen message text */ +"chat_unanwered_call" = "ⵓⵔ ⵉⵍⵍⵉ ⵓⵙⴰⴷⵎⵔ ⵅⴼ ⵜⵖⵓⵔⵉ ⴰⴷ"; +/* Chat button */ +"chat_send_button" = "ⴰⵣⵏ"; +/* Chat notification toast */ +"chat_new_messages" = "ⵜⵉⴱⵔⴰⵜⵉⵏ ⵜⵉⵎⴰⵢⵏⵓⵜⵉⵏ"; +/* Chat call information */ +"chat_call_message" = "ⵖⵔ، "; +/* Chat call information */ +"chat_missed_call_message" = "ⵓⵔ ⵉⵍⵍⵉ ⵓⵙⴰⴷⵎⵔ ⵅⴼ ⵜⵖⵓⵔⵉ ⴰⴷ"; +/* Item present in the menu on long press on message */ +"chat_more_menu_item" = "ⵓⴳⴰⵔ"; +/* Message shown on chat list when contact is typing */ +"chat_is_typing_text" = "ⵉⵜⵜⴰⵔⵉ..."; +/* Text shown in chat when there are undelivered faux offline messages */ +"chat_pending_faux_offline_messages" = "ⵔⴰⴷ ⵜⵜⵡⴰⵣⵏⵏⵜ ⵜⴱⵔⴰⵜⵉⵏ ⵏⵏⴰ ⵓⵔ ⵉⵜⵜⵡⴰⵎⵥⵏ ⴰⴷⴷⴰⵢ ⵜⵉⵍⵉⴷ ⴰⴽⴷ ⵓⵎⴷⴷⴰⴽⴽⵯⵍ ⵏⵏⴽ ⴳ ⵉⴼⵉⵍⵉ."; + +/* Status message */ +"status_offline" = "ⵓⵔ ⵉⵍⵍⵉ ⴳ ⵉⴼⵉⵍⵉ"; +/* Status message */ +"status_online" = "ⴳ ⵉⴼⵉⵍⵉ"; +/* Status message */ +"status_away" = "ⴳ ⴱⵕⵕⴰ"; +/* Status message */ +"status_busy" = "ⴳ ⵜⵡⵓⵔⵉ"; + +/* Notification text */ +"notification_new_message" = "ⵜⴰⴱⵔⴰⵜ ⵜⴰⵎⴰⵢⵏⵓⵜ"; +/* Notification text */ +"notification_incoming_contact_request" = "ⴰⵙⵓⵜⵔ ⵏ ⵜⵖⵓⵔⵉ"; +/* Notification text */ +"notification_is_calling" = "ⵉⵇⵇⴰⵔ"; +/* Notification text */ +"notification_incoming_file" = "ⵢⵓⴷⴼ ⴷ ⵓⴼⴰⵢⵍⵓ"; + +/* Settings menu / screen name */ +"settings_about" = "ⵅⴼ"; +/* Settings menu / screen name */ +"settings_faq" = "ⵜⵉⵖⵍⴰⴼ"; +/* Settings menu / screen name */ +"settings_advanced_settings" = "ⵜⵉⵙⵖⴰⵍ ⵉⵣⵡⴰⵔⵏ"; +/* About screen menu */ +"settings_antidote_version" = "ⵜⵓⵏⵖⵉⵍⵜ ⵏ Antidote"; +/* About screen menu */ +"settings_antidote_build" = "ⵜⵓⵚⴰ ⵏ Antidote"; +/* About screen menu */ +"settings_toxcore_version" = "ⵜⵓⵏⵖⵉⵍⵜ ⵏ Toxcore"; +/* About screen menu */ +"settings_acknowledgements" = "ⴰⵙⵏⵉⵎⵎⵔ"; +/* Settings screen menu */ +"settings_autodownload_images" = "ⵉⴼⴰⵢⵍⵓⵜⵏ ⵏ ⵡⴰⴳⴰⵎ ⴰⵡⵓⵔⵎⴰⵏ"; +/* Settings screen menu */ +"settings_autodownload_images_description" = "ⴰⴳⴰⵎ ⴰⵡⵓⵔⵎⴰⵏ ⵏ ⵉⴼⴰⵢⵍⵓⵜⵏ ⵓⴽⵛⵉⵎⵏ."; +/* Settings screen menu */ +"settings_notifications_message_preview" = "ⴰⴼⵙⴰⵔ ⵏ ⵉⵏⵖⵎⵉⵙⵏ"; +/* Settings screen menu */ +"settings_notifications_description" = "ⴰⴷⴷⴰⵢ ⵜⴽⵛⵎ ⵜⵙⵏⵙⵉ ⴳ ⵓⵡⵔⵏ, ⵔⴰⴷ ⵢⵉⵍⵉ ⵓⴼⵙⴰⵔ ⵏ ⵉⵏⵖⵎⵉⵙⵏ ⴰⵔ 10 ⵏ ⵜⵓⵙⴷⵉⴷⵉⵏ."; +/* Settings screen menu */ +"settings_udp_enabled" = "ⴰⵙⵎⵀⵍ ⵏ UDP"; +/* Settings screen menu */ +"settings_restore_default" = "ⵉⵔⵉⵔ ⵏ ⵜⵙⵖⴰⵍ ⵜⵉⵎⵔⴷⴰ"; +/* Settings screen autodownload images option */ +"settings_never" = "ⵓⵀⵓ"; +/* Settings screen autodownload images option */ +"settings_wifi" = "ⴰⵙⵎⵔⵙ ⵏ ⵡⵉⴼⵉ"; +/* Settings screen autodownload images option */ +"settings_using_wifi" = "ⵡⵉⴼⵉ"; +/* Settings screen autodownload images option */ +"settings_always" = "ⴰⴱⴷⴰ"; + +/* Profile settings menu */ +"change_password" = "ⵙⵏⴼⵍ ⵉⵏⵉⴳⵍ ⵏ ⵡⴰⴷⴰⴼ"; +/* Profile settings menu */ +"delete_password" = "ⴽⴽⵙ ⵉⵏⵉⴳⵍ ⵏ ⵡⴰⴷⴰⴼ"; +/* Profile settings menu */ +"old_password" = "ⵉⵏⵉⴳⵍ ⴰⵇⴱⵓⵔ ⵏ ⵡⴰⴷⴰⴼ"; +/* Change password text */ +"new_password" = "ⵉⵏⵉⴳⵍ ⴰⵎⴰⵢⵏⵓ ⵏ ⵡⴰⴷⴰⴼ"; +/* Change password text */ +"repeat_password" = "ⴰⵍⵙ ⵉⵏⵉⴳⵍ ⵏ ⵡⴰⴷⴰⴼ"; +/* Change password button */ +"change_password_done" = "ⵙⵎⴷ"; +/* Change password error */ +"password_is_empty_error" = "ⵉⵅⵚⵚⴰ ⵓⵔ ⵉⵜⵜⵉⵍⵉ ⵉⵏⵉⴳⵍ ⵏ ⵡⴰⴷⴰⴼ ⵉⵅⵡⴰ"; +/* Change password error */ +"wrong_old_password" = "ⴰⵔⵎⵉⴷⵉ ⴳ ⵉⵏⵉⴳⵍ ⵏ ⵡⴰⴷⴰⴼ"; +/* Change password error */ +"passwords_do_not_match" = "ⵓⵔ ⵉⵎⵙⴰⵙⴰ ⵉⵏⵉⴳⵍ ⵏ ⵡⴰⴷⴰⴼ"; + +/* Source of photo to take */ +"photo_from_camera" = "ⴰⵙⵓⵍⴼ"; +/* Source of photo to take */ +"photo_from_photo_library" = "ⵜⴰⵙⵓⵍⴰⴼⵜ"; +/* Error while converting avatar image */ +"change_avatar_error_convert_image" = "ⵓⵔ ⵜⵣⵎⵉⵔ ⵜⵡⵍⴰⴼⵜ ⴰⴷ ⵜⴻⵜⵜⵓⵙⵏⴼⵍ"; + +/* Alert text when sending file to contacts */ +"file_send_to_contact" = "ⴰⵣⵏ ⵉ ⴽⵔⴰ ⵏ ⵓⵎⴰⵡⴰⴹ"; + +/* Profile menu item */ +"export_profile" = "ⵃⴹⵓ ⴰⵎⵉⴹⴰⵏ ⴰⵏⵉⵎⴰⵏ"; +/* Profile menu item */ +"delete_profile" = "ⴽⴽⵙ ⴰⵎⵉⴹⴰⵏ ⴰⵏⵉⵎⴰⵏ"; +/* Delete profile confirmation */ +"delete_profile_confirmation_title_1" = "ⵉⵙ ⵜⵔⵉⴷ ⴰⴷ ⵜⴽⴽⵙⴷ ⴰⵎⵉⴹⴰⵏ ⴰⵏⵉⵎⴰⵏ?"; +/* Delete profile confirmation */ +"delete_profile_confirmation_title_2" = "ⵉⵙ ⵜⵃⵇⵇⵉⴷ?"; +/* Delete profile confirmation */ +"delete_profile_confirmation_message" = "ⵜⴰⵎⵀⵍⵜ ⴰⴷ ⵓⵔ ⴷⵉⴳⵙ ⴰⴱⵕⵕⴰⵎ"; + +/* Call screen text */ +"call_incoming" = "ⵜⴰⵖⵓⵔⵉ ⵜⵓⴽⵛⵉⵎⵜ"; +/* Call screen text */ +"call_ended" = "ⵜⵙⵎⴷ ⵜⵖⵓⵔⵉ"; + +/* File message text */ +"chat_file_cancelled" = "ⵉⵜⵜⵓⵙⵙⵔ"; +/* File message text */ +"chat_waiting" = "ⴰⴳⴰⵏⵉ..."; +/* File message text */ +"chat_paused" = "ⴱⴷⴷ ⵉⵎⵉⴽ"; + +/* Deleting chat confirmation */ +"delete_chat_title" = "ⴽⴽⵙ ⴰⵎⵙⴰⵡⴰⵍ ⴰⴷ ⴷ ⵜⴱⵔⴰⵜⵉⵏ ⵏⵏⴰ ⴷⵉⴳⵙ ⵉⵜⵜⵓⵃⴹⵓⵏ?"; +/* Deleting contat confirmation */ +"delete_contact_title" = "ⴽⴽⵙ ⴰⵎⴰⵡⴰⴹ ⴰⴷ?\nⵔⴰⴷ ⵉⵜⵜⵓⴽⴽⵙ ⵡⴰⵔⵔⴰ ⵏ ⵜⵊⵎⵎⴰⵄⵜ."; +/* Deleting contat request confirmation */ +"delete_contact_request_title" = "ⵉⵙ ⵜⵔⵉⴷ ⴰⴷ ⵜⴽⴽⵙⴷ ⴰⵙⵉⴳⵔ ⵏ ⵓⵎⵉⴹⴰⵏ ⴰⴷ?"; +/* Deleting single message in chat */ +"delete_single_message" = "ⴽⴽⵙ ⵜⴰⴱⵔⴰⵜ"; +/* Deleting multiple messages in chat. */ +"delete_multiple_messages" = "ⴽⴽⵙ ⵜⵉⴱⵔⴰⵜⵉⵏ"; +/* Deleting all messages in chat. */ +"delete_all_messages" = "ⴽⴽⵙ ⴰⴽⴽⵯ"; +/* Delete button */ +"alert_delete" = "ⴽⴽⵙ"; +/* Delete button */ +"alert_cancel" = "ⵙⵙⵔ"; + +/* Error while creating new profile */ +"login_enter_username_and_profile" = "ⵙⵙⵉⴷⴼ ⵉⵙⵎ ⵏ ⵓⵏⵙⵙⵎⵔⵙ ⴷ ⵢⵉⵙⵎ ⵏ ⵓⵎⵉⴹⴰⵏ ⴰⵏⵉⵎⴰⵏ."; +/* Error while creating new profile */ +"login_profile_already_exists" = "ⵉⵍⵍⴰ ⵢⵉⵙⵎ ⴰⴷ ⵏ ⵓⵎⵉⴹⴰⵏ ⴰⵏⵉⵎⴰⵏ"; + +/* General error title */ +"error_title" = "ⵜⴰⵣⴳⵍⵜ"; +/* General error button */ +"error_ok_button" = "ⵡⴰⵅⵅⴰ"; +/* General error button */ +"error_retry_button" = "ⴰⵍⵙ ⴷⴰⵖ"; +/* Error */ +"error_contact_not_connected" = "ⵓⵔ ⵉⵍⵍⵉ ⵓⵎⴰⵡⴰⴹ ⴳ ⵉⴼⵉⵍⵉ"; +/* Error */ +"error_too_many_files" = "ⴽⵉⴳⴰⵏ ⵏ ⵜⵎⵀⴰⵍ ⵏ ⵓⵙⵎⵓⵜⵜⵉ ⵏ ⵉⴼⴰⵢⵍⵓⵜⵏ ⵉⵜⵜⵓⵙⵎⵀⵍⵏ"; +/* Error */ +"error_internal_message" = "ⵜⴰⵣⴳⵍⵜ ⵜⴰⴳⵯⵏⵙⴰⵏⵜ"; +/* Error */ +"error_wrong_password_title" = "ⵉⵏⵉⴳⵍ ⵏ ⵡⴰⴷⴰⴼ ⴷ ⴰⵔⵎⵉⴷⵉ"; +/* Error */ +"error_wrong_password_message" = "ⵉⵏⵉⴳⵍ ⵏ ⵡⴰⴷⴰⴼ ⴷⵉⴳⵙ ⵜⵉⵎⵉⵜⴰⵔ ⵜⵉⵔⵎⵉⴷⵉⵜⵉⵏ."; +/* Error */ +"error_import_not_exist_title" = "ⵓⵔ ⵉⵣⵔⵉ ⴰⴷ ⵉⵜⵜⵓⵙⵏⴼⵍ ⵓⴼⴰⵢⵍⵓ ⵏ tox"; +/* Error */ +"error_import_not_exist_message" = "ⵓⵔ ⵉⵍⵍⵉ ⵓⴼⴰⵢⵍⵓ."; +/* Error */ +"error_decrypt_title" = "ⵓⵔ ⵉⵣⵔⵉ ⵓⵔⴰⵏⵜⴰⵍ ⵏ ⵓⴼⴰⵢⵍⵓ ⵏ tox ⵉⵜⵜⵓⵃⴹⵓⵏ"; +/* Error */ +"error_decrypt_empty_data_message" = "ⴽⵔⴰ ⵏ ⵜⵎⵓⵛⴰ ⵏ ⵓⴽⵊⵊⵓⵎ ⵅⵡⴰⵏⵜ."; +/* Error */ +"error_decrypt_bad_format_message" = "ⴰⴼⴰⵢⵍⵓ ⴷⵉⴳⵙ ⴰⵣⴷⴷⵓⵢ ⴷ ⴰⵎⵛⵓⵎ ⵏⵉⵖ ⴰⵎⴰⴽⵓⵍ."; +/* Error */ +"error_decrypt_wrong_password_message" = "ⵉⵏⵉⴳⵍ ⵏ ⵡⴰⴷⴰⴼ ⴷ ⴰⵔⵎⵉⴷⵉ ⵏⵉⵖ ⴰⴼⴰⵢⵍⵓ ⴷ ⴰⵎⴰⴽⵓⵍ."; +/* Error */ +"error_general_unknown_message" = "ⵜⴰⵣⴳⵍⵜ ⵜⴰⵔ ⵉⵙⵎ."; +/* Error */ +"error_general_no_memory_message" = "ⵜⵉⵎⴽⵜⵉⵜ ⴷ ⵜⴰⵎⴽⵜⵓⵔⵜ."; +/* Error */ +"error_general_bind_port_message" = "ⵓⵔ ⵉⵣⵎⵉⵔ ⴰⴷ ⵉⵣⴷⵉ ⴷ ⵓⴼⵜⴰⵙ."; +/* Error */ +"error_general_profile_encrypted_message" = "ⵉⵜⵜⵡⴰⴳⴳ ⵓⵙⵏⵜⵍ ⵉ ⵓⵎⵉⴹⴰⵏ ⴰⵏⵉⵎⴰⵏ."; +/* Error */ +"error_general_bad_format_message" = "ⴰⴼⴰⵢⵍⵓ ⴷⵉⴳⵙ ⴰⵣⴷⴷⵓⵢ ⴷ ⴰⵎⵛⵓⵎ ⵏⵉⵖ ⴰⵎⴰⴽⵓⵍ."; +/* Error */ +"error_proxy_title" = "ⵜⴰⵣⴳⵍⵜ ⴳ Proxy"; +/* Error */ +"error_proxy_invalid_address_message" = "ⴰⵏⵙⴰ ⵏ Proxy ⵖⵔⵙ ⵜⴰⵍⵖⴰ ⵜⴰⵔⵎⵉⴷⵉⵜ."; +/* Error */ +"error_proxy_invalid_port_message" = "ⴰⴼⵜⴰⵙ ⵏ Proxy ⴷ ⴰⵔⵎⵉⴷⵉ."; +/* Error */ +"error_proxy_host_not_resolved_message" = "ⵓⵔ ⵉⵣⵔⵉ ⵓⵕⵥⵥⵓⵎ ⵏ Proxy."; + +/* Error */ +"error_name_too_long" = "ⵉⵖⵣⵣⵉⴼ ⵢⵉⵙⵎ ⴽⵉⴳⴰⵏ."; +/* Error */ +"error_status_message_too_long" = "ⵜⵖⵣⵣⵉⴼ ⴽⵉⴳⴰⵏ ⵜⴱⵔⴰⵜ ⵏ ⵡⴰⴷⴷⴰⴷ"; + +/* Error */ +"error_contact_request_too_long" = "ⵜⵖⵣⵣⵉⴼ ⵜⴱⵔⴰⵜ ⴽⵉⴳⴰⵏ"; +/* Error */ +"error_contact_request_no_message" = "ⵓⵔ ⵍⵍⵉⵏⵜ ⴽⵔⴰ ⵏ ⵜⴱⵔⴰⵜⵉⵏ"; +/* Error */ +"error_contact_request_own_key" = "ⵓⵔ ⵜⵣⵔⵉ ⵜⵎⵔⵏⵉⵡⵜ ⵏ ⵢⵉⵅⴼ ⵉⵏⵓ ⴳ ⵜⵍⴳⴰⵎⵜ ⵏ ⵉⵎⴰⵡⴰⴹⵏ"; +/* Error */ +"error_contact_request_already_sent" = "ⵉⵜⵜⵡⴰⵣⵏ ⵏⵏⵉⵜ ⵓⵙⵉⴳⵔ"; +/* Error */ +"error_contact_request_bad_checksum" = "ⵜⴰⵎⵓⵜⵜⵔⵜ ⵏ ⵉⵔⵉⵎⵏ ⴷ ⵜⴰⵎⵓⵛⵎⵜ, ⵙⵙⵉⴷⴷⴻⴷ Tox ID ⵢⵓⴷⴼⵏ"; +/* Error */ +"error_contact_request_new_nospam" = "ⴰⵜⵉⴳ ⵏ nospam ⴷ ⴰⵎⵛⵓⵎ, ⵙⵙⵉⴷⴷⴻⴷ Tox ID"; + +/* Call error */ +"call_error_already_in_call" = "ⵉⵙⵙⴰⵡⴰⵍ"; +/* Call error */ +"call_error_contact_is_offline" = "ⵉⵇⵇⵏ ⵓⵎⵉⴹⴰⵏ"; +/* Call error */ +"call_error_no_active_call" = "ⵓⵔ ⵜⵍⵍⵉ ⴽⵔⴰ ⵏ ⵜⵖⵓⵔⵉ ⵢⴰⴹⵏⵉⵏ"; + +/* Error while using color theme */ +"theme_error_cannot_open" = "ⵓⵔ ⵉⵣⵔⵉ ⵓⴽⵛⴰⵎ ⵙ ⵜⴼⵔⵙⵜ, ⵜⴰⵍⵖⴰ ⴷ ⵜⴰⵔⵎⵉⴷⵉⵜ"; + +/* Tab chats badge ending */ +"accessibility_chats_ending" = "ⵉⵎⵙⴰⵡⴰⵍⵏ ⵓⵔ ⵉⵜⵜⵡⴰⵖⵔⵉⵏ"; +/* Avatar button label in settings */ +"accessibility_avatar_button_label" = "ⵜⴰⵡⵍⴰⴼⵜ"; +/* Avatar button hint in settings */ +"accessibility_avatar_button_hint" = "ⵙⴽⵔ ⵏⵉⵖ ⴽⴽⵙ ⵜⴰⵡⵍⴰⴼⵜ."; +/* Chat button label in contact screen */ +"accessibility_chat_button_label" = "ⴰⵎⵙⴰⵡⴰⵍ"; +/* Chat button hint in contact screen */ +"accessibility_chat_button_hint" = "ⴷⴰ ⵜⵕⵥⵥⵎ ⵜⵏⴽⵍⵓⵜ ⵏ ⵓⵎⵙⴰⵡⴰⵍ."; +/* Call button label in contact screen */ +"accessibility_call_button_label" = "ⴰⵎⵢⴰⵡⴰⴹ ⴰⴳⵕⴹⴰⵏ"; +/* Call button hint in contact screen */ +"accessibility_call_button_hint" = "ⵙⴽⵔ ⴰⵎⵢⴰⵡⴰⴹ ⴰⴳⵕⴹⴰⵏ."; +/* Video button label in contact screen */ +"accessibility_video_button_label" = "ⴰⵎⵢⴰⵡⴰⴹ ⴰⵎⵡⴰⵍⴰⵏ"; +/* Video button hint in contact screen */ +"accessibility_video_button_hint" = "ⵙⴽⵔ ⴰⵎⵢⴰⵡⴰⴹ ⴰⵎⵡⴰⵍⴰⵏ."; +/* Tap to copy hint */ +"accessibility_show_copy_hint" = "ⵜⴰⵙⵎⵎⴰⵍⵜⵏ ⵜⵍⴳⴰⵎⵜ ⵏ ⵜⵓⵏⵖⵉⵍⵜ."; +/* Incoming message label */ +"accessibility_incoming_message_label" = "ⵜⴰⴱⵔⴰⵜ"; +/* Outgoing message label */ +"accessibility_outgoing_message_label" = "ⵜⴰⴱⵔⴰⵜ ⵏⵏⴽ"; +/* Tap to edit value hint */ +"accessibility_edit_value_hint" = "ⵉⵙⴳⴳⴷⵏ ⵏ ⵡⴰⵜⵉⴳ."; diff --git a/Antidote/zh.lproj/AppStoreLocalizable.strings b/Antidote/zh.lproj/AppStoreLocalizable.strings new file mode 100644 index 0000000000000000000000000000000000000000..3f83883781ab40037320a8d4bc9e212b89188067 GIT binary patch literal 7612 zcmeI1%Wl&^6oyBLRTqdyFx?;(NNBkffugEv78Kfos07O@O`MC8I#Did!yEBN+0aJ; zzW+={nTUo(7s!z;%l3FYmow*|bMf!rzshdQC2oT=arjPl)91|(PBtl=310P-;COhYtUy*tBra6fsItNx(0KcyD8VIyWp--`aFHL`TD%; zP`ae1&)A83?%udE*B!3gZkL(;TnD@#&|fmNT$^zc_k(kXwrZCk#ifl|qP&mPJ?@Lv zBYR4bJ*D=NYs1FgVjjuub#lUrFL)63C~ zl-u+eGmqM+JV7e25zW!G=bmY2$jq9h&-_n$mr;`ZsbP_@_LQ1|p^@19dZ&>Otf#cB zF?)Q2*2~$Fe)W_xlJ;Io?`^lqm=(@VcTDZj^rU^zwH8zA-xbJ# zYu=FCiICI2?|_{!l^6JEJNvr84t>au^M>7v2)hr+m~nK>GKa`}ihX)tQrKQT@p~EJ z=e?$4b`9*RAa{-T%nIAfsqMXruv1i5rlc(96D7s+7IlT)<;Ct+Wh%<8+8~u0c8Y&O zQu$kfUH-6(bCrWRR?1cMy-+o8S)+DRpqHcXgoWkB*~$?ZX@4Dq*3iDB>d0K!T>fk> z&QZSM9jD|ZlJY%QeFN(obyQ?359@K#|*qml{XjE zC&m_J#=i(-aTMZz#QfZqUAYVIAkN}8DVAA>LyH3Yw2WD<1uNs38!;+J9L?7vK1yGGx+*Rzml5XAsOxhL&#|vvpB2Y3L|A*qEMO`|&SwJ)oW+ER zt=mHvpI7KY?<%wVH|wdB*h5dzz=YN43*_2%foDh?>;`d=b?RgZ+9iP*RmLli?pe&h zI(ok@ZdF`@+6F#3W+H>0*Hd$`cYMMsWjBw_Y82bVfljfPz|2-=4}Vr>57u;-yvD}` zhE}|+zE&Ttso&d;)^Z49{{KM>{PeFN_&@O|E!G)!df-xSi*vz)$XZ4mHDk~JcbxN5 zoDqFvDVF10Wp?i-oU5!Z->ZqEmi&@fOL-gNq(~qB8Lf`W`CeZfqYmf0Ppj-w)^nF~ zpWI9TdcsPA-wwWb%nt0)()-+mr*ryD(9n8f9>=KDC{ywAL%JFL!y5%HE!#z2tTT=x KQ+D!Tj?o{Mwm*gd literal 0 HcmV?d00001 diff --git a/Antidote/zh.lproj/InfoPlist.strings b/Antidote/zh.lproj/InfoPlist.strings new file mode 100644 index 0000000000000000000000000000000000000000..6c333a86e6042a9b313f0a4b40846fa9afa0f57c GIT binary patch literal 978 zcmbu7K~KU!5QX2_U(xhP42X$bj0XZ26E&#O#ABfqNT4NcY2r`vPpaSSrcg~U*uzd| zW@p~ad)@D^fqDvb#tC$*RPV|((?)9*D%E#3CrY)%_jO~Ul3Yw}sf4W0Pm~iyE*FD0 z*9Ug0E#H#6jOZ0>-kknS6`2gQKto+=fE_wJVsed{X-B{9u+$2iK%bmTT~Is1i$O8W zKK_`^H++xPg^Ln)Psmo-*kSjWV|#o46Sm&Eiir9>)e+MY{0Kbjw7D@}p@l==kue6g zyT=Okpl3CaUJf|Z*3OXL8&0SA{@Gj@f}iR?aQqX2bQ+?O2V zYW){uBZHE&+-TS8KuDh literal 0 HcmV?d00001 diff --git a/Antidote/zh.lproj/Localizable.strings b/Antidote/zh.lproj/Localizable.strings new file mode 100644 index 0000000..4d6fc33 --- /dev/null +++ b/Antidote/zh.lproj/Localizable.strings @@ -0,0 +1,415 @@ +/* + Localizable.strings + Antidote + + Created by Dmytro Vorobiov on 08/10/15. + Copyright © 2015 dvor. All rights reserved. +*/ + +/* + Translation is done with Transifex service. + See https://www.transifex.com/antidote/antidote-ios/ +*/ + +/* Login screen text */ +"login_or_label" = "或"; +/* Login screen text */ +"create_account" = "创建账户"; +/* Login screen text */ +"import_profile" = "导入用户档案"; +/* Password field */ +"password" = "密码"; +/* Login button */ +"log_in" = "登录"; +/* Login screen text */ +"create_profile" = "建立用户档案"; +/* Login screen text */ +"import_to_antidote" = "导入到 Antidote"; +/* Login screen text */ +"create_account_username_title" = "你的联系人将怎样看到你?"; +/* Login screen text */ +"create_account_username_placeholder" = "用户名"; +/* Login screen text */ +"create_account_profile_title" = "如何为用户档案命名?"; +/* Login screen text */ +"create_account_profile_placeholder" = "档案名"; +/* Login screen text */ +"create_account_profile_hint" = "例如:家庭,iPhone"; +/* Login screen text */ +"set_password_title" = "Set Password"; +/* Login screen text */ +"set_password_hint" = "Password is required to protect your data. Keep it safe - once lost it cannot be restored."; +/* Login button */ +"create_account_next_button" = "Next"; +/* Login button */ +"create_account_go_button" = "前进"; +/* Default status message */ +"default_user_status_message" = "正在使用 Antidote"; + +/* PIN screen text */ +"pin_enter_to_unlock" = "Enter your PIN to unlock"; +/* PIN screen text */ +"pin_set" = "Set PIN"; +/* PIN screen text */ +"pin_confirm" = "Confirm PIN"; +/* PIN screen error */ +"pin_do_not_match" = "PINs did not match. Try again"; +/* PIN screen error */ +"pin_incorrect" = "Incorrect PIN"; +/* PIN screen error details */ +"pin_failed_attempts" = "Failed attempts: %@"; +/* PIN screen message shown on log out */ +"pin_logout_message" = "Too many failed attempts. You have been logged out."; +/* PIN screen screen */ +"pin_enabled" = "Enable PIN"; +/* PIN screen screen */ +"pin_touch_id_enabled" = "Enable Touch ID"; +/* PIN screen screen */ +"pin_description" = "Prevent unauthorized access to Antidote with a PIN."; +/* PIN screen screen */ +"pin_touch_id_description" = "Use your fingerprint as an alternative to entering a PIN."; +/* PIN screen screen */ +"pin_lock_timeout" = "Lock Timeout"; +/* PIN screen screen */ +"pin_lock_immediately" = "Immediately"; +/* PIN screen screen */ +"pin_lock_30_seconds" = "30 Seconds"; +/* PIN screen screen */ +"pin_lock_1_minute" = "1 Minute"; +/* PIN screen screen */ +"pin_lock_2_minutes" = "2 Minutes"; +/* PIN screen screen */ +"pin_lock_5_minutes" = "5 Minutes"; + +/* Label shown when connecting to Tox network */ +"connecting_label" = "连接中 ..."; + +/* Tab name and screen name */ +"contacts_title" = "联系人"; +/* Tab name and screen name */ +"chats_title" = "聊天"; +/* Tab name and screen name */ +"settings_title" = "设置"; +/* Tab name and screen name */ +"profile_title" = "档案"; + +/* No contacts placeholder text */ +"contact_no_contacts" = "没有联系人"; +/* No contacts placeholder text */ +"contact_no_contacts_add_contact" = "添加联系人\n或\n"; +/* No contacts placeholder text */ +"contact_no_contacts_share_tox_id" = "分享你的 Tox ID"; +/* Contact request section title */ +"contact_requests_section" = "联系人请求"; +/* Contact last seen status */ +"contact_last_seen" = "最后上线:%@"; +/* Screen name */ +"contact_request" = "联系人请求"; +/* Contact request button */ +"contact_request_decline" = "拒绝"; +/* Contact request button */ +"contact_request_accept" = "接受"; +/* Contact request confirmation */ +"contact_request_delete_title" = "删除联系人请求?"; +/* Text shown when contact was deleted */ +"contact_deleted" = "Deleted contact"; + +/* Share Tox ID text */ +"show_qr_code" = "显示二维码"; +/* Share Tox ID text */ +"copy" = "复制"; + +/* Add contat screen name */ +"add_contact_title" = "添加联系人"; +/* Add contat button */ +"add_contact_send" = "发送"; +/* Add contat placeholder text */ +"add_contact_tox_id_placeholder" = "输入 Tox ID"; +/* Add contat placeholder text */ +"add_contact_or_label" = "或"; +/* Add contat button */ +"add_contact_use_qr" = "使用二维码"; +/* Add contat placeholder text */ +"add_contact_default_message_title" = "信息"; +/* Add contat default text sended to contact */ +"add_contact_default_message_text" = "你好,请问可以成为你的联系人吗?"; +/* Add contat error */ +"add_contact_wrong_qr" = "无法从此二维码中找到 Tox ID"; + +/* User name text */ +"name" = "姓名"; +/* User nickname text */ +"nickname" = "昵称"; +/* User status message text */ +"status_message" = "状态消息"; +/* User status text */ +"status_title" = "状态"; +/* User Tox ID text */ +"my_tox_id" = "我的 Tox ID"; +/* User public key text */ +"public_key" = "公钥"; +/* Share Tox ID text */ +"show_qr" = "显示二维码"; +/* Profile menu item / screen name */ +"profile_details" = "档案详情"; +/* Profile button */ +"logout_button" = "安全退出"; + +/* QR code screen button */ +"qr_close_button" = "关闭"; + +/* Chat screen placeholder */ +"chat_no_chats" = "没有聊天"; +/* Chats screen message text */ +"chat_outgoing_file" = "发送的文件:"; +/* Chats screen message text */ +"chat_incoming_file" = "接收的文件:"; +/* Chats screen message text */ +"chat_call_finished" = "完成的语音通话"; +/* Chats screen message text */ +"chat_unanwered_call" = "未接的语音通话"; +/* Chat button */ +"chat_send_button" = "发送"; +/* Chat notification toast */ +"chat_new_messages" = "↓ 新的消息"; +/* Chat call information */ +"chat_call_message" = "呼叫, "; +/* Chat call information */ +"chat_missed_call_message" = "错过的语音通话"; +/* Item present in the menu on long press on message */ +"chat_more_menu_item" = "更多"; + +/* Status message */ +"status_offline" = "离线"; +/* Status message */ +"status_online" = "在线"; +/* Status message */ +"status_away" = "离开"; +/* Status message */ +"status_busy" = "忙碌"; + +/* Notification text */ +"notification_new_message" = "新消息"; +/* Notification text */ +"notification_incoming_contact_request" = "收到的联系人请求"; +/* Notification text */ +"notification_is_calling" = "正在呼叫"; +/* Notification text */ +"notification_incoming_file" = "接收的文件"; + +/* Settings menu / screen name */ +"settings_about" = "关于"; +/* Settings menu / screen name */ +"settings_faq" = "FAQ"; +/* Settings menu / screen name */ +"settings_advanced_settings" = "高级设置"; +/* About screen menu */ +"settings_antidote_version" = "Antidote 版本"; +/* About screen menu */ +"settings_antidote_build" = "Antidote 构建"; +/* About screen menu */ +"settings_toxcore_version" = "Toxcore 版本"; +/* About screen menu */ +"settings_acknowledgements" = "Acknowledgements"; +/* Settings screen menu */ +"settings_autodownload_images" = "自动下载文件"; +/* Settings screen menu */ +"settings_autodownload_images_description" = "自动下载收到的文件。"; +/* Settings screen menu */ +"settings_notifications_message_preview" = "通知预览"; +/* Settings screen menu */ +"settings_notifications_description" = "当应用程序进入后台之后,您仍会接收到 10 分钟以内的通知。"; +/* Settings screen menu */ +"settings_udp_enabled" = "Enable UDP"; +/* Settings screen menu */ +"settings_restore_default" = "恢复默认设置"; +/* Settings screen autodownload images option */ +"settings_never" = "从不"; +/* Settings screen autodownload images option */ +"settings_wifi" = "无线网络"; +/* Settings screen autodownload images option */ +"settings_using_wifi" = "使用无线网络"; +/* Settings screen autodownload images option */ +"settings_always" = "永远"; + +/* Profile settings menu */ +"change_password" = "修改密码"; +/* Profile settings menu */ +"delete_password" = "删除密码"; +/* Profile settings menu */ +"old_password" = "原密码"; +/* Change password text */ +"new_password" = "新密码"; +/* Change password text */ +"repeat_password" = "重复新密码"; +/* Change password button */ +"change_password_done" = "完成"; +/* Change password error */ +"password_is_empty_error" = "密码不能为空"; +/* Change password error */ +"wrong_old_password" = "密码错误"; +/* Change password error */ +"passwords_do_not_match" = "两次输入的密码不匹配"; + +/* Source of photo to take */ +"photo_from_camera" = "摄像头"; +/* Source of photo to take */ +"photo_from_photo_library" = "图片库"; +/* Error while converting avatar image */ +"change_avatar_error_convert_image" = "无法转换图像"; + +/* Alert text when sending file to contacts */ +"file_send_to_contact" = "发送给联系人"; + +/* Profile menu item */ +"export_profile" = "导出用户档案"; +/* Profile menu item */ +"delete_profile" = "删除用户档案"; +/* Delete profile confirmation */ +"delete_profile_confirmation_title_1" = "删除这个档案?"; +/* Delete profile confirmation */ +"delete_profile_confirmation_title_2" = "你确定?"; +/* Delete profile confirmation */ +"delete_profile_confirmation_message" = "这个操作无法被撤销"; + +/* Call screen text */ +"call_incoming" = "呼入的语音通话"; +/* Call screen text */ +"call_ended" = "通话结束"; +/* Call screen text */ +"call_reaching" = "连接中 ..."; + +/* File message text */ +"chat_file_cancelled" = "已取消"; +/* File message text */ +"chat_waiting" = "正在等待 ..."; +/* File message text */ +"chat_paused" = "已暂停"; + +/* Deleting chat confirmation */ +"delete_chat_title" = "删除这个聊天及所有消息记录?"; +/* Deleting contat confirmation */ +"delete_contact_title" = "删除这个联系人?\n你们之间的聊天记录将同时被删除。"; +/* Deleting contat request confirmation */ +"delete_contact_request_title" = "删除这个联系人请求?"; +/* Deleting single message in chat */ +"delete_single_message" = "Delete Message"; +/* Deleting multiple messages in chat. */ +"delete_multiple_messages" = "Delete Messages"; +/* Deleting all messages in chat. */ +"delete_all_messages" = "Delete All"; +/* Delete button */ +"alert_delete" = "删除"; +/* Delete button */ +"alert_cancel" = "取消"; + +/* Error while creating new profile */ +"login_enter_username_and_profile" = "请输入用户名与用户档案名。"; +/* Error while creating new profile */ +"login_profile_already_exists" = "档案名已存在"; + +/* General error title */ +"error_title" = "错误"; +/* General error button */ +"error_ok_button" = "确认"; +/* General error button */ +"error_retry_button" = "重试"; +/* Error */ +"error_contact_not_connected" = "联系人不在线"; +/* Error */ +"error_too_many_files" = "同时传输的文件数过多"; +/* Error */ +"error_internal_message" = "内部错误"; +/* Error */ +"error_wrong_password_title" = "密码错误"; +/* Error */ +"error_wrong_password_message" = "密码包含不支持的符号。"; +/* Error */ +"error_import_not_exist_title" = "无法导入 Tox 保存的文件"; +/* Error */ +"error_import_not_exist_message" = "文件不存在。"; +/* Error */ +"error_decrypt_title" = "无法解密 Tox 保存的文件"; +/* Error */ +"error_decrypt_empty_data_message" = "部分输入内容为空。"; +/* Error */ +"error_decrypt_bad_format_message" = "文件已损坏。"; +/* Error */ +"error_decrypt_wrong_password_message" = "密码错误或文件已损坏。"; +/* Error */ +"error_general_unknown_message" = "发生未知错误。"; +/* Error */ +"error_general_no_memory_message" = "内存不足。"; +/* Error */ +"error_general_bind_port_message" = "无法绑定端口。"; +/* Error */ +"error_general_profile_encrypted_message" = "档案已加密。"; +/* Error */ +"error_general_bad_format_message" = "文件已损坏。"; +/* Error */ +"error_proxy_title" = "代理服务器错误"; +/* Error */ +"error_proxy_invalid_address_message" = "代理服务器地址格式有误。"; +/* Error */ +"error_proxy_invalid_port_message" = "代理服务器端口无效。"; +/* Error */ +"error_proxy_host_not_resolved_message" = "无法连接到代理服务器。"; + +/* Error */ +"error_name_too_long" = "名字过长。"; +/* Error */ +"error_status_message_too_long" = "状态信息过长"; + +/* Error */ +"error_contact_request_too_long" = "消息过长"; +/* Error */ +"error_contact_request_no_message" = "未选中消息"; +/* Error */ +"error_contact_request_own_key" = "你不能添加自己为联系人"; +/* Error */ +"error_contact_request_already_sent" = "联系人请求已发送"; +/* Error */ +"error_contact_request_bad_checksum" = "无效的校验值,请检查你输入的 Tox ID"; +/* Error */ +"error_contact_request_new_nospam" = "该 Tox ID 已更改反垃圾设置,请核实"; + +/* Call error */ +"call_error_already_in_call" = "正在通话中"; +/* Call error */ +"call_error_contact_is_offline" = "联系人已离线"; +/* Call error */ +"call_error_no_active_call" = "没有进行中的语音通话"; + +/* Error while using color theme */ +"theme_error_cannot_open" = "无法开启主题,格式错误"; + +/* Tab chats badge ending */ +"accessibility_chats_ending" = "unread chats"; +/* Avatar button label in settings */ +"accessibility_avatar_button_label" = "Avatar"; +/* Avatar button hint in settings */ +"accessibility_avatar_button_hint" = "Sets or removes avatar."; +/* Chat button label in contact screen */ +"accessibility_chat_button_label" = "Chat"; +/* Chat button hint in contact screen */ +"accessibility_chat_button_hint" = "Opens chat dialog."; +/* Call button label in contact screen */ +"accessibility_call_button_label" = "Audio call"; +/* Call button hint in contact screen */ +"accessibility_call_button_hint" = "Makes audio call."; +/* Video button label in contact screen */ +"accessibility_video_button_label" = "Video call"; +/* Video button hint in contact screen */ +"accessibility_video_button_hint" = "Makes video call."; +/* Tap to copy hint */ +"accessibility_show_copy_hint" = "Shows copy menu."; +/* Tap to edit value hint */ +"accessibility_edit_value_hint" = "Edits value."; +/* Incoming message label */ +"accessibility_incoming_message_label" = "Message"; +/* Outgoing message label */ +"accessibility_outgoing_message_label" = "Your message"; +/* Text shown in chat when there are undelivered faux offline messages */ +"chat_pending_faux_offline_messages" = "当您和朋友都在线时,将发送未送达的消息。"; +/* Message shown on chat list when contact is typing */ +"chat_is_typing_text" = "正在打字..."; diff --git a/Antidote/zh.lproj/import-profile.html b/Antidote/zh.lproj/import-profile.html new file mode 100644 index 0000000..6a4a129 --- /dev/null +++ b/Antidote/zh.lproj/import-profile.html @@ -0,0 +1,9 @@ + +

导入你的 Tox 档案:

+ +
    +
  1. 使用任何应用 ( 如邮件或 Dropbox ) 发送“.tox”文件到你的设备
  2. +
  3. 然后打开这个文件
  4. +
  5. 在可用的应用列表中选择 Antidote
  6. +
  7. 选中你的新档案名并点击确定
  8. +
diff --git a/AntidoteTests/AntidoteTests-Bridging-Header.h b/AntidoteTests/AntidoteTests-Bridging-Header.h new file mode 100644 index 0000000..94dfa1b --- /dev/null +++ b/AntidoteTests/AntidoteTests-Bridging-Header.h @@ -0,0 +1,45 @@ +// +// Use this file to import your target's public headers that you would like to expose to Swift. +// + +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import + +#undef LOG_INFO +#undef LOG_DEBUG +#import "DDLog.h" +#import "DDASLLogger.h" +#import "DDTTYLogger.h" + +#import +#import +#import +#import + +#import "ExceptionHandling.h" + +#import "FBSnapshotTestCase.h" diff --git a/AntidoteTests/CellSnapshotTest.swift b/AntidoteTests/CellSnapshotTest.swift new file mode 100644 index 0000000..686b0a8 --- /dev/null +++ b/AntidoteTests/CellSnapshotTest.swift @@ -0,0 +1,15 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +class CellSnapshotTest: SnapshotBaseTest { + func updateCellLayout(_ cell: UITableViewCell) { + let size = cell.systemLayoutSizeFitting(CGSize(width: 320, height: 1000)) + cell.frame = CGRect(x: 0, y: 0, width: 320, height: size.height) + + cell.setNeedsLayout() + cell.layoutIfNeeded() + } +} diff --git a/AntidoteTests/ChatIncomingCallCellSnapshotTest.swift b/AntidoteTests/ChatIncomingCallCellSnapshotTest.swift new file mode 100644 index 0000000..c20b468 --- /dev/null +++ b/AntidoteTests/ChatIncomingCallCellSnapshotTest.swift @@ -0,0 +1,37 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +class ChatIncomingCallCellSnapshotTest: CellSnapshotTest { + override func setUp() { + super.setUp() + + recordMode = false + } + + func testAnsweredCall() { + let model = ChatIncomingCallCellModel() + model.callDuration = 137 + model.answered = true + + let cell = ChatIncomingCallCell() + cell.setupWithTheme(theme, model: model) + + updateCellLayout(cell) + verifyView(cell) + } + + func testNonAnsweredCall() { + let model = ChatIncomingCallCellModel() + model.callDuration = 137 + model.answered = false + + let cell = ChatIncomingCallCell() + cell.setupWithTheme(theme, model: model) + + updateCellLayout(cell) + verifyView(cell) + } +} diff --git a/AntidoteTests/ChatIncomingFileCellSnapshotTest.swift b/AntidoteTests/ChatIncomingFileCellSnapshotTest.swift new file mode 100644 index 0000000..c73ea8f --- /dev/null +++ b/AntidoteTests/ChatIncomingFileCellSnapshotTest.swift @@ -0,0 +1,109 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation +import MobileCoreServices + +class ChatIncomingFileCellSnapshotTest: CellSnapshotTest { + override func setUp() { + super.setUp() + + recordMode = false + } + + func testWaitingState() { + let model = ChatIncomingFileCellModel() + model.state = .waitingConfirmation + model.fileName = "file.txt" + model.fileSize = "3.14 KB" + model.fileUTI = kUTTypePlainText as String + + let cell = ChatIncomingFileCell() + cell.setupWithTheme(theme, model: model) + + updateCellLayout(cell) + verifyView(cell) + } + + func testLoading() { + let model = ChatIncomingFileCellModel() + model.state = .loading + model.fileName = "file.txt" + model.fileSize = "3.14 KB" + model.fileUTI = kUTTypePlainText as String + + let progressObject = MockedChatProgressProtocol() + + let cell = ChatIncomingFileCell() + cell.setupWithTheme(theme, model: model) + cell.progressObject = progressObject + + progressObject.updateProgress?(0.43) + + updateCellLayout(cell) + verifyView(cell) + } + + func testPaused() { + let model = ChatIncomingFileCellModel() + model.state = .paused + model.fileName = "file.txt" + model.fileSize = "3.14 KB" + model.fileUTI = kUTTypePlainText as String + + let progressObject = MockedChatProgressProtocol() + + let cell = ChatIncomingFileCell() + cell.setupWithTheme(theme, model: model) + cell.progressObject = progressObject + + progressObject.updateProgress?(0.43) + + updateCellLayout(cell) + verifyView(cell) + } + + func testCancelled() { + let model = ChatIncomingFileCellModel() + model.state = .cancelled + model.fileName = "file.txt" + model.fileSize = "3.14 KB" + model.fileUTI = kUTTypePlainText as String + + let cell = ChatIncomingFileCell() + cell.setupWithTheme(theme, model: model) + + updateCellLayout(cell) + verifyView(cell) + } + + func testDone() { + let model = ChatIncomingFileCellModel() + model.state = .done + model.fileName = "file.txt" + model.fileSize = "3.14 KB" + model.fileUTI = kUTTypePlainText as String + + let cell = ChatIncomingFileCell() + cell.setupWithTheme(theme, model: model) + + updateCellLayout(cell) + verifyView(cell) + } + + func testDoneWithImage() { + let model = ChatIncomingFileCellModel() + model.state = .done + model.fileName = "icon.png" + model.fileSize = "3.14 KB" + model.fileUTI = kUTTypePNG as String + + let cell = ChatIncomingFileCell() + cell.setupWithTheme(theme, model: model) + cell.setButtonImage(image) + + updateCellLayout(cell) + verifyView(cell) + } +} diff --git a/AntidoteTests/ChatIncomingTextCellSnapshotTest.swift b/AntidoteTests/ChatIncomingTextCellSnapshotTest.swift new file mode 100644 index 0000000..5f7d62f --- /dev/null +++ b/AntidoteTests/ChatIncomingTextCellSnapshotTest.swift @@ -0,0 +1,67 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +class ChatIncomingTextCellSnapshotTest: CellSnapshotTest { + override func setUp() { + super.setUp() + + recordMode = false + } + + func testSmallMessage() { + let model = ChatBaseTextCellModel() + model.message = "Hi" + + let cell = ChatIncomingTextCell() + cell.setupWithTheme(theme, model: model) + + updateCellLayout(cell) + verifyView(cell) + } + + func testMediumMessage() { + let model = ChatBaseTextCellModel() + model.message = "Some nice medium message" + + let cell = ChatIncomingTextCell() + cell.setupWithTheme(theme, model: model) + + updateCellLayout(cell) + verifyView(cell) + } + + func testHugeMessage() { + let model = ChatBaseTextCellModel() + model.message = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. " + + let cell = ChatIncomingTextCell() + cell.setupWithTheme(theme, model: model) + + updateCellLayout(cell) + verifyView(cell) + } + + // Broken on Travic CI. + // func testWithLink() { + // let model = ChatBaseTextCellModel() + // model.message = "Lorem ipsum dolor sit amet, https://tox.chat consectetur adipiscing elit, +1234567890" + + // let cell = ChatIncomingTextCell() + // cell.setupWithTheme(theme, model: model) + + // updateCellLayout(cell) + + // let expectation = self.expectation(description: "link rendering expectation") + + // let delayTime = DispatchTime.now() + Double(Int64(0.5 * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC) + // DispatchQueue.main.asyncAfter(deadline: delayTime) { [weak self] in + // self?.verifyView(cell) + // expectation.fulfill() + // } + + // waitForExpectations(timeout: 1.0, handler: nil) + // } +} diff --git a/AntidoteTests/ChatListCellSnapshotTest.swift b/AntidoteTests/ChatListCellSnapshotTest.swift new file mode 100644 index 0000000..067344a --- /dev/null +++ b/AntidoteTests/ChatListCellSnapshotTest.swift @@ -0,0 +1,62 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +class ChatListCellSnapshotTest: CellSnapshotTest { + override func setUp() { + super.setUp() + + recordMode = false + } + + func testDefault() { + let model = ChatListCellModel() + model.avatar = image + model.nickname = "dvor" + model.message = "Hi! This is some random message." + model.dateText = "Yesterday" + model.status = .offline + model.isUnread = false + + let cell = ChatListCell() + cell.setupWithTheme(theme, model: model) + + updateCellLayout(cell) + verifyView(cell) + } + + func testLongMessage() { + let model = ChatListCellModel() + model.avatar = image + model.nickname = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." + model.message = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. " + model.dateText = "Yesterday" + model.status = .online + model.isUnread = false + + let cell = ChatListCell() + cell.setupWithTheme(theme, model: model) + + updateCellLayout(cell) + verifyView(cell) + } + + func testUnread() { + let model = ChatListCellModel() + model.avatar = image + model.nickname = "dvor" + model.message = "Hi! This is some random message." + model.dateText = "10:37" + model.status = .away + model.isUnread = true + + let cell = ChatListCell() + cell.setupWithTheme(theme, model: model) + + updateCellLayout(cell) + verifyView(cell) + } +} + diff --git a/AntidoteTests/ChatMovableDateCellSnapshotTest.swift b/AntidoteTests/ChatMovableDateCellSnapshotTest.swift new file mode 100644 index 0000000..625ca1e --- /dev/null +++ b/AntidoteTests/ChatMovableDateCellSnapshotTest.swift @@ -0,0 +1,36 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +class ChatMovableDateCellSnapshotTest: CellSnapshotTest { + override func setUp() { + super.setUp() + + recordMode = false + } + + func testDefault() { + let model = ChatMovableDateCellModel() + model.dateString = "03:13" + + let cell = ChatMovableDateCell() + cell.setupWithTheme(theme, model: model) + + updateCellLayout(cell) + verifyView(cell) + } + + func testPanned() { + let model = ChatMovableDateCellModel() + model.dateString = "03:13" + + let cell = ChatMovableDateCell() + cell.setupWithTheme(theme, model: model) + + updateCellLayout(cell) + cell.movableOffset = -200.0 + verifyView(cell) + } +} diff --git a/AntidoteTests/ChatOutgoingCallCellSnapshotTest.swift b/AntidoteTests/ChatOutgoingCallCellSnapshotTest.swift new file mode 100644 index 0000000..76be5e3 --- /dev/null +++ b/AntidoteTests/ChatOutgoingCallCellSnapshotTest.swift @@ -0,0 +1,37 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +class ChatOutgoingCallCellSnapshotTest: CellSnapshotTest { + override func setUp() { + super.setUp() + + recordMode = false + } + + func testAnsweredCall() { + let model = ChatOutgoingCallCellModel() + model.callDuration = 137 + model.answered = true + + let cell = ChatOutgoingCallCell() + cell.setupWithTheme(theme, model: model) + + updateCellLayout(cell) + verifyView(cell) + } + + func testNonAnsweredCall() { + let model = ChatOutgoingCallCellModel() + model.callDuration = 137 + model.answered = false + + let cell = ChatOutgoingCallCell() + cell.setupWithTheme(theme, model: model) + + updateCellLayout(cell) + verifyView(cell) + } +} diff --git a/AntidoteTests/ChatOutgoingFileCellSnapshotTest.swift b/AntidoteTests/ChatOutgoingFileCellSnapshotTest.swift new file mode 100644 index 0000000..1b508ae --- /dev/null +++ b/AntidoteTests/ChatOutgoingFileCellSnapshotTest.swift @@ -0,0 +1,179 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation +import MobileCoreServices + +class ChatOutgoingFileCellSnapshotTest: CellSnapshotTest { + override func setUp() { + super.setUp() + + recordMode = false + } + + func testWaitingState() { + let model = ChatOutgoingFileCellModel() + model.state = .waitingConfirmation + model.fileName = "file.txt" + model.fileSize = "3.14 KB" + model.fileUTI = kUTTypePlainText as String + + let cell = ChatOutgoingFileCell() + cell.setupWithTheme(theme, model: model) + + updateCellLayout(cell) + verifyView(cell) + } + + func testLoading() { + let model = ChatOutgoingFileCellModel() + model.state = .loading + model.fileName = "file.txt" + model.fileSize = "3.14 KB" + model.fileUTI = kUTTypePlainText as String + + let progressObject = MockedChatProgressProtocol() + + let cell = ChatOutgoingFileCell() + cell.setupWithTheme(theme, model: model) + cell.progressObject = progressObject + + progressObject.updateProgress?(0.43) + + updateCellLayout(cell) + verifyView(cell) + } + + func testPaused() { + let model = ChatOutgoingFileCellModel() + model.state = .paused + model.fileName = "file.txt" + model.fileSize = "3.14 KB" + model.fileUTI = kUTTypePlainText as String + + let progressObject = MockedChatProgressProtocol() + + let cell = ChatOutgoingFileCell() + cell.setupWithTheme(theme, model: model) + cell.progressObject = progressObject + + progressObject.updateProgress?(0.43) + + updateCellLayout(cell) + verifyView(cell) + } + + func testCancelled() { + let model = ChatOutgoingFileCellModel() + model.state = .cancelled + model.fileName = "file.txt" + model.fileSize = "3.14 KB" + model.fileUTI = kUTTypePlainText as String + + let cell = ChatOutgoingFileCell() + cell.setupWithTheme(theme, model: model) + + updateCellLayout(cell) + verifyView(cell) + } + + func testDone() { + let model = ChatOutgoingFileCellModel() + model.state = .done + model.fileName = "file.txt" + model.fileSize = "3.14 KB" + model.fileUTI = kUTTypePlainText as String + + let cell = ChatOutgoingFileCell() + cell.setupWithTheme(theme, model: model) + + updateCellLayout(cell) + verifyView(cell) + } + + func testWaitingStateWithImage() { + let model = ChatOutgoingFileCellModel() + model.state = .waitingConfirmation + model.fileName = "icon.png" + model.fileSize = "3.14 KB" + model.fileUTI = kUTTypePNG as String + + let cell = ChatOutgoingFileCell() + cell.setupWithTheme(theme, model: model) + cell.setButtonImage(image) + + updateCellLayout(cell) + verifyView(cell) + } + + func testLoadingWithImage() { + let model = ChatOutgoingFileCellModel() + model.state = .loading + model.fileName = "icon.png" + model.fileSize = "3.14 KB" + model.fileUTI = kUTTypePNG as String + + let progressObject = MockedChatProgressProtocol() + + let cell = ChatOutgoingFileCell() + cell.setupWithTheme(theme, model: model) + cell.progressObject = progressObject + cell.setButtonImage(image) + + progressObject.updateProgress?(0.43) + + updateCellLayout(cell) + verifyView(cell) + } + + func testPausedWithImage() { + let model = ChatOutgoingFileCellModel() + model.state = .paused + model.fileName = "icon.png" + model.fileSize = "3.14 KB" + model.fileUTI = kUTTypePNG as String + + let progressObject = MockedChatProgressProtocol() + + let cell = ChatOutgoingFileCell() + cell.setupWithTheme(theme, model: model) + cell.progressObject = progressObject + cell.setButtonImage(image) + + progressObject.updateProgress?(0.43) + + updateCellLayout(cell) + verifyView(cell) + } + + func testCancelledWithImage() { + let model = ChatOutgoingFileCellModel() + model.state = .cancelled + model.fileName = "icon.png" + model.fileSize = "3.14 KB" + model.fileUTI = kUTTypePNG as String + + let cell = ChatOutgoingFileCell() + cell.setupWithTheme(theme, model: model) + cell.setButtonImage(image) + + updateCellLayout(cell) + verifyView(cell) + } + + func testDoneWithImage() { + let model = ChatOutgoingFileCellModel() + model.state = .done + model.fileName = "icon.png" + model.fileSize = "3.14 KB" + model.fileUTI = kUTTypePNG as String + + let cell = ChatOutgoingFileCell() + cell.setupWithTheme(theme, model: model) + cell.setButtonImage(image) + + updateCellLayout(cell) + verifyView(cell) + } +} diff --git a/AntidoteTests/ChatOutgoingTextCellSnapshotTest.swift b/AntidoteTests/ChatOutgoingTextCellSnapshotTest.swift new file mode 100644 index 0000000..5a86af7 --- /dev/null +++ b/AntidoteTests/ChatOutgoingTextCellSnapshotTest.swift @@ -0,0 +1,83 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +class ChatOutgoingTextCellSnapshotTest: CellSnapshotTest { + override func setUp() { + super.setUp() + + recordMode = false + } + + func testSmallMessage() { + let model = ChatOutgoingTextCellModel() + model.message = "Hi" + model.delivered = true + + let cell = ChatOutgoingTextCell() + cell.setupWithTheme(theme, model: model) + + updateCellLayout(cell) + verifyView(cell) + } + + func testMediumMessage() { + let model = ChatOutgoingTextCellModel() + model.message = "Some nice medium message" + model.delivered = true + + let cell = ChatOutgoingTextCell() + cell.setupWithTheme(theme, model: model) + + updateCellLayout(cell) + verifyView(cell) + } + + func testMediumMessageUndelivered() { + let model = ChatOutgoingTextCellModel() + model.message = "Some nice medium message" + model.delivered = false + + let cell = ChatOutgoingTextCell() + cell.setupWithTheme(theme, model: model) + + updateCellLayout(cell) + verifyView(cell) + } + + func testHugeMessage() { + let model = ChatOutgoingTextCellModel() + model.message = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. " + model.delivered = true + + let cell = ChatOutgoingTextCell() + cell.setupWithTheme(theme, model: model) + + updateCellLayout(cell) + verifyView(cell) + } + + // Broken on Travic CI. + // func testWithLink() { + // let model = ChatOutgoingTextCellModel() + // model.message = "Lorem ipsum dolor sit amet, https://tox.chat consectetur adipiscing elit, +1234567890" + // model.delivered = true + + // let cell = ChatOutgoingTextCell() + // cell.setupWithTheme(theme, model: model) + + // updateCellLayout(cell) + + // let expectation = self.expectation(description: "link rendering expectation") + + // let delayTime = DispatchTime.now() + Double(Int64(0.5 * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC) + // DispatchQueue.main.asyncAfter(deadline: delayTime) { [weak self] in + // self?.verifyView(cell) + // expectation.fulfill() + // } + + // waitForExpectations(timeout: 1.0, handler: nil) + // } +} diff --git a/AntidoteTests/FriendListDataSourceTest.swift b/AntidoteTests/FriendListDataSourceTest.swift new file mode 100644 index 0000000..7fc4434 --- /dev/null +++ b/AntidoteTests/FriendListDataSourceTest.swift @@ -0,0 +1,159 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import XCTest + +class FriendListDataSourceTest: XCTestCase { + override func setUp() { + super.setUp() + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + super.tearDown() + } + + // Antidote/objcTox should be refactored to protocol oriented architecture, then testing will become possible :-) + + // func testPerformFetch() { + // let requests = MockedFetchedResultsController(objects: [[]]) + // let friends = MockedFetchedResultsController(objects: [[]]) + + // let dataSource = FriendListDataSource(requestsController: requests, friendsController: friends) + + // // calling some method requiring both requests and friends controller + // _ = dataSource.numberOfSections() + + // XCTAssertTrue(requests.didPerformFetch) + // XCTAssertTrue(friends.didPerformFetch) + // } + + // func testReset() { + // let requests = MockedFetchedResultsController(objects: [[]]) + // let friends = MockedFetchedResultsController(objects: [[]]) + + // let dataSource = FriendListDataSource(requestsController: requests, friendsController: friends) + + // dataSource.reset() + + // XCTAssertTrue(requests.didReset) + // XCTAssertTrue(friends.didReset) + // } + + // func testNumberOfSections_NoRequests_NoFriends() { + // let requests = MockedFetchedResultsController(objects: [[]]) + // let friends = MockedFetchedResultsController(objects: [[]]) + + // let dataSource = FriendListDataSource(requestsController: requests, friendsController: friends) + + // XCTAssertEqual(dataSource.numberOfSections(), 1) + // } + + // func testNumberOfSections_NoRequests_OneFriendSection() { + // let requests = MockedFetchedResultsController(objects: [[]]) + // let friends = MockedFetchedResultsController(objects: [[ NSObject() ]]) + + // let dataSource = FriendListDataSource(requestsController: requests, friendsController: friends) + + // XCTAssertEqual(dataSource.numberOfSections(), 1) + // } + + // func testNumberOfSections_NoRequests_MultipleFriendSection() { + // let requests = MockedFetchedResultsController(objects: [[]]) + // let friends = MockedFetchedResultsController(objects: [ + // [NSObject()], + // [NSObject()], + // [NSObject()], + // ]) + + // let dataSource = FriendListDataSource(requestsController: requests, friendsController: friends) + + // XCTAssertEqual(dataSource.numberOfSections(), 3) + // } + + // func testNumberOfSections_OneRequest_NoFriends() { + // let requests = MockedFetchedResultsController(objects: [[ NSObject() ]]) + // let friends = MockedFetchedResultsController(objects: [[]]) + + // let dataSource = FriendListDataSource(requestsController: requests, friendsController: friends) + + // XCTAssertEqual(dataSource.numberOfSections(), 2) + // } + + // func testNumberOfSections_MultipleRequest_NoFriends() { + // let requests = MockedFetchedResultsController(objects: [[ + // NSObject(), + // NSObject(), + // NSObject(), + // ]]) + // let friends = MockedFetchedResultsController(objects: [[]]) + + // let dataSource = FriendListDataSource(requestsController: requests, friendsController: friends) + + // XCTAssertEqual(dataSource.numberOfSections(), 2) + // } + + // func testNumberOfSections_MultipleRequest_MultipleFriends() { + // let requests = MockedFetchedResultsController(objects: [[ + // NSObject(), + // NSObject(), + // NSObject(), + // ]]) + // let friends = MockedFetchedResultsController(objects: [ + // [NSObject()], + // [NSObject()], + // [NSObject()], + // ]) + + // let dataSource = FriendListDataSource(requestsController: requests, friendsController: friends) + + // XCTAssertEqual(dataSource.numberOfSections(), 4) + // } + + // func testNumberOfRows_Empty() { + // let requests = MockedFetchedResultsController(objects: [[]]) + // let friends = MockedFetchedResultsController(objects: [[]]) + + // let dataSource = FriendListDataSource(requestsController: requests, friendsController: friends) + + // XCTAssertEqual(dataSource.numberOfRowsInSection(0), 0) + // } + + // func testNumberOfRows_NoRequest_Friends() { + // let requests = MockedFetchedResultsController(objects: [[]]) + // let friends = MockedFetchedResultsController(objects: [ + // [NSObject()], + // [NSObject(), NSObject()], + // [NSObject(), NSObject(), NSObject()], + // ]) + + // let dataSource = FriendListDataSource(requestsController: requests, friendsController: friends) + + // XCTAssertEqual(dataSource.numberOfRowsInSection(0), 1) + // XCTAssertEqual(dataSource.numberOfRowsInSection(1), 2) + // XCTAssertEqual(dataSource.numberOfRowsInSection(2), 3) + // } + + // func testNumberOfRows_Requests_Friends() { + // let requests = MockedFetchedResultsController(objects: [[ + // NSObject(), + // NSObject(), + // NSObject(), + // NSObject(), + // ]]) + // let friends = MockedFetchedResultsController(objects: [ + // [NSObject()], + // [NSObject(), NSObject()], + // [NSObject(), NSObject(), NSObject()], + // ]) + + // let dataSource = FriendListDataSource(requestsController: requests, friendsController: friends) + + // XCTAssertEqual(dataSource.numberOfRowsInSection(0), 4) + // XCTAssertEqual(dataSource.numberOfRowsInSection(1), 1) + // XCTAssertEqual(dataSource.numberOfRowsInSection(2), 2) + // XCTAssertEqual(dataSource.numberOfRowsInSection(3), 3) + // } +} diff --git a/AntidoteTests/Info.plist b/AntidoteTests/Info.plist new file mode 100644 index 0000000..526bf85 --- /dev/null +++ b/AntidoteTests/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 30 + + diff --git a/AntidoteTests/KeychainManagerTests.swift b/AntidoteTests/KeychainManagerTests.swift new file mode 100644 index 0000000..312ad48 --- /dev/null +++ b/AntidoteTests/KeychainManagerTests.swift @@ -0,0 +1,52 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import XCTest + +class KeychainManagerTests: XCTestCase { + func testToxPassword() { + let manager = KeychainManager() + + manager.toxPasswordForActiveAccount = nil + XCTAssertNil(manager.toxPasswordForActiveAccount) + + manager.toxPasswordForActiveAccount = "password" + XCTAssertEqual(manager.toxPasswordForActiveAccount!, "password") + + manager.toxPasswordForActiveAccount = "another" + XCTAssertEqual(manager.toxPasswordForActiveAccount!, "another") + + manager.toxPasswordForActiveAccount = nil + XCTAssertNil(manager.toxPasswordForActiveAccount) + + manager.toxPasswordForActiveAccount = "some pass" + XCTAssertEqual(manager.toxPasswordForActiveAccount!, "some pass") + + manager.deleteActiveAccountData() + XCTAssertNil(manager.toxPasswordForActiveAccount) + } + + func testFailedPinAttemptsNumber() { + let manager = KeychainManager() + + manager.failedPinAttemptsNumber = nil + XCTAssertNil(manager.failedPinAttemptsNumber) + + manager.failedPinAttemptsNumber = 5 + XCTAssertEqual(manager.failedPinAttemptsNumber!, 5) + + manager.failedPinAttemptsNumber = 8 + XCTAssertEqual(manager.failedPinAttemptsNumber!, 8) + + manager.failedPinAttemptsNumber = nil + XCTAssertNil(manager.failedPinAttemptsNumber) + + manager.failedPinAttemptsNumber = 3 + XCTAssertEqual(manager.failedPinAttemptsNumber!, 3) + + manager.deleteActiveAccountData() + XCTAssertNil(manager.failedPinAttemptsNumber) + } +} + diff --git a/AntidoteTests/LoginChoiceViewSnapshotTest.swift b/AntidoteTests/LoginChoiceViewSnapshotTest.swift new file mode 100644 index 0000000..14bb37a --- /dev/null +++ b/AntidoteTests/LoginChoiceViewSnapshotTest.swift @@ -0,0 +1,18 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +class LoginChoiceViewSnapshotTest: SnapshotBaseTest { + override func setUp() { + super.setUp() + + recordMode = false + } + + func testDefault() { + let controller = LoginChoiceController(theme: theme) + verifyView(controller.view) + } +} diff --git a/AntidoteTests/MockedChatProgressProtocol.swift b/AntidoteTests/MockedChatProgressProtocol.swift new file mode 100644 index 0000000..0c51012 --- /dev/null +++ b/AntidoteTests/MockedChatProgressProtocol.swift @@ -0,0 +1,10 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation + +class MockedChatProgressProtocol: ChatProgressProtocol { + var updateProgress: ((_ progress: Float) -> Void)? + var updateEta: ((_ eta: CFTimeInterval, _ bytesPerSecond: OCTToxFileSize) -> Void)? +} diff --git a/AntidoteTests/ReferenceImages_64/AntidoteTests.ChatIncomingCallCellSnapshotTest/testAnsweredCall_normal@2x.png b/AntidoteTests/ReferenceImages_64/AntidoteTests.ChatIncomingCallCellSnapshotTest/testAnsweredCall_normal@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..635c4bf6d3813cc2dd8554cf4644800484febe2e GIT binary patch literal 4437 zcmd^C`#;nD`=8}p-ICBv2ZbDRtfZWUMAUjX2#hi0~3#KJFmM*;vc%DLa*2hC3 zmQHS47Pz&3KT2Cmb;oY`q7$x8ty=*_D{U;z-EIlYVc~zdxgYEr) ze7)qF_R(74Y1|p{_S#Dt7HR`|;J?~Zs(~F6G9P>b-r|303C+k#iJ5l?4GmzyXNdg@ zqt22x*FOx+@a?C&=aJLYvFuN+wOpwq)TZfJYHa?>=;uwtm|yl*LVN{)fT$S&xDNvm z{I78n{FIzq8zVg&)Z+@9&obPxKfU^s%f00O{}vRyf!XGI#2KV_=jr>eBQwe$iKO9@ z=l*p|S5=(7C(c`z#>*RjnZ8l!IzzooINDM>XXCx^Utx{`nb|#21H)fsXgYIWej!0@=aahXwcrDrkB4D)V#D= zcW@&=tWrFu+b#Q0vx~UwFi3v(ENI>j$k&u{K>me5`6wP7^$9es+PQdSZQoBerLYe~<25X7$%hA)%`7yv8T`q{yHI~bzgP7L$TT~%U zKR+C~cb%dcMo>wQjCXY%oUbQy6ep1m*Hns5WX?gTQegJo9>=#D(Im_9T_-*9z2rT` zQp3;Xaw~{)N;*aLc3(M}F0AKzCwex+*_+XDErD|uHQF837d@xfN@#C=w;5$dIi|3* zMj^z%QxUF|DMc|4;GCU7*{d)wae@xn^`{p9_zm&xbOzX%|9 zAiLUG=Z84Bk=%hW3cef=+>0)7j*K7Ck)x7oxtIC;P>jMm04Cn4jwBEF^ zH*4tyJu5FJ5oiyHO*L8Ru!Gr0A((7Cg^~BWGePsuZzFObH6p&ay2PcCE~DwtKR9i8 zY1G(Py&Jau1Y~9-vDb8bVR+qQ%C+|*Q9ss%X-!%}x6}mq;B>t*rL($uQM#czBHN7Z zzad5|HaNQG$i7K5;ElR2`Cbbj*cYWpcs8bBE*v4QcW7N78Y~=lWw_IJ z>BQocFmE|FbzE~8Mu7|m{ylZQ#TOV}KUA_mn!7S^Z%2z?OZIEW!}^prVPo-%>n@m* zTsEj=jHVZJM@;^cRjE5NFE)3B@`*#GRxs4K-m$IvAt;&z&p;BF{TIM3E_z@{v98%# zdO5}gr>N>Exo7Dgqb2DD9v%0qyS30?Y(8^svz%0p_NDsF^$A& z%c#+zp63zVhYWeB!-0{}b}8e6;S;KW`MM~N2CSP*lx=8)mWgY(e9PA})JYQ}lKFGi zNT%e~cxBibt9g^{l|4mOfX;nq`O8`W*bqLPw6YWJHZ`iMZKX zn-fdP6ZMeUFjcHZE#9u$k5XzaI zjT;oREDNm}3tV|1ZIeTKJ87J^0RK{EkVtkBDug13hNNeepZg#7 zwb&8KJqg{-R7t(^)f(T_#JX?gs{?m1AMd9bCu&a8DvAd(xIQXcR1wMrWi_lpkZDr4z5Z1Ss6iX=(-cz~k+ zLykgcz_Af=BHSoRQJC6dZ%=VKB$#q|Y2b?);d!2BF@WiHb2i4YmQ1l~jVK z#@?4oaNlQROCS_Kj`rnzWOdbXtXkI7ne*02)K-(MOh08SwMl4_)$}>jQeGaCH*lx~ z+DG(ai%*7TkUeYJr+3R}oO?qNW|BsRh@77JW@m6UoW||!>;#RqE7dX(Jc-H@! z_k=*u&p8`VUeGB;7)5nnPEPLb$8}p&(P|y#9tRc~N>a3ij2y=RfT9W*jFj`@TGSiB zqBG_k0dn;vI{20SyXv6Pzw8RU&|%Zf>&oH=a=zg@hMTHQDCk&j208p&aFWr2&&n^i zkr!M&KW`^7K%BtfuQ9_Oa0PDzj;bltib;M{f=rRk`hJs51g>+UU zceF}<9C}bpKyaTKAfd>)P$N6OsZv4b@{=%w(&g#2TBE?zySks^q@>=h(qWXK3gajC zeR3Y3qJ4GO58Udlm57~m=s5UZ-Xic3{V~585YV)|WbmhaQ}~y*(pj1@LXUYF6d1Q=;}SDURt4j8gw_Ftz@j8}gPFGAPEFDS%GheSt-z z)AJ7_jF_!nGna+L){t@1Mu#eECm4;BezAC8xZ|tnOk}rMAvFmMr3cwIG%-?y=qE-zsAe(dMgkBG;^9m$H~q6phYU0qFtMb*`^G{=R`W(jU< zx82{5iWZu|g)D9rp*8&rbFei=uAY9f=UL^v+w6^U6)XU1DjVV;A}vZBrqS~9Z}2?u z2niQZo#A!fG7<5Hb!xP-lUG<#p?>o-o@`e|QSQ^zo$%dUF59Y~vy8r_Z1f?#7-)`+WKZ#r!ik_;a|< zMw^i2&X5^(9VW+G48Zs{GxrT8l+_R$_*ik9M`lli_7D1~s9{1E!W7EVULTHl_7W3t z2bhf0GGkk_*FWFSOM#bqK=rL=R6;8^lXW>Q9dIX}|Y5C;!8 z5mKl@3t#;9$xd}b4N}w;*y{h>Y+aqn@1ehRBhbE(kmBOp&`0`Uo)+jvc)@tX@@ycs%s=82blq{2Vg!rgZ7(RNB52>Hwk6H0iudiR&Y$o;1#8xxTN z7$IYB23_@5ti=ohj4m7FhGhw%A>|s=ih)8FEYYFe`O&k;@)1upv>h8cN#`qr2zdT0 zZh$aGj_WP&8e$V;Ki79PC4*77Y;yEkJw z<naJBKe~9RJ3rvR!q%Lh_!=OhSLzQb8SLJRP|imSzH>+8uYiDtaw-mhbP)TQw++^GL> zk4-0u)6OzyQfkldp!tytL~7i|lI0t#%oIM}>i9nNB;F2x!}joahT}B8X3!K1q#F8m zOaB(`-|F4pBe%Pyq&vTv6echk?b3I9x<~L3q7dQ?808SYj z8CU}VtPl5Nqhm+*-(EiqhV~sxi1iIUKn3>PkNpArJtKz@0Dw>IZ(}jG7X7(DdCu3s z!gk-Y?%Usw=)OrF`2CojSBd;?fAO*J#s=4H!&nvzAWwKb&vwCTYO5oypkJOYHuI-% zxn+v^=77cG6-{M}i|Q3Mk%m96Nu6YhW*TSDRaCTmIsAT3pU30^uftN%fT?Gu58Oj) zB=^UUz5H)UK~OJjKhfR$lgrPa*j60*0j1$1GtwKYcIy`ND9bTj0PC5D0JaN&|Htsx z1=dg-^-h9!aNfK?h|Y*7UhCT<#}eNEq7u8x)eR!3P^zn2y}4qKLM|^PWWt0H*Zzx| zZN9EqeMtj!$1dz6P6zK9EObclD*b&}`jvk`YAMc2WGapQfUGB@pU?33)e3n2L3~q( z%N`xYD8=LPL;=X7oi0XPRX+VBD_0~?kB!ux7Q44nCk(&a4;}}qm!0^XS%;N@ZZX8( z$;s*Z%;gk8j{AFjv^8t<~TEUYn|mVtor$PEKw|OjWSf3mHKa zAD4#={YW>>l5bNqdoa>u5U$W?hxi;oR8V(D1;zS-bIa^rj(YZG7QEd8dWLv>dZgw^ z_oD)1q-!Qz+Zsb?yEJ)uz`C<*nU;6j(;2_-j}D5b=q6jHtixB3%DUKPZg8{)k1FX> zm7-zDjbGv@WodbU*zS=9b=X!#Ona(ETgZB&X%~TKn_JfY!;~t<48#;hPZWl>;xq_8 zdXbr(&X{?z6(sg7(L9IVkk8kjexVIVrB8FEWD1t^!{k{SwO#;*6ZPjW(`u&wk-|x~ zS{vI-D|cF=plhVcneb|Mb@W71R&4Wk5^C)<_!$QEQb>stzAhsTsM}Q}RxU-523JsS zLB&{$=P9q`vdG~6l%SX+m{yOfYLe$rZf-6%bY+AqhrdV1V(su7)QtaalpC5tq1f0$ zUi9OEYX)BYERrOQW1yS$P1Jg6M z`@m)DE=t9Z#G(}82&~ld#L_I2$HW+jb?zbocnDL8e49}<{ z<+iPN=Rah_)sosjp|{>WS_Esgh{mh}*4o z2`S)jxG@(V-nyB)G-W^4_$2^2L!S2Awx0j@U``0INzjfiFKhKAQ)b0PK)B zv!yX{o&`|QjGSHlwJNYdG6k0Hl18jFvRq&XEeyFXevCh1ky-gc=KacKkxR%%SajNM zYGPZSM5G-FNmAKN5)d@&s*&Y^AUWEXzu zmA8g@V(q0-9a)#+H+D*uGG53c`ZC;MvD7&0P&k#R`^RXdWZfY1qa zuG%m!lIXu4v3AvOSCptxt#bG1!14(VymFddxzZTluViut)_XVbQS^Y>ko(+;xHSav zE(?6D&DOibX|G~Rz!6+YsPfbU$Go2n*EV(ZTJ zd$|#x^$ytYdE7(v2HC&meO|_P%Z_c$PmY34lE;R9NKw0T1JFJUW{#Fm1IpRCl~}X> zR9^RRlUP_*TN-r(W0{SOZrbkO=ldo3@`fuTCb=FiX>|qOb`jf2i)$xbvxs?+W8muj z>R36%Kd`c}y1r5;(fto8_ZsM`{JIFW$)d^G7*{@P)Avq`GBYqdex!{Xmde}!hlSHF zaBRG6vqC>Trn_#lc_9HG)4%X`)Te4G0>qP?vYPy_P{bXV!$ZE)n$q&L*7;CVfb`y- zoE;5@CT+}Wg)642{dn;*i$C(KMVBENc>3UG)J!zkX9kZ9L!1TzwSv z_a+jeCqFfw)M_1{118sotKEp})Hkxy)Io$CUd^@)`0 zMErF&zO)+aC&|g_${MMpFM+#vNgElBxgF`+;W8TuZyuBXB{qN z09y>Dp44||URRKbGAEJlUk`wJFS*0Kpb6S1bg*qyW_0_SMj`JKAw*ci|E$h$ofCWf z%-rH)Ye-+FoCEPRIky6ZqQ#}AraE0A6jxMKfRsTki~2&#*4wB>n1dY^$yA01=B4zU ze*&b?Qz9!E(6Lqo;|;uOwa{CsTFA=1-vSc#1tVk`8J<51NB55ZpoCrZd&ZFRicQ`Y zF~5DAWZ)hVt#2bP=+o2xv@v`o@y|s7U}4Wk(pVKZgH32~R{29q)@Y^P7HjBm(lPEE zYBr=Ghr&g{b)o8LAy7J?|3sOGEdbH}1y!kaz5g&>k&lVI`8bmDtyE118r%gQ*>9_(E(qiLg!RjxVC+FY}wdCk;0h1EiALA%QgiJ&??Moe(lB(c$rgoM?~?h}ZWyUG`zBzVwEk~}D`^71*_uZ_yG2=5|HwhD9H*1sN{HMj$7bNBdNdu~64(;l2p zYn%#C+?*iKh$Zkjnb&QPIKNs}81AJWraGCiDk@+%co0pNh4`OuQTlpYJ$f_Wv{B&| zQ5Hxo#P|#$vg>22*=-r9UUnhu_HGs1RKh7itWAH~xM8kSj1!eY5dwaA+kGUzu+a z|7K;=E(I{$EN=zw@;}9O-{vF!LSYXDqQoaSs~}GAU4FchIeBh&K^Wre``7#I2UoMk z2s<+vELnJ;d|)+s?x3oC&jmt-GY_Y|<>n4m?c*(*qSlEJX;gRw5*E||Jh{yq$9y&%R_`H)GVlFyWrt`AQhf-4#w~C!oD{o z??H(f@lUN{^t^P`zL#yVw-*LaE_YhYhtZfn0AV-|eal-13Zd8bclvvm z&v{#4!A~>$RpcNxuh;!x-Mi0;64yH+SVKP=)V+tTNK58jev|j+u({Bjf^F3$kH8-P zQ}s)gwp4+f$<;~JRr-;-)Nzl)Ff$roOJ{^<=BNH|TPc1objG=AuMhAW1N^k4kXE#J z*BH`TSDTc8`Yo}EN5xpvbCzYmDr*PbieJJ*wvI6NhxC!$&A#MJAgXgwFuKy04)O0U zo}X0#)swQQrPzkCifl}lKEN-r>R*)Mi3hpG@}=0pJ7nV?jxGG1n-L@Jnm!zK{L)|1 zhl6>9YQpuClc$Q*^bZ$(n?_r%kw3SOIbAA6!A&28;8fW=3J&qb_AEtfeBlKH(*NWU z|1e22DX~TDD_^gdiT%ieLS#O7L-Yf?SvPw5#1(FVpqZI1(~f@SH*c^0eEY01JR>AO z7|WM@v@TUTjAx6dp~4K148Cdd9mtYgQFN>NHIl6j!Jbym13 zc2T}}67x+RG%JH5ZK<_@@9pO=Z>o3y>CSX{IiLUB?q=^WMZ#rGq?A}D`Ow#JM*>cr zi4z(+PtvOXJoNHFZ~~nds>G$(sInZrwJl3_cZ3T%# z%X(53)b%wl{{DorS%Ut76=;PznrjrR^-g2m_=|4YKCRolW*-gxzq~AdB)Q-?#n?z%c`}bJ5{a3NQCYDN_P3(A<)_{&86`6~m{**ia z{Rnei7kZ9J$B4h^=5zx&W;l54Q;GP_HF`~X`65x;EK5@h#bzmCel)Ws7)Q`Rm$kf} zG){MDt72EN5jt-4gwO>DE3}^Tyussq_pjrNewG^r=fIB%MTIL|9LmExc6wfDc=>YG z#7@Tke7z2~xaWu}IInJ8KeIqn_FQ2PS&(3V-z`$2TQuIUHZmgf0(w zngty)@%dz*^4n!&WiDX5n6qG1xY~1>A(rq|0u(yAxan1d#;i zMl`Cd%%cXJZgC2*u}Gvs#-I#xzee?_8mOitp{>wq%=6FMQSF^@P43#7!aKx2exJNVVuICx$t(pGvwLQMoW09nC_OSo4m}y zwfx(7=mkfG)6Lc;{Uzp18g3t-umbqCGj_BCcRX=YR%2$3)|t-4#Y=go460%`CeC_g z?BM2f(sobRW!pA<$f}4e#K>K@^-4}Z%86cMsk3d6u`E{vcHB%7&`Ann?mpUfED6Av zKB>zr?3ED~4D2#mJ>mw7K}5JlR8r;po5u&$9LAe%lJd_^ai_eQ75RByJ(#G-RaZCd zRrko9Xs#~Ta z(t2?x^ez0o;I_!~&?D$bF&V>=-p0sD)V`dZFWwE#acwE-;Y>kt(d&e;XI`S!FCflH zp{hjO#j9-hJPz}t1kt@eH@Iq!P}fwJsyO>Xpr+vd`Q}cu^AqdJ*JdC;e_}k@pl7LHYB|l1#t}$e6E5W-+`S(rA!^1cVXP$g2^j* z^HCC?-1EnU7_13HSC9r?| z-L~!dzE@`e%JH963aAs$SHVAI*S$KOk9RF@YW0qcZaiRnOd95pVDpsMwdNGWyEQjC z1C*1qV#uq}ewmZVB*fXWLK-nkN-|~>y`wcCl1zvi*i zQd+9r9~9a-l{1rWB&}{~k7HHffM?gQ#QhquHs(HJ4o^NT_l3w^nIF7cT4H1>IfDrC z=X@H}>yB|-|NI7$8S`4lp~5Gwj|be%lIBgE;tJyKqO^=>OfrOeopoQL^c8Yu+}>O1>C*0&X{Ym@RfW<$Pg#Rb%kL1b4+~dSrTkrWK-n8vcZ0M~F!pD|xT`weSzMM` zv{zHpE7cybNM!gVI=X!W(S_(kC#ls?hH@D6#$tha{lrw3bv?jlN}+eSN%(BCb)t&K zh)Pz@@LO$VZSIRa`oEfecx=1Q9$?~du*U16dq}DCAEZRfk4SR9d92HkKdgfHD)7O6 z9|I6AUlL<4C@v{u3N}2H8kKNB@({QAgXZd4H4x|&CW>`BXW_cTghi=G>|+}+&mSx< z;OLuHrA+k%Ng;hxU`=As_$9>j9eR$I`|{U_f&7kB?A$6Uk_ds(T2Vd$ZB)iWy(i}x z>RdiPRt!yfYhLXDU7wzU`1#STD8y>fEFbfENDG|Cnvuvrg{zYz_lE7p+s)m@$7>3I zv7sfA8zj_c*PdOkn3sdFDxrYZ0$QTuv-KOpdFhxzsN8aCqQrqMdIj>vNMqS6QK+aPI{l0=vDp&Q)bSX>CVw}UvRG= zqeBPlv9qmR1|kL8jq3NmvI@P`Tv+xy1qnPwa!c{Mikv1&JgbUza7~A%nDAievtnn1 zG{E^;OG|_V>4Htav0H?bPA*op7fWQa7ZIM&X2xYUUuWw{hW<_iqRoo){qoeVGK?7X z-Nl%Eex^;0XieSbM}_^sdmZDPo%ir5;kk_?)2hiH%Gj+o$=(OeBad>4%s8sVnom+B z&uzKlq~E1}f`6fm=;tTREr+Hc<3n15bh9FtSEj^<*=V`pZN6I&yoyaZ(Kl~Gd1ZA! z$*d(8s0*wJe0!J^S6|B-E62R+P%58BCgbG+Lk@DbRab2A14LHHd-jQa569bj@0GsX zinOyEfsBs`;|WH%X%L&1N>A?)_(ays|0|N{nmBPs$gS_JzrQbO`pDAxWP)vVz|!f` zDgX=ozV4du&UAD@8&=uy>256+RkT~^A>*?7vMCa+J?L%#xO%SsH&na96IW{1$E-gZ zJ-l6)IS|b!wZG6)#IbsKULIR$@3pkQLr8PB8`&p+JKllE!@IKYji)U*+ryr865YCh zrr7}7?JqP`w46F1)8DGNjjku`tNL1UM*^}j=2^h<3)gY+4_&%2WVdTEa`8!VSmLBW zfGJRS#BK^UFbqjiP=}tFAF?I2ogmY}-D}8BD*cKm_eINi*l(0(#jQRpC&?{(piOa5 zfCvYXU)-`gxa=6Tgm6;gTCm?;fPRyROvuzgR!?9GhnN;Qoo|~aUP@#DetdPHq~!)S z_PNkxcY0V>kj6lK_ReR`Eu3TC8cLp-y;#}RXh7@l5#8v!OUQD;1S8&i8UwURPOEHR z0z3^y5*H><6VGWU7y%mo?!59VO^ei`XBX8wTJZSyu+_PTJWnlvf6AG8xfXQ7v^N$! zH5Cw5agLI~rFet&a;t_2is!oN2x)r@UrBsC;IU9FDde(gE!-Eqdb^G(ckk-MiQ|4o z6->w1+G#(wa}#y@hrV6GyA}*N;=P8?lBR{aatpdZf?ASXHv3+IaM5t`c>^NrZn!*v=`+l=b2d%aVS z++38~-23|-+rvDZe%Dtbf7$s(P8!eGk9T8>EV#|ujyV_tmW(L48C8M9Y zudA_nOxA(Ic%hiWo)Nn~aI)J4a}PwAx&lhme5Z7sA)TDuypQ63{8(V-2o@f1K_S1` zTCQYc-ZqU`^^fqDdSrX`4H`HE$@h({cs}oH2y;?dK$2X)bDmPgs=r;r!`yuK687dU zU%rIbS2FSi;{z&{+!@kcFW&SxC9cgujW)!1rvF7M=}7RZ@AlE4H&Mfl$swurdaE zE(}a-#l?RagdDYMarB=??<7?tjA7?ne5#4c;x<#0UUa(_qiWa`Ig|I2va1-?9RNxv4?WV?wfdc3A=>9054Q*WQ1 ze{S^>bnaWxCF^Sk#i^R}y(vk5SAq|9haVC&E-fd5tMBxcyMA)$(deUmRQ;o^DAHin zq24y_3VnnTMsp)G*!6>IUY6PY=h7YTI=}lrHsgAfE~#Q%FMpEtd5{#qE@V!l_h!}TMS5-9}(C4nO{>}o3}9`0M` zQO9KOM3*XD5PT)D`8T9Zgalg5k1BdBr3WP6)VKw+?Oi<`C-)C?{J`hu?1pOh^M?~_ zrIb@jpMyX%UnorEV70va`bf}^2G@%o+qpM`2?KT!g=0Q}dtbKmA~@K09!G}UM)u~My|&kIMa2z5|8Yr7gREMOvq$~8SaVrJkfd$j zP|IJwbLzSOaU9VL;oQ?cO<&ydLA=M=AFdsG>^`>KF7CuIdJFikg|ubVP6i*+!Ju7x z28;Jnv~xab{PFrn;TSv~|B6hZ_&GL)Ea}X8rM4=nDplP5P^Zuh&l_-XTzFxgs|Ov_ zZ>S%EuD!*NX!^m{t%La^dnrVgcrLXrtR8b-(hK?f9AhLwe9*#K_9&eY?h5YP^@E2W zFMO66TQ znzdwca36GTV*x?qW8$3pj)z6P&6%vS*rL&2R>xF;I)D$hW-AapXZcSF->Wyv;3k^z zH%3cvJH~Y5d8{PqD*jgh){z~Hi#|Tb0d$P(hZG$I&cwCukMFf(E(6H?ON~K=ay~2G zCX=cizQ9V;f}#(`Y__|eusyfPH8WN9`Y@x2(zCg+e>+?1ia@l*J^v!i@S%8io=HTj zBe|gUETxHy_;uWQ=CJd@7YrMO%6HkV&svnWG~Pp(n_te^oXBwbz3+JYu?HZjnd6`j zdL1P;ILF=DsEUmGTs&V|(GzUamOWU1MM>i5(R0sfw_)qHi%+5|ijru+iYaA>t?loV z-?qy~fwp6L-1=WD_2^f!i%*joIp#sj+1;IHQuvG)6k-x`X~uIYq)NDhX{<;E34zIBK|UG2o{6x!U|48m^<8IYY%vkC=&e3rQyLP~Y;1 zpXrliOhj<4n@5H^zz-zFK5kn=|@hJqJ&vvC>Gg(`s3Z1t1SDK1xuB2 zF+U>9hE%)|7PGax>XeNVEfi!kDR8yjSt7*_vUv-ypPEHJntgRVj=RN)B>BET*4REs z_i&~7wzjq#rp>J5?wBqY@dIy(L(9uYqXallWMGH;rCtt{;;%~MVGu3Od;^$v!&;8) z;C;+dt?^6?qs!nJkE=MrXkJJQ6g;*9-NmCrZIXrcd^#HOKDG&+eOR=%N`E#B6}fkv zdCsumZi|!E#b!aXP2mgEWr}jDq6DFBW2T_E%q@ z9-%Za!XMYSaTSUfv{jie)MOK3EGI#cFG)_T6hBbrAll(i%CUp$V=TCd{%PWH2=Ln^ z`@{rP$5mQV&yECr1i0DKgZj$nKs(W$;t?T^8APex;RSw2&jbw7q+4L075v`KJ=f4X zc{1?O(guoHA2OI(}fcDw@b4FF`YpTBRK^I_v_T^ossla#epdCQ%(m9>lKDjw1)`1;uh{(ZCQO6jPHXl6W#G^A@^L)awF(`# z(D`Ew^VRNkz7`Ju$mqgUZYS2C>&-(yT0BezU@`8-5`r}9)r^&2TukG3@xPjLe_wCD zp3w6T=N>*OL5j*89y42RF4aYB3-hOiHNF@r95j4l6uB46HORkzo)2oL)x*UL!@jCS zLb)fh$exAz1!0gX>kAn>*sIf=@2Hu8yH+pFqvZSx|0u&HhtuDQt{ zVYI4VD}U$KcieG0Qf$xYvJ>zDRZB0GI%+=4^)7*`^XkVYa|51LByGG3ttwStTpxW$oXMt*> z({8C?jILmPRZ|PBX3uFKQ?XcXg~q!3U~2v+m|Dt@_z9)rk$gvt%KWYtpEpygX)d;2 zeh3yjef|KydKNe_vB$vZZ@q6mJb!0jd&Si65iv!}6&K^m>c+o=DMp zV{UTuJ-l7A{IJ=`?Jb+C+Ak^e6bcEG!HiSfAiUWKii9m4^cr{_9)*t7bF8`5|EArv zL9>@emb|Q;6m)cjkRGY&=2ViAx1>0?n~&<83Rejv*snv)q2!>l2*q09Ldm+@P@`uZ zs}( zLn+~u0~Om3X2<)xB;VEdkZ6U=v55p*SJ;OO)CgN{I4+iHV5N1nzTR_)r%jW!8373* zWP;fUY{q^oZEBls2^r+=%U{V5LsbKoUL56j?xW^?x6k(qy_Lu^ny#!Z0FB$u-l~Dz zY8z|do5g2T;VUSW`OMmzEIcGSKr(@_Fw8}41=2GVF|G2+dbEkMpqGY>?yc2zn-s}j z*l%qSVE-7u6%m*(T)SigwJ=Z~VOfy7gS5(@ z`7&50TT&2sTOfKGBfnCq8j@2qshuJed{W|seTyd?!2DgMmQ0sG$v0fQKQ1i%18q(HSIx7opwjSC`R(1}|d@Q_> zIy@?z&RE_(wUbad?}}B$d{<2rd*jvk2^NCwm^TGHVtjZ~*D~B7HifE77sFZvXK18m zrX^}?PrjGC56C;|8g?92K_~*h9>5}Rocv1^wXA85epRzIQoL5(Ip^i{E8NxQIi(Ej zxQKiR`_&B>4wQ|8^FL|s(+1y^yx8OM0sPVG!oVes?{HBD1>sP=IlS496m1CTn$e1E zQ%3B}W$rewmIVa7Y))w^%MVP%U`Qo-jt9pND*8oe2AxK7Z!&s!B63nPF~wBQV}Kjd zjkiY=h%esL66U~O@d=xsMF$td5SvX)zl*1wa!d$N4Ut3lJBAN9u%t-Ui?kpq54l|t zq1^yf!8CP3m{slG)|%T{+fQvRNbxuVfpxHl0-4UTR&Ic%*bnJ+s!QO&@b&5{!u7%i zx0S{5Y*LzTT07lLTO~w5l%@Y_WYN7V?49dn-~)$x&uK_w=*P9E_SM(Tycb3E+Ve2l z_og;n)L8?IUi|`$Y#|*y$QeIAQMNdasi|&XSe^vOK5%${G~Km^VHfa^>aT#!(g5)t zR1O799Wz|?r>7xH8t0t^4Wje*tN}7AsN3P(S+|`MB^LL=erq=~StwL$?EYocH+|*} zCnUefLaNpfte_WNu1X@vr__w5z-GTEv`Th)wR^qrbrKW5AMA=ncm9}ZAd$s851!ca zne+abhVELssxI6xj7+2_z-C>kV=@`xV@Fz;0TO-=lyFd^Fmye2FB5-*N~laY>KoX# z8UBy^wDNe*3EjnsY~n(}VSX)~T||}D(WaOEx?8fp`p3ty0N~_6eI-l*QhQdKjC}+m zKJDxB6CADv-2A}=nbJ9hhxp=3&J4)A$)PtziPvWWcEUB6x)bs=Plb?_sbNoJvb@ks zZ??tZ4uUnMtV9jTh0-$vCUvd2n@VuwdWDq^0yX7kBrgQzX`E*huDivA-`kB3wl`|z zPddG(1n4~#sbjT=7_!6)&cZoZS4htAv`loz!aJMDkoZm7y$>fk(4OU)eAT)187kV+ z{TUb0*3b3J_zbu{&iDlA3+Kpi`+M}Sc8&O4hIqHR2ykq6r=BU_h&vk1cZh$m^RROt zOupdh36LD)+}&NVZMl}*N}bBdFYqDeUmg5@zW20X>yA5ZV)O7ztoS$5_NYNWo8%sN zg2HXTS8JzQvg%Qq5BFfJw7+*Hmmo^r&|te3jq@W)gY$*av-zf>Cvt%K4F~fRe5Oryx+ef0= z(wi>XSxCQshB&i>-wqW$^ZnCQJCDnI>JeM|L${&8AA%CN3u^h2_@$`4F(AtD=3bF~ z+@AD+8ZnH%=+Y=AT?^)!U}gsLL}J@AX7aVjsrv|9>=`7ug2ImHe|QN_8b&MzqAu#q zf3EkPbmI#`qE#sPbtkB@#uk`EsgA9whu>T0TUkEOSRf+)G~~-?%*c^+bXLMWVM%mX?k`+#<@f+cIzS zDiIq^jR(7x&pC5XHjsT8GAdnZO<&&lQMyEEHS1Ni>TM7|@StAz(#U~k@Vk!Bc7v?P zomm5}kN)(S0uP8xfl_;<&f_^C?fXU0ifQ(zPppjxbcdq;-?9G_9g$-Ib$7?e)iH2i z7)Y~;exCy&7GI|PyXE;gT=7@pT>eD-GBUd>(TLfoJXNprl{r(bs#(tnRbn0QQvOvA n{x8Qce?a>GWW1U>=MHbPUrbkovTgi6`U996Aud!HILH1ATf{F^#1*8h0hfX3E6lsGZ(t@HCLCVle z0w_)C1PBnC^cs3i2=~YQ-{5<{-}~X-C2NI1!Z~}NeRg@Cy~B%}NNx7R@WUVwi2cTO z&D$Ul1OozrU$8I%ufWee_6DB79=ElxfO1*|W`JK_5OaZl7KPUKDW9 z)V~8fLx9KrR~_&;`=94p5Qs-HQUmq|c!u53)VSjVo*!&+F`M|K-c1aTWsC9y<8iI- z%&+3yPrROMe9rpUN6c2E;?X;g1GxE_LT{bYszZ*C*r2O;b97<0pSD!&aQL9;;?B-d zuc19UZt8xY_k79F$`LS(3jz9n{hRmS)k8x=WWyZOG8GHqX41lTf0f_*tp4hv_Nsi@ zg%J?*z1ixH-1{Z!xWx?`ZclzM$k%2R`K*jD90XyZ@nbKKOSO*8(Zs`EBQi! zy(*C-P102~vcTG63kh4TuD-Nf^BmYtkXg%{aOt15^?>zZZUhK>?P#g@LcjW?dJUb5 zhP0#y1X2GKR#^fxZS}IWnQ830_6*PW6xcBFXk5rF&ckxIVP)zC6SHD9Hq6b^X11}1 zn7FPCVG+qY3-Rc!lCx;IvS)QgSX*e0rv>PpP9mR zzWOYTYx=q+3bp9`kVtqWu^Su2A<>MDZV^=e{*D_VqG@SPmofoKV)o6(J5@b#ll^!I z2qMVZ{C*ERVqv=E4=>0|ml+Zr5;buh35iG=Z)OqUI(6ZB|AHhe;ZVclZ@>{o0+?N% zJ60e6SClz@LlTqhvhQFhBXJDTf@LVjGHT2<_JoI7G0Ho|TKuvcgyjj#M`(-6 znIC{QDU*l{rdJvuYy=GECK>AX^#xSmx^jDdOd>xRb_LdnwM{-c0b*9X=^?_9{}gRQv`DWYHv(<4@iuA?C4P7crc({@@Q zEEm=@RH7(TtyZT4M=xe7#9oob>?{Azg|OuwZF~x+kC&h z?|1P2&V9d2$M4ed|8?a>;m-inpnIn0iwTj>B0y%a%){ zHIl%-gbZkt!sMFc<0B#?^%e^AhT4zi1qLSj zs=_zvWEbcS7SNxlUqP==Emj*A8KRsx^zE9YKsrXC z;O&XGGY!JQiG)2mb!KFw`snl==n|bdN^eq^VL%0bb2V>oFj-;oj09%Pplys;gA1l_ ze@{>0N-&wI3}t)34N@qcN6=yqbIPs(U-z+W}BEIas=k zz@~PfYrC}QG|5%i+ZlMzJ$PoZf^oSLsvtaJ@Xr}DQ;>xPgp-4VHgBn}>?5PDT*{yY zMtR>v<^qEa=vbVqBn;la z`8E$EBrL4|uZyY$C=OPjQRTsV^b=<4w54yJK0b=!7W#|NhBh^A z!p|N!5$j)5y+N0yAAkjP$VL#0N*@_PK|%boJRSd5+9Fv3lddz;roN{VxZZ6@T%RNH zE#C>9BcoNlI2l(Fby(J;$HJIw3aX;-%*BYKt+5puP7;4xzZVcjsoWBn8e85`HSbiV zFhuGcR?dA`(&S}wWTeQ6l%|ZP=ne<0wycfRgd8aYBJHB8@5*?vK2HP0XRMz6NJ=jI zE2RT|qeF6$Hq$8&CL4p8L-Jt}+k9SwmAOvwLpkHc+LDq)$o5)8WYqD7Y}fy zeeTA_29kdC#UWQb!Mso|Vata>N_sWzx8qcGh>+e@f`1i?LO}nAIe~xT%a$nhJ&?vv zF0H7Y%7X=-nC-2=SjZ7eoc}^#QW@#M52EZIS3>QMh`d$uNmj9D#K_+dYqW99Aa{o^E~q)vgZ=O2y{jNRtbvpg{AUBp2mKFR8%Fbn2I3$J{B_2RU$~iIr+r#m9?~S}6afegp*C+q2cGyaxiE zJhk5sTSy{%clE?R+tjP7rpRm@-v#Ze1-`x1YgpFeG(XhFU7h$iT&5PGsKk0Y5pvv> zg%yhlkzsm-%$hT_>xr5;cejjVCD9mHfA)veo5D20Wjq~sMsfxf>_G?slG+PCHnCe! zW=-pk2-TpqRq4T10e}ZZ7 zsHqwYCxk0h7t`wJp5#T5kim4_rUXM{)aZ@>JGdH%FOXG%P=?X5^CsUOG}HDR-W$93(bYY z?k3Gblc+~=FMd*+3{0y8?C)rpI<2)G>N(? z&voAl$8f%E;8|JrNYiq_) z_)GKiqq|zkB`D(8uMnmvYIwvQXzN7Ck_ZUf2opO)pJx`G=>vUMlb218R)1IZKyM_^ zYp{tnv$l-)-|UPQ)z&(?_kcXlZZiY)l%rYB)`=6Sg564Bs{} zH!)x^%1WV*O zp6+2~Qv1ae%FUKCn)I5rmUe4zVh2~>cA#xqheLjw%2Sz_;5&g4P7s-3-yR=gpoxw1 zNpBWJ^<`|D^2L6qTvshw%vcg40W0(CGe`e=_`E#b^R z#azlTk)EiyVT@TIFJwDbf|==SP;v@?Y>k>PZOWvk=8@qf%`Fu5M*$q;`rt@gM( zL1pfqbn}LDajW}IMFhhzQ3iHD@{xuaq9>{~#FhriJmRWa$NA~c;vbGM^uTc7`#A6| zm8mDHm3X#j+pErzXzTIFssu55tfH^R+<3&=HS|&{C6CJNaj<161Pz)56`s14YQnHzRT{=jXr?s+TsW zJ5n8NZPPkPSST}7YpY;4?Y`;*NJ7?m>*TRtn+ho3jqp_(HB-O{s|8#K%Ddiv{v+j> zIjwmCsJXDT)F`giyiABh>r<1#5;H}|ny7ETGbDnNBu*)0!q1*S3@Y9ib9HjcT7F9* zp@Fny^;K)VSL`AEQB@p*9+b_Swk*Ujg(W>)_LUmUtY8LUwC#Ru;ZE+hh( zqb@wYsYuab)sC7YhmDtiG(4u-Ru$&9LSguuWn$|KXYN9G_Gxq9bbXu@k~+Inh454qWvQ3Qj%nHm)}`%`>D#C!5=;ZhnH7-EA7q{ybd;akj36}f$w%q4AGj7mcZHkBT`wmSYxG}PS0nTc%XnD8 zE$DU^=J%%mCZFFn{q0h}BkFfT`9GFVv3RZ+owrh-fF{eQhDhObi=gc@3&U0Fe@5_# zBR>MXH*Km7m!7H}$&0%mFdRg6&Tl~v2bL^&n6&w;eYl?U-An3M#!mSj;R%$p82}$= zmNz#yA4{Xqcd3JS)#+Pf3aR3$851On;K2>wm}MeweF!{-DLxx~0O0k!ZQ=NWYg#v} zaF;#Az8^mq;W5?vDN?54&v?$6zSqx!&GQn9!@8#g~SVP!u z7Q3}fW?+FZ+Yx!L5~foJu5^M&<8j;{@Anb?(VNsDn3h=Br#^_af9mkZ0Y_F zTK)HaT}1r+g$Di`-$17*dOhcyZ=r;KmEGz><;yMe-RnVq`!M1-IAC|jYqLN*Qpigi zIyE&_ffH8p%%GN83Dkoe74pR*?LUO}_YMq5Y@{2Mbnmh&QTqD&TqN+LJx~51KhGH? zE(6Uc)OWGMUL}8Nk9M!f9ol3|LY=phlan`7DLHLpbDd;?Cg<%gMaaBoTFJy7U{NA( z3^83F-J+K(Y||;h#4lv>xdh8^1Bw(>j-}I9^~nJZ6>L9U*xs<241Va)4Kt~~8)H}~ zAuWwoFIkW8eUPu}zmZ*G{w&|+axgt$v!YmfXq7t{DBK6cL)XOS;`_0#OoO_)?kvNn z!`s_axC-1GJ8Fa@NPcz$U}ILpCMG5`Ki-_LQ#~{Va6JHsbbjQKj5jltkKK*1h>@8c zjn$AqWkqXC;?x4q6`#)~N?1w4Z@j)$bD*|fs@i&1W{P288k!3g92Am0YXo6v=f zUuV=iT$kbm(w4`RxD1|Sd)+*2Xc5>gZ{+>xIj1lszWSC}3foI^f5&t(Z&GJbg2{Oy z<);ISVm-|em*++%f=fs>@w@-U*Sc@97vMCs9FIXWxV6IP9k%JzMRc5cn2spc_~I4u ztM)j~RkgD&&SQ=~mvNf`l=lV`yIsKbs`pcenLc+CN0!7#z-{;aA#@BWekzoHSikqhDYtFCy*5 z=D#ZWY_CjwwQ)H5ELqxg^BkdfTRRn7ad}9?&2aN>(tz8~uTT3oE?`)Kik@vH#ouJt zWH3Mb+xATSnYY+dkVO>ld}6^jA!EeID z*>W#;i>Ewvq4Mpm@K6S4Z2#yQ7yb9;*=`DO5^8?5g6hK6v@8-~zmMKUFz@CsE4Rbx z8dZ_M_3rN8Gc@$4ko#jax=s=8+@{xZC3lnOZv`3uNFmns@GdSK3t0Kfyh;9mZKe$L z=~Aa0_z`AAyGSd86BFs4(}j61)sN=Z6Gvv<;%kUrPw=`UKYsl6^XJ9p=pduB& zHTwp?qRq7#qB~FB$JijzXWd&{sum##3OULDS4uwIc#%CN;;JYXu5tc^M%g*Nuk8hX z54-#XbCEZiV2-ETg?`@KO-7!q3fTTf`A52S{^InqyRprRU-;6DKm2LoMCT`+L1$-S z*%xq!*KS3JpuH|`B?GI-WNJ6!fHnpR>aVrg+1Ua8k}DQh@2RR)*yir|u5SiXH~yf` z+a1dq7M?)!ch6p*I7@wS;?*H}u8LnSDZ-V1=rJu?-7y9K%hf>3_PIV$Chj`ywK=~E z42$L?tVr;9B-|eLD-;ka{pW?oV+U?S^PLW85(vU=BGM?loyyd2@+-k}MQ*%gE<01w zg_wuCGRQgxQOnD+qD{}hZuA@+30#|sAJuUAF8P07RSYw>w<%GsscSh=8J!cl0Q9WLR!*M-`(HSFHx9Sbt}zlqZx#~m<|gwc zJNsi%QPCPuQa?@rg~GwwI(3WIn{OQ#DqV8q>%f3%&5gZ8MK`MxxN$vl!z16koD1&(e0K#VhuBPqn|(L-Y@LX&F%E~dHDP;P{D4bV!fQ3V6(=u zlI6%eN<~?AmYlEGT>NMVSOD3T@Pm1ww(U8CqGHoDucZ4q0~L~X^BIMVsw&d!1T2bv zl*+BSfcEk#y6|>!xN3iFcO3vH^V@-fbHI6tfW3*Rs@;3@`UMU}oJsLPn-sHshQ2>a zh`7OvS9Cb_%yvQzD8RiN!1SSx0E{z~+D9BG3y|n6N#~NXvipyyM1A#jLH;lM%1Lb8 z>MwL&587J#Ia;n8KJ@ZU>6}svfTJFtVY)#0d3GuRx2c9Z;N|hN;}8EXoVR_J!4}4r zU@j{>VdRBR(Y;=EP44Bx+8^ZUDHLHltyhyQq~epO{KIH4QtW*r=3Yt3a1km2Z#sCd z3iyEI=hC9^z$#h}e=GdZLP;Z6(C#`(xj$!Lovw`xXXAk%H2@Oxdq(^D?RjDEyY6uC zfd4nk?NPj7*+E3LzrNW!V-X$~PEKo1(V`YMN_>Cyoom+ov8<1+!o&7QoFgSl9Sn2aW%^W3_)V;hDf##+DLz8JE#wLF%5DVN~-^Rcse;-n-Bm1^_SLJrq7w^p!$ z5?iVXVJ7#G_FZ$VFf-1kzo?P64uALhyFBsB;scPl9q99V&7yC<7b6F?KS{CoY>o}% zlXj7lCpub8-U!QCIA3y00ppeK<0bh%7MK#F$mXPJhiLxK75CSH*%)zks_n?C%|g>z z2OIq`TTSv*H#!{V*x@k0lDVi9LqZLfI)4rn%!)1VFyVKr%Q^&&dwV0ZN4iR1YVViJ zOlNyJcJr!AWxr66zpN34?1&|wKT&PYqcdL-DWrO?I2V4sBJ#Z$su%q{kmTTK@;M#d zL~U3gzp-%fcSU?!jo_cEDLF-OV;csZxUDnX6#YPkZ>wdjTR^{(3<%0=1H)hkoq zXxWNI_L_RB4qmyVVM)P1HWBl7D_!1IUSq`$snIX(+6&^t`I#ae9qR?IlGlY z!f?48xp2X&fX@Ks{8QSJXSwW%$D&gLj4CLjFp)+ko@@#_3~b%ozqhzg61IXD0y`o1=a?QKCmSuSd7HRJ>u9 zJYF5Z9@c$sG3LK8zMfZ?!UwUCcBe^~Tt!bRclf!Py9!qnbne;S-aI^Cw6L=BPkekS zxX>hN+Lnm#|3cNB?20XS0#O%Iao>rX`x06T?AnYQi(<@=g&^@xH6WxGjoJ;yO?@LV z8i@#P-QswzV|tJB`19f|Wpopi%(AbMn)?=vZ4NtkEZo~!Xn58CQ5&=ndsgX_8Jhk5 ztC$>gm%Ibi# z2X`@5IJBCkxI+d#Wcrkh$#qqAt$R9n7; zzHWyO_g4ykrQJBUD|UDKPO;0?RKsnpu3g>a4T}<&LBf)>{q=nbK(fz-vsSO0T@9>|t5&a`W5(xS=RgmdExVo7bPybx1uu zg}%!)Q&q!WF%Nrn*{ATNf*ay73K*-q3d%}FUv4P`=8VPo7Hru-vP$CrJaL`Ba%IL< za0(#OB-M@CFSfI~Ln&VM9wpARr9VoRJ0$D};q~rm)+KY2&bK+3@{*o?%nW+$UA|r* za8M|TeXa6+KOHr7NR&5x?|4*^&AJI+V(!1r&#V`}YV}NOxVueOc;g-03)LKFIMdB% z29w#9k6c{5wFTG9v_u{$Yx~U@tLXN;JrX{V=_=Oq~y{K zvL1?N_|$2V`qz~<+}Kk3g+8^oH~Z0ZwYV01)};vEIs$AW&(ch#X)5Nbo;%<74hD(s zGauE-O%cX1%oiVA5xbJ^v0likj91h(jStPw%gb9ZE_+a%Fpl<=#9759B@N!4=M5<) zZcH=~`pO;fk;F7X)Zpnjhq{)a2Dv|$j?^v69i*P5=(J#w!|yd8jEep5hm% zkN+tEz(5Z<70eG_5(kYxNxTW|>#3dqb!vnH<48}4VDz@Y`|tPckKdX%6~3|it@=KD zfRLGCs4#?!1(5y3oEU=U9@A|eak|KgbT7yx_!CT*O@Wyf`g)TnkX!fs9K(PKR zDWWPCB5L=;^u5!`8R*$TKz0W(%~Aw3M!=LVt?Wj&&OATgs-&sQO2XcPb|L1R5P`Wn zBZ$8>G63xpSUg?6(uR{F>;-um8(HKLfDSEPm>tt~ymRN#h(o{;uBQ;WcY(?99%5=( zcZ$G;?Q!vCk6?Cr;_?pE>;%U^(F$8^I?el<;iS_Qr?A%_@l#F8H07JMMu^1QqcJ5Py;!z3LtYQ4} z9{}?Xk}x~1(xu%x9527iTuFHf^L)G0x@Wo9?YlfbGI#{^fmO~?qyT=?B2z6!JfQF< z*X7eJ1Z70>0_Y!t1SIY-{PdZ*mVafnITKcnRpza87ZwkmiwtfbJ$%?eggzQaw zy5qde_b8QGVXCYY%UB;Vcx@7>ADHKAuM8VGN_+o@$M58~j4aA80& m5#UA@@r|2n2%NzxVe;5C{?q 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 literal 0 HcmV?d00001 diff --git a/AntidoteTests/ReferenceImages_64/AntidoteTests.ChatIncomingFileCellSnapshotTest/testDoneWithImage_normal@2x.png b/AntidoteTests/ReferenceImages_64/AntidoteTests.ChatIncomingFileCellSnapshotTest/testDoneWithImage_normal@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..5ec428e031ceac04c2609afa1828c98ee7d43f2c GIT binary patch literal 20365 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%0D@0t%C@t=YO$#vy)5}cWu(E`+nU3b-Jd)jW zAlmZvJ-^amJO$Q}#)MDyW@`La{z&V47+V=0FiNqTf||5ci;sxrI8n-5CC0Y~_Vh35 zznF|hDKp8pI4}5lwIl3v7Z>H9m5H$4P1VZ7eYj%Aylj~8)or95#wixLMNA4we>Y~^CfSFIyYQ%e!JthH-GxWj6#TAMW&@$4OshBh8=y! z@==5MwNCB)n4dRdbn~K(O_!y#2r|s!E9MprfJsl%3e#74QGfj=Y|0>K(-Rn}aV@YN zp493)7t>zL9gcKypDGf8W#+Sd2Z9JC17tSAzSUo=HRRj5(yjjZMo@rEs~N zh{!xgg#@u@+Pf(!%nKv;mlzak`#!dLsC{GV>{rZ>0?ZEZ>r{yihc+R=o=E&JPE(NK z1~Z`P2;!!*wfIHAMLW6<{)~Oe^Q~MX^0@LnYlYN}D%!SQK+&iyT;w$DU)=$@ z?hOG5baT@fNRtB`=@Ud9>Dx*7`Jyr9@k!RTN9yql@DoX##}x{ej8RMc*WoOQi4wnE z<5@zNro&zGmg3Wj=5@g@#Ve-DfXjc+?;BEOKW_FR*&&kqR-gQ@$X zW(->p{FU~WQ~l8NJz3}x(M_{<@7m`eDC+^ze~31X7L!gDjtM0^wEn)(zc5Fl-AzzX z7AMF8v0Oa~sXX)!f8-#}K9Ew57|ci{2(aE^n;p`8r!otoaTZ}6Dw$@INN+K6^2WkQ z>R=qQn=;s7aEjmp-#N;w1FPc{013geNH97d_)XrPZ|Tw8r9(3AxZT1c*=nzGYo#hp zQkB%T3WQGq`6x!|)7FaON74#6GV!lf=MI`VHbYM$%%H^nqgdq?#}T;tjnaX9=IKX1 zzFKvxb{e3jlaPi{AdrD^jYVnJ{H_--0alF8L`d-b&c2_<#)XvahX}~@GZM&2(Tx3< z^e*Mzk%Y0)X-^rwA)_y2YdlTVzDAM81EE$knqF$FyU*EhJOi@!kU@~=+SuZ@7~YB$ zH@OZW{%)i98%(Z8WR}v1?%1FkO7|y+BftB=psg!!vNckGuesCaCfgog*vE1hz&nNPtfG)CB#^ z0VF&4C6?QA6d8Z#VE9sr$9KY0w@ik;_=w*ouWY6NOk+VDa%^dS&93((r}@+0q7>f(5ceIwGGmn=l6v0sKV3ZOB_ow&0iR_gJeL5n18np& z3(!tN8U8jGuqd!SaXe93`b~&G44FGWUlY?jS9Bzu0Pi;rnP;hm1-2UKFd}Vef6)6X z%=BCJx<}R8igSU9IHy=qO>#KqB9!lx-~GrN`UuVqSjA(;FL$wqWsXmLT|XXa9eQ2t zk@c)C=*2X$r}lj(*E+Tz(TAmaK%4K(PVI^8L1Vr-vyChnJ!)4ij3;6NZ#Z=2Aqqii zXl(U}cIlLa(`i8S#Fz(g5NZMAgmY}Nw->{s5(1M~-ZXG)NQq*kTxnWWZSnW{{klP^ zAe_6(Hh-+&`s)KOaAHcnyFRKZ#R8lu0Tfq>le2sToVe^xkOWQ%u0n>!cvmLZ`j-8C zMNYKC1r#Dr`uaTi%2@wQdqOVx?N^*j@o9YYWs&&4K2nR4Z0Cr;GN4;{bs9>P@INk*pXiy&=4cA2DjEbk$Ah2}R z`RA;mS%|3XRk^050JZH`ibmyKc0-M8F7QlD7a&g68{Gd>7+jOJ-UZlF!T4o5QHy%& zp=`SH{-rTa@p5JXRO$H4O%wI#xBvC%E0!g40P9*H^8wH9?JlV(CI$};#N3?doK-Em zYe9nene|uZH%JpBP9kxQFXN@?lJh)(Q=eSCdDVL#P=O#dVVV{=mHJNd9o9aj;pmQX z3+Y9TJjBB9O5QoXwTg_Ro5PUI+tj1f-|T0zg3Lu{r16mm7FShu6zb{x2e>8=^c$~I zUg0mI1c@P*8wQ<>dYFHLH5lxsHyGJ@i0K+fkLg|M8>=(#ZT8ZKxbw#-hHwHcu-=l0 z{I4f1x27|?-P`q1GJ^zY0N)>~$mB3z=5|FLSL?P`)kCkl9Vp}?OdFf z3L}ZMrEf0+5W>iakqik3;5-z?arGs9s)mkD4!6l8Xri{Sv)nl;nae*uwi*9U+vcvc zKs%sQaELqj1GGxchk`yb7qzGKcmV3}aBo>C7!%i|dh`=scX=>{fMna+QqsK9wfqd$ z*=jDSYx=zB>ch8Aw&oyi@XXWuCC5QdQ1mq{dudo~FmnZtXPHj_f&>~Kx zvBuf)aHB-#Mg}WJ9Gv{C6OfQs{q=$a##SK-_72HM5S1?+$k9%^nL4`ibHM2Kz zl@l<^Ma`lBWB53sbmHc0?(^&HU?D?RzXz(4$7nM z_U~l>&~X}t^RfS_0MfB1_kaO8Q>$~}c+tkpW!w#VC6A3k9>*POj`WVZ&i|$ze-K3hIiV?Y(_9NxTci#fj0)VIi)&;D@_WCfA8Wij5n zb5IH8zSdfyNgn=Fo#~i*HE>c9up@S2WZyPhDR9_J_|R7Gw>gk-%M*5g8*#g%+(fNE zH_f(2%oUW71k9V~jWUCG7TNv$f{a6>42age1HIiT~s9iSIduQo-{DD0l*kzD7J#CrLVc zDxnYYR+|vlZMi9&stL<^9}j8&j27|P^J;buiuR_GWBk60`}K(Z_dtBAtUvv14Od8< zyzG1z;*%0vzP_wNgf_q!Xvw!{kt`GZYb$b_({l(G|D&UL1`$_GK z<9#tgB1ACFL1n{mxjXSD;N^k=Q%fcJgjcGvc9pk^W3jq7F+&3Cq)y^TM?Vyy%;eC( zNZPzW?&_WG{1{MM@MS7kaLN9d`=?w5KSqwmn`*&pWdTgeF*!ON9;!#{_C#r!11I7P&EETB=*$4|pLh^yD(u;B7@4 zMnas$q0)K!R#lRuH=sI%sBcr(Ii6OgjgkZG1uh*ay#8$c5;Z76whzDphJ26qTXtgXwG(Cr|6c z+K1F+nn>&%T{U=V^-1kWB#kp@V`tnqvC=LnAcbEye%xLP7wiLQ{OH%VkpgJdP`vo> zk9n$iS$Lzq>e`1oP!hqq^uxOR`WnZsa`PGPrAy-f+W=wGt+`{YU!5hEk5m1=$~l5$ zSHAf^oAXt5FzH%B_cT`8CKyQDfu|L_G=M)=vRz{5m*Pj8-kg@93l?V%09zZ6A}*2*f11FPK0W z%!aOylMgY3BmSTr&8cEHEQg%w$u1Fcz%<5N7Gfc;2!tO zgg#qF4r{{xLcLbGEn3^FCrzm)v9BXW)}BpNfBFJz=@)wQwcY_eii%~gI3{&o zrJ&;jbpD`JOM@uw2kYl09M{Lq98#7HQQBMGODaIB1y8N>*Q@g%M)p8*^NVWq6{0;n0{^t?8uO)o^^esGy&KJ*80}?~ zRkyi}P@n7$abvXv&ZNw^F4s3}yD4hzK;pgJAG>Yc2rGKrxV0EM)|D<9vvGl4MuW}) zLglab8y6trx3PC8AwC)2#OLEQ4&$HUn7uCeC3Lvpz#+k_gK)?HAPFpLA~{fK~A0bU0Agw zlfBmm{=3l|CSTo(?2sF7WbP*IA2diW3h^yc&acrZ^3;=axAefkA_FHm{0T8Z7f>kk zgG3Gvk|Dj9YU2|V1%*H*lDjonNBXbvQV7@f&LuBSslUq47Hk@p7H&WH%g}KToT5PJWMtN1+q|3F z@zHr_z`^urY0))!nMzoobDrF-`JD0 z{l{&CBl)C4P(^&ZR%u?Ai-~HQ@y%#<)gZaL$Z@;DD_cB)=n;PF%yKgd6jkSojKb%i%%h)Yzt6=itW$Ki3h3Zs!7e7=1 z`HPcP>}k86`KBV)OxOWRVA}OsTk4pID&6rs?4laywp7Vml)SBwa}mSN0-wfNIhjX6 z@9dx)0rwQCuWis|jh6-Xp>_56Mm~zmHVs(2#o~>P6l|>WqnLh{0R`M_1$W95k!JEVx-3uM(Nc zX^yT4f2514kfAkKg|N~RI;%-(r5B$2sC4Q#(Y@hXs$6{$9|~C(-vK*Q|9Po}K7ctp z&agpDg2mOCZP>ax3kp;m_%1oI4`leekG_r^Qyg!XIb97Ziv01hFaQ)NlT&{4yQ85} zlG$g-V}*b7!XDs5zm2OO2Zq9Y|3M0j7J+VKoSw5ypWfH6Xi`I2(l|M0Hl}-eYPBFV zq4(QiOn+#y&MA?m?uG27n5gp@BgvW!>8G;w(nU*Q?aaS9wK#1jT!tZ#@A)fd1d75l(uNDR&Z>0DW)he=cek^{yQZ+ zN@t?sU^W*+z#ycd($pEC)>;EK#ZYR7LH6#wziRL1?_u(RwXmy|Cqq19SN+^8S8v9Z zr|jL$5C%b2(ah*nQVlZ9)9KmvcY;iN?RL0Y`6jG4WAmznR|A@~;w~Kq{b|?WBLcRxCldGiOf=#!*@~m z^HamijK+dsM+|nI zi_L!JoAla#h0qnspBS1=5Dhq@_`uC(X{ z2a-=JN1eBYr}+c~8cxY~PE<>;^q10HubQaaqT*AAMagpPj>C0B1BobeKVCRqy|7~4 zctz4!m*E&qVs&>+_lHf>740lctF-2?G|tx1Yu7xr6yLQ`;;%vwLG+5{FJp`Grier~ zr!slp&nY+%U)|%a=*FDm&^{=5z3Pe3?DO%U`n0Ng$d8>a0Trq z1|P<%AR{mFX&Lv{Gwz9gZt2~Ub9HmMp?hFxs6DmT z;OT^jvh0e8%G{c=aWB`baUPR;C1A3)6{p=-r!bYLwQ?HJ;q+{xr@PPdQEYKrq%FT$ z<4j3NK*H9mF&r=Igq}uN8T-zO1P)|5xDxMRLogw)+M2Ror?q0sOmDNm4HJJd>_Cin z(r3;2mV1v4C?s8Zd}b-*wfN%tIl;a9hGD7p&)b$X)iLV5D*M%;+L;9hS^ysNJ}J~` z&*Fmu%{gMoZfE_SvpN00i+j%qmw&Gfzj3K5PSk9@)>fLtRC+(=eg^5#)78yWFwqp` zt5ZpGh-2!?@T>k|J&{;*UJ7&H3Lf_>jqKAL<-y;lCjGp{--G!4>#lWaVi#~K$Dl$p z-+lt>u=cBZNJs>~Z=C(YGCMG#z&&>6mvGqv!z^;2%rgF#OrDl%*9mBxu*#zZSebB>{zcG9AZ+cYg79^# zZ;=#rF>C)TfBzO#4gvMSW-yuyh-4`{2|CJmO@-}bX%vOlP6VFNw35?q|Gm;;>^BsU zNWnihci7u=@mH;MGtuYNGXGPt;(FV>AH~L6cdEp-LNZcQi%X^rykEL=e1~RCmc1>H zTCYJ)`|%d#TGEswSP8YRDv8fWWvhqYb0O3j1e*K4zrw7+nT+1tZLOYC=a-ZOv$@xGmK8z-8eg5zxvl# z-Wj90!#dkL-~1id3aFs2|EDrM63n_^o}T+2RU3W}g68~BS@mKYmiK8JEl`u4_;;;& zGtt{SG_`SGZ>!Bs`4`#$Db)6#1`!0E=AiK{j{aSOEry+D<9zn=it{ZmZ7Z;By$`70WzrdRm8Onm-cJvsqG z{x$H!tl)CW{eQ~S(Zn6VpCm3vK$LH7|1LbILepL}6_LkAm7Wu7Vf+IE9sCpC{{ANk zKrD{GOWC~{7VnEXFhBc-DrWy-2mfc5VV;(w(OmD#0`>QKe;3C)V;Tg1+Ihl=Dvy`c z!Snv7C?7;C0B@tc{twjuK>g2BZ*O4uZ~Fh|Q~&d+{{^c57t!D3w3?R@y4dDPOma&W zB7pmL4uLf?y2VKNXWL_P_$U`zM*Dp)An2x{?#)46F$5MwXL#*}+HSn10?lJ^Cuf(x zZiD$6k))-(IMf7J(QMZx{iXNkMvv`(J=Rtb$@J}k!i!&S*&ckVl9b+)`al1=GKaBk z{>lmM&MOvkjZT2zJjKV;aag^*MTja`wg3+fQX{>+d1e`PA<$m}#>4k*NilCkajrFd z!g6}sJXVDZ#=spGG^opPnn}pD&OyLV>Sq+O>L$U{QT(epkzm<{4P&0>>JN*V%-+h=klL@`p*?aggO`x!+n5iKtj0)_`a9(2z)_tpWxAD(ZK`R z_)lB?9?E6GtHj|QqNtmBp1cMCH8%YR8cE7>@>|Fxe`5w-9`IA1vSMEczY97K1H}{9 zX9fQrmb47*Fu9fZ9ig}XX1X0Hl`A;u_8KEeGfEqlis`=FTb)$V8S<|~phW%|iI2^#_UiE0+z0hCjsnRp2=ke znB2<=DbjdT1Q5lnHOfK@xU4vn@E|sTiV8fR*(Q_uOHa0621qWO>lH>v0b2U9?%J7o zapIBC$5LSXJ%glNchj-x@gzP|Fqtv>T8i61)fBj+SEJwJL$v6SQyLAhzE2cvtkP6r zp|gQOIn6@6Ef^QD&uID`7hs!&l;zVl+y^6G=hhF@XMj$@lHZBE-DknErh9?f1B*84 z66FSXznlU}rxu1x@Hcb--U=s$1ZzZ$=}gfa_NsFaqb?!4#Tlh0lr~XD{{Q2T_mkl_ a7^RZBjAs26&cH2sAbDx!SI`$G@BS}}g=NG5 literal 0 HcmV?d00001 diff --git a/AntidoteTests/ReferenceImages_64/AntidoteTests.ChatIncomingFileCellSnapshotTest/testDoneWithImage_right-to-left@2x.png b/AntidoteTests/ReferenceImages_64/AntidoteTests.ChatIncomingFileCellSnapshotTest/testDoneWithImage_right-to-left@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..bbc938d37cb2af2f1966d54c1f427489ba208d10 GIT binary patch literal 20610 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
W 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 S`+5-YrzorXyyThjyZ-}ckRWFO literal 0 HcmV?d00001 diff --git a/AntidoteTests/ReferenceImages_64/AntidoteTests.ChatIncomingFileCellSnapshotTest/testDone_normal@2x.png b/AntidoteTests/ReferenceImages_64/AntidoteTests.ChatIncomingFileCellSnapshotTest/testDone_normal@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..462c5823553b5b2c12547a73070171d991a1d168 GIT binary patch literal 11603 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 F{}-gs!$|-D literal 0 HcmV?d00001 diff --git a/AntidoteTests/ReferenceImages_64/AntidoteTests.ChatIncomingFileCellSnapshotTest/testDone_right-to-left@2x.png b/AntidoteTests/ReferenceImages_64/AntidoteTests.ChatIncomingFileCellSnapshotTest/testDone_right-to-left@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..677ec8996e4fe478c4a46e397f1dcb9cf069378c GIT binary patch literal 11681 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%0D}6E4ej9l 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 CjpmmC literal 0 HcmV?d00001 diff --git a/AntidoteTests/ReferenceImages_64/AntidoteTests.ChatIncomingFileCellSnapshotTest/testLoading_right-to-left@2x.png b/AntidoteTests/ReferenceImages_64/AntidoteTests.ChatIncomingFileCellSnapshotTest/testLoading_right-to-left@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..3f11b79d34327bdf62c8208e5ef473e69ac0bcb4 GIT binary patch literal 18041 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 literal 0 HcmV?d00001 diff --git a/AntidoteTests/ReferenceImages_64/AntidoteTests.ChatIncomingFileCellSnapshotTest/testPaused_right-to-left@2x.png b/AntidoteTests/ReferenceImages_64/AntidoteTests.ChatIncomingFileCellSnapshotTest/testPaused_right-to-left@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..ec6042706d81851d7c28429c181a0814985f80a0 GIT binary patch literal 14377 zcmeHuXH-*N*KHCoq7nr}N>D*Wiu5j^B%pvagAJr3pfqXH#E<|siXZ|?l_E${dXdmU zX(Am|YN*mnq$NNK_wc-*(eIA?>yB}Me0MyI5dtUdv(}z#?ltG$2_Xhov|tC}2SFeZ zO#AYsYakFL00aVuFhPMU@UxG+fhVxXH7#{ee&_Ld;Fkk#myJC@AdWM853u$%fnUJI z;|`ZlH-Kjd@Ywrm0v^Ku_1p*oaU(_Dje%4%yrxFZRDi&1hJ0^)YCAjcdWn zqQC9c#OgLo7@`|h!uK+;-ff0pc_wbmMJkm`#hR;=QQ^=T)db9WNh2CZeBN+s}BSl`Cd=+ zfl#GvzxbVGwb$dr`tl&Qf(c{JlQv^T^O|C;*Bi@zSnh9`J`l>f{juQPJE^x|xP5Nm zFN@egw$su$@hJ^`jJl$K9_4=FmFs^>@r24fYSF_oORU3c+NQT6o`kas2 zpS+p)3gHlU@QiTbq>Pwx>;#)M>*Ckgavh8a&FrVIY^LPki<~SLI7q zuj(U@0tM|*myf^Q>|I1a=svG?j7`7O5G-%~V!){Q739~Q-Nmt`-JR8z6kx%C zVb#@a9{mR(Okr#f-sgtMI-=7}+bvk1nl6zv9GtGA- zFMNA%sjZ-ra*v%FiiKa!4E!}C<#!0el$%_CG^33t125(rshcBq?TdJE*GBv4AHho2 z5lUhoUriEx_oYH!?!naSFutA9j_=$HHU1Pp>0QzZ{N%4=>+GKE_s|1hSUnm~dfajp z$=rocq3kG~%>pVsQx_&L6a&*NdsQ*a4QA9lz}!zm-|>82c})JPd53~mI)3=9^$UpG zyc2}ux=IPy=K8p>+ds|33ic*mNMwKm%(!r%+Cm|mf1zT>ToZRbyI#c}Zyywt8yt6< z7}s!3SAsT@K?M!n@=T;K8(pEc@>Xv5#0Leok+!+W{`^9nV!E>S6S+j%lFP(YCwkG{u zd#uBJ{YCt~Ncq^jz}g(v70=kJ$_L#5^#ZFJsSGo-{5rB627;tBV$V9I1wZujeBNYu ziS-;iw#T1xq9E^nNL)Gr$o5bl%5DdrGMK8AkRGTE6T7qGtqBUe3OQK+=oxE2xAc{B zJs?==k9vDzF$ByQ!#{p{{87Qjx7;YU3^33HfDx}Jmi~#;`C5Kedg010)06+>I2oyZ zmQELClLd74aPflQI@>V#PXWqVJk=V47sI%O-T*k8I9bV|jRQdtUDn{?>?W;xyV$wu zPi?iwz2C?BmR%5g_g_3HRgjy~P6O^FXOI<0CqYQ@jHZL4E_r&+a7vUzWR7FdPWjP4 zT;D?|th_VW{c{M^KJ_CsM#e|wbU=L|BhBzfb9^c1k&%U-*KO?g+m?7DFXaNvsom%u z>JAeM`3KJ=XpF*x6MO+c7mEFwAe>3m#KqN263FBe#3I5{4Z)mCnHXNQt5nwWWs%is ziL*$uMru;|bn^ir0HYu9TSMbs0eiJbKI`NXOC zG;Kd9WgQNXC?odAv%BZDU+r;xL9Vd$(;{FA4hy*D=7!5U`YXBR92Y&^9K1R3;q&cA zFU_!{R{$9Ds-LHEv7yj9nP!{6^ZlGI4m5mj$ZAd1 z)~W`(jXQTtImcLK%pAJ>n{HS|41uD*f9!A0WKxGb7+LIf0U1&;;}<+wQqI#t7xas7 zxoz?&{k0ig@rO?5%UZv2O9P}RFEBoHSpyiP!2ODHXADutq3bpAo&zeDxP^UQH}&xr=Wt`$ zUN;y2kJU+#{ClbiLW~Uj0rhVI!kSj!F!8e^XgXY!HX?J88*6*CHa-^px7yqjljhw5c6|?!W7>)2@6MP(~4^ zzt`mDNC8HGs~9%>zt;uk?uin0P#`-amwOWH)RUt?FLi>wyUg|o2?|s_@ZX?TEqP&l zDgb#9@;7kT1P-Y21t3!x|E3u-#keJx17AY1$Gj(fuv0JxyGRR$Z1cOiED?vshj^ZF~Qby(`o&uElt{F`&`>a3|O zBffte33JGx4Wh~DnT?V;Ucbe2raitDH-=TI8Klm}N?ImY@6yOBmLNTkbwAu_79A>q zS9l%aycZ;@j>~RDkvn2%F1_`8j!~9k-R=nf(wv8$O4YB2bfhHWvX#mt`B#kGg4hGx z?@iv9a>u<)RCK*U@FrDMg_I(&qq0hIB)T8lPztNXO-Y%zes3q_;YKUbyW{hipxG5c z^&ENS1&2gBS(4j(&DPkNF7_y#@ASB*x;6f|^|h$cGjm>FPsPadExyT9j>Fp#rgZm| zdA?4>#`|2!{0C=?yQ`w(hd3qlCXGIo#FQs~;k5LV4zWDeHH=$6g1~Z3TfO>i1?%TL zxG=6Qw=3;UJ+ZFUtIhaDhGs8_oj8zC-E&7L9^&F}*I5V?6mDMDUF&NaDsK6;G*}X? z8!MsjgWlaHjrk*dNqCgCg;V+e;j*K=uKT+}<2XJ$Bob;5p6wZqyfC24uRB4Ng`OSG3 z$t=3VjA|eX2DP{3Yk<$SkKr%bKj>C>ji58GhC6fnr!drnBfz~KuP@NzPNJDEyZ^D$ zg+@*T4@Rd3D?!K0s}h+m95I=jkfwX;{n2tke%k)m_l>9S^Euj@6*4jKAQz!PPd?7Q zhTG<5mt)^PtK*_RN8ckXN|T~*{w4=#s>^{gj5U*C4`8_HbM)=1+M!|M!0(=6HOzdq zdN{IO_E^B%a877%%alCR|dh zvIm$e;l5(z^0)8#+iJh#*5`A7*e=ti3?8ai+rJ{%t9gXMHDY~r<@ezFm$S0A)e8@t zb;0M3qkyzk@);x}oF8QTHb+ux3YxV}Z*X~_u&F5*{?S8&f31&V?&JqMmp>2R0v#Um zP>fWSJ9oUx8LRhu$1rf$gB?A3sip(K41lCHr(l9>lSZF)st<#FU5CKx$%FOXFRDWB zX(C2(r1C6!WRn9fC*X4#pyLDOiNU1S)Tc2KbhJ$p;)}e6LWqVyWG}@?e9tepcE#{stCw+STS~RkLp;--0{MMQFCB z#KqjMOL_MQ2(-IP2s#A^flj{IdtYQZY0&%I<+5kwnQG*wNsS?*-Z!N-M{zEvGOvHG zuj?w8EL=9O6&d)6-73>sfjzEOubE3q!F?kqARG3$J zui`YY2YQjEPoLJG0)fel&Bm7pi9g|8)v^h%YE|$53^p}4?;uzZ$m_FR__r5>9);50 z6P$;cd=r~EGp^vDxWF<%c=s)x)~pFYHd-`1P2F) z6gF(@`-edLLx%z{f*`~LjTUhsyXf^hf!d>IjDsCsae0=LdNXugJUnFUbmvKVdE!3n zGx~}bE|@z_@SZXJQM8R?>6IjkGO?S%AbqHt|G=`r+ha6p1Uj7vxDOHzyTR=Apzb$5uTGHb_ht|_J#7M%oj z0(odCAu%PzHFvJ1G4xgvdb9Qdjy)1QQsI$hYGQKVvevIP zClJcdZ9lQnkFvBco@tyAk=;H@n@`}li&K`ugZkJEL7Fz=BD334FS$N zQsv_+sxhW4I_X4o6>96p?mMN-GzTzPX>2un-3=$#D*)sazB ze}QFHx>kfWg=>}P`JX6OAEk~OjodArO$~!1%|D{4J6>6d3Y_{W2>&YuwC^|T?WJAB zn@9ZVhy^Ptu~p$ezfrsyv!g>=TqLm{!Ox;d*}|#Ip03z#)Pa_4a_{s zwd_;!(nK!cd{cU&Ntn|9!2-TZOkk!s%Iha#B$4t%4Je5-l>?cJ|rf-V-A6<4Yp~Ko*U1K|X=7(>?cVg{2 z`w>rk*-XNK1)YWomrY8wS5L%(e~O&6ca2($pdM6z@(;NMMU0Cjy+i$np)a!@49ufx zhZh&0(^>U0cTx98Aw{xH0mg?~-IDZ?J7+AmL}%)!xZFp#GZ4d4z`PiiO?uGR-7lHm zVmc0CDMY2dZ`7#5OLXePk;#)i&dy#UxPjl3PStIFg>mjWCwB+r8>)rId>L!oGS>P% zGC%-96F`Ju3~+nt&Uv!!UV$!0(=&#i;hVYsK&uC7zL#=p-PH|6kwtn~t7~j$$hX^s zpX`OborBmW!%_b9zyXb_$&IS>BNv&0=^&${X{4)OyL6@*$g>t5*YM?ng;@i6?T7Pd z+L+(^L1&fu<+LRmax5DyT=cN>;_|EHI$C>OVl~P zET->o1Nryjb{n1;TDZnTUxahlWbRlF%kud$Y%P4xp`dCAUC9?b_8&Rvxq(7c85Ymo z8vc!XfI5rTso=bnhb#F%8=9M+^<`V#BWqSuI!ZJC^pVonUk0w=LhptUJWNeZSB5@1 zUBUUQapHUTQ7@SJ|GC$b^JePLjN~n-%;R6bh9<_xf7+s63qSpEQ6Y=Y9s{dNbE|}f z-DC8#R(*Z_t6M?B6bjXoOlTqb z(;4iSHj(t`dKT0c6dN0hAFV-4W4RD=QfYs1GO+8(64!gzUq3Q(T*JRHjljLuId+|X z17R6bE$=YLKM`UM}T^RKJIQY+CLbCKw^pCKw}V($973%+t%6-$|uu&f;+ z>#q}6@QW*>HHo#vw;Y< zz#O^*hI@{?W^m9L(RM=Bubf1Fx60i@qc>u!n5|!@I!W;4q<}cN>0Uqi!Da2KsCK)8i|GHw$t_I+{6mj87*!T0)gd^KSR!e*3BV z!UG}G&c|GK9@DZfG8iAlm6s3n&)LG>j=6Z_%d|kK6jeMA2Jo+TW969K^y)g_bwPY{ zN1`H+L!DSAT>xL5;hniH(T!A;OYKobz|bdop@mA}f8+-;X14ZB{GLq@^2=p7@KO@p z1M$T`G~RR^;~wyi&FkDm(Jlo z&y0+W=;5}1O*9~!8(f{btMYG1JSPtn**J_S3oMhSDckEcm{uG?Nla2QYnJWgIk!|? zvc$ulcOC*5QxZ_0VZ++xmjt>v@9hbO&8LuKD9y1tzwKf>N~o$?^@AciPg|_qbO-7f zgK%GYO^tbJ$c7?b^RA=g2V9=oPOrG**GyTv&W)j74bcSKpPq?{e#0g|P|EE2+cGci zM0Xx)$MrRm=oraGmfCyBw1cVVwyD`U_7Nv9EX2gbJjBidAHSM+-7&}cuPSqW2U%3y z&*(1;8*Ysjx_;W5vgJ+!ia1)W;$2XAnIaZBCY5-}Pj_&zz;nU;MrwLpTxo&gV4e4v? zT=l^2>6=?#em*gob18-A4Tgl`?pbS?E7TboBvP_1;WySI+VQE+QBnbSjy>`HXOB?a z8rg-H2W?<*(U|;c&Ly{-JC46F!zzvk-ZHf^6KX) zoJ#^|r>2T((R4Z78brlF*GY$Sb)A4@8z@3mMBP%z*H8QM?yj(a|~Bj_GTq$KvKaKv|0KR+a|Y( zHeR`Vl93M-$Oq9sBQdm`AD>E?S|sO2F8EZ%?A0=Esf(dq^`<}$D?ZHlw1qPyaK;^w!sL~uk0yt*%52V8uQxB%m0d5ozzga)Rf+R5}x}> zv@&v|y18YOttp%F6a7BsC z9&9oYFCnp^M86UwFUo=!h*4v)QGNTu>P6^R)D8vsaODPf6}Doj>Le`7%X3SC%!FH# zQBEPK$>_`;S^ePb3i8?-;L(q7U3y3>IqXXoikzG2)*$UW4=4(nv|=vleIlQ@sJLwr zQx(4-3~cp-kycdBj0SIod$#AD45nwxr@e$L@@gc zhO~cVjR`#tT(wW-hP|40nNb63$i$DFbP;rKIF=7=1fDqZ{XydGfzVBn`@q%Iz`Jq= z^o&6vRq>55qw+LhgYY3R^=IeTy{KQAo(Ky6$oldY4D3-7dXRs3D6n#uP0?&36xb$Y zLm$zZvzL4df6)Kq9@OrRlC4})Ch1! zh5zv*X1xzM=pO;zSOC<>tdRTFd%rzfKwOGP1G3w_eBzuNpSjWEqSt(H#@pdvaH2D1 zXR#o|d1>fl8+EmXcb<3>fn6dl4X$TRV^lNxBZ{|MaQ@5-z_NRc|cV%o$ zqn(j+W2+m4jg3))cMCd5gs~%dLsiZAoU8Iv z43SEU{mtLL-EhQyTp|+7RJ<0x`LykLLu;IWc5Ym4ZE|O<$a(k4Mgu|3nQQ5oZHHS7**&WI@JN97Hais# z4B3$g{UL(KZ0E5RpGxFf7x2m1URLd%0 zU}%ZpC7sMHXdSHc_jlb`*CW26%w^w;lGRB!EiBTH)P3R6R_lEMG|lx zu;CF6{RPP4yaGjm?9d~5Lm^5S%d6^lne*6w?nUhKcj{jqZ*S>3)y_3=HCr$!x{O>7 z57FGFxM~n&OcOl0aQ4_9SLGCg==QE6o0i_q>LPeEXn~@vugrOM*kK5?V1P@3h7W8{ ze`QX!{!#G^8#OO6`MuFqtu^U2a1zS&iq)Rqp+^w94_2BU2+X_^H~>9zzBH#HKEX4t z+;OZLO_Hby;8&TH&jo*bDuS)5WV$r$(hIUEcRPhoroF%4nQZysCHPHJ(&qEbpzk>{ z%;x!GKC*yj1Rz-gyBV8ymf0VkYf!qx00{s4z{u?nL!A@~#i#AC4alo$891)(Tb2+P z-yCxM3QAVRC||gd2a}MLB$XMJ)j7DeA|5lR-r8#A87%f*OyGPqV$8jFWA4C8wqwgy z278AFbLuRJR)MD*eNs>ZLA^fU{iZh(I;+FZpFt-tJS_DodL}XV#ih#?H;4BSkqrQR ziDynu&U{*>@Vo4!Osr@deoxlRxUyA zqTJ<4)NVJTa>$4@*r%KBitQyW`94T@%m@X4%Z?WeSLO(h`|bdu(&nW~{2`&tuHUaB z>uU2~7*-F)BK&(KPp2Du%FbUkHZ+#}(^X%| z`T}y?=-`pQaN(W3sTU8@JP)9Wiw~fPgzvpt<;R>=b`ve%jwuBw@1lZAHgBCnY*xMZ ztX)>Fjit9|1FfjE@U3<*=0~1t+bEBuExXf8@P-jjEZ(j13PU!l3O;*qQ3=gthD%+o zBcVx|`6=Ly#a2D^(d?cZ+!qlAt)xFqS}wlYzRFbaF|7A8cBhW*9{*Bx%!|wMANS0 z#OT9^?D{*f#I_p~vnh^gUeIu{yExWg+a7PvTRThq>CP z%?Gv0rpacU5?k64x^12Pb8ip3ItoaW(LJ*=47W=CdR!}YjIMuqYhNdMr&%1WIzHVN zdx(^$qcXJL+%|1i+^P4iXFMSdle4ZkJ@cm&0tXhaBxye{6YRg&jU()VSO`YRsy6{o` znG{;GigK(3uup3Kmkk#WKfGb42Q?rI9i1hi$SI2DL$e>Ehbny6?hdewyFyWSE zb!$OSOV+o}mtm>We-ddGXQOF8;x&Eby6(m{tfTq3TbbFqC*VH4tX2?hb+h0zB5XqY zjss5Su)Wo(b47hXa{&daF-F<$T;I=jHXRWb02mjR=TI#C6)yhBo->O>TGOzXubiU= z9I&1=Awg)5Q;7^Et$ZL5-yc{*Wuocw>s@&r;j7)afjj zqjnJ@puA(C&i9ThZ_W;U{!s~~De1hpdt&ePaMrE65bgu-0!$=R8-p}$z6IPDohc|f zsM)ZmTHq52<8P3f5N?Q)t{kNkiqd-v9i)o%7D|AC zbO=qP2Y4ILH5~7_f4?{09X}iyk&wOiT62B#o8O#s?YHWWmB1GmFMvQGu!{17Cm;~M zF9?M9mXsLygpupDEAWQr^hD`CsGx^w8Tf_FUiqaH2t<4H?1iWDgnbkEkje6a+B4uC zA9$Vpv;r^A|9Wo$ftXzw3aLeb_j@W2?mctI!zAfP(mY4DEt>Ii2nfu!&Lz=bvF(~T zB*Nl5?Qld}7}X|Uoc(N8ut4=la8`*eF80wI+mqlFVa88*cvnTZC@q`d56C&$z6tk{ zCb~%-PJqN?DasdNMx>H7sP}~pmp2wp0kAak_Q_s+c zcIYWYLDQPw&fV3*mm}yl$hgvx6?yn)0g;LY3&G?yMPMKuGR%1SD$x z;f+TP%!5HUm;iHdTFOlwj<9&2x{2<=@^a}1&3~SlP3Btic4t@7_#34H7hNX(8vB=G z`LZ^njnWf&0^ml%NI6!8lnVt^$mhP3#V6*gQ>so@wyh~zocLhiU)_~HZ7Q>c#Dm$= zN7N_4_niy`UF;6oU(l!H z2^VGf?er2tb?MW3Cuz)24!KW4Y;w;o@Zu;+X;LF~ztXox))ibi9`ose;cMbP-%{ea zx=V=Q{tt-iX?b|V>MR6Z{da~Ib+pm!%Cy8^SQdQU%S8xp7r1N~EAcN&`3P^m&^)o7 zU77N1&DWFS+gH|oZ!{36()!gK|7mtHGa<*#l$s&!t#;MqBLVOCJQIMeqKHpWGh%^D z#9drP&R0KX>cULVrL?W`{Yyz?8;)bk`cwuegXB7ZZ$hY6(~`ivJ=^C$*|GKN6BRc z#ZOSKD0Sd|t!JREzHX4=lw%^5h_`e=4r+gW9|Z2IC4OAKv{#7Il1LX7TZrYFC_{U! zs)op|rF)A6Ug&U$HyZW{Ng~E0b-rid<8wm6o)D)dN_|XyY{3>wJlD0jqf`?Ee!ygkNEKJoam*3K7k&b!R5_h;~gH8kLHlDASA4OY7WVz zdZCKr=vhpT7EP(q2%`n1uN;c7>nFNxznMYS-1v1;_>4%C^(PW=?c{58gO%~pqwyv} zy&#Wmz*u{9WQvlIxvYj1V}JxqLdvFq!Cx#Bbd93#SJXZvL%a+IDcP0z}Z8!V91 zcXg*mG~;Pk$g%QOe*t1bHuY-;t!OSHHX=4)W)^IT#4ql+PR=b8p;Q!xE~>f~jAiO< zE^~jbUZCImYbJh1%qKrqqyQ-g?AJJl?{bjPF{alh<*slL@qlpOYjok+t&%Mb^L|ir z;fFS<&8`;vjF>&`V$`-y0T2kGY78C>qkn9FpTMF~n}BCun#kZHB?CVG%PX6r!V5Rv zrkyPq80r4N49_$zn;;=!3A^v*Oa_6(={JA_A&6foODNfp*M)ymVB={tAtg0YXhikJ zMzV(x1Ey6Tl)Kmwh-xeYy}QO1brUa4ygPV?@D?y+t;pGsihVqCXV<9ww`)|C^wTpC zzH}V)xn8K4eA^wto(k=NPq8#LzZd$)6gH3k3nM2-#Iqu|m*O!`!K!B{{=MJsR~fh8 zJ^01qmW&o18x&*W64ATkv9qdAzN(fKHa*J&c5M)V1}~{Wi=`s@E%8)5;pu$8k5Z>D zSCv|aCSqrK3N{eKsCt*?kD-mxE?0-KdN?;>n}%3)DP2)G!|W%^l$*VH!HCsxnlMa-xQ`vLQ8)tTXgx0>;;+{L}c*lS@}0nh%{!evj1!f2OBdjVRzS z&>@v;B>i*#0xFQw;&pA9(QzwnJH(T-HG`fe*XWF=bua%p;*pPoTH{x`7u0lloGLE(J&D$Y~28xA6D!{5j4L%Fi8GaGi(+$yr zo-%;tGb0x0&9wlM2Us=z7wP>mXwcnhS<#9M1rL!&-1s60BX#bOw*Y;(U;Yz+hAjI@ z;oeP92acjhgujTn!-85dCkL>kX$8=Y$3jNpU&w%4+ku@ENuJr$nB(spNcLWo7miur z?!jtc8ORxd$oYpA?f)V^oJiuWR~N`Y6)ov`>57EwPOK<6{fKKQP!{4PthoLM%qxCu z(4H3Du?y91$>Il?)&?>40%c2J*_GBeq@%NDO=&^76#j<|@D^KAJU5n!y8te?Ndfq_ z=g=CNFcG76WT79PS}dH=hGbH0E1f)JG3!4KZLKIfC5N)vW=4kgE@j&v4IjSV5zB9| zIlj5drv)>s1AI8M!SX63*SoB+x^3LhJHZ981f|~}_xDS7YS|V&T}AH1)de9#jd*u5 z&lQgHpEpd=*~)AEk>gV5eH5{C1IeeQ|8fKB)l&VBkU0zH8h=_ZI9@FHB0l9;Uyx#= zS&RK^DgaPZj9=MWiwJ)Sj6YDOu}$m%48iax+!;R6e*{$QgPVVN51Z8#8!s>f0Y1G$ z{N-k{$AC|{TeJC7H(vqVGmEem9Dbmj_A6QngCBHXZ6U%VHIe%R0wz<KIrDKKyBp zED!%mUS6z|7m~X+krO$W&a-|*NXhd$meAC zA0(eklmF1gc_97|UEoyY|24X(>1+J{{rmJ(ou{>KWKFEUKz{+^ocjNXVQcpZxK2Vc z+I73W#9EAK6Z|*K0)JN6(!^qnF10#b}Cu`n<+G_>DY8U8Zc9yxMo4);b@l5ztVnh)+%%U_N( zdK#wMZX~OBE86Njs75nVA4Si#4LA0uE0M@zH{~^QAy^$nL`vT(E!`7t9QFcN+_1g-W5I-H1QMPv>IJqH z%S|YJ4wo|@^Ja1OrnW~Hq*gcZ;%9qWyPKMtrif_n&D<^gtRjNb5`HS+kYg1`Q?S>; zd<=p2zZyl^=(?m|r{9p8)9wDQHnM6@3Pi3CqX4wYMnvUQcmwwcSf^2N^1&Lo;D z-GaBp#)op}(&HqyO;)vC0iCF^=h3je*jq#WVAv|p+K0=%yh1}2elam2VYO^}4eA}n z+DwPrdr*3$;m<)R(=%*%b@nz;!6K=iDIKZK35Xr34Gj$?$S)svo*`9WE6i7Mq5mzQ zel6NutRuUT!6hJ%7j)NoDN1|m7WhR%Ca>)Nw7(xOVYX=9j`Xq{lV^c{)%UuOLcfI* zXfV?JaM1pd^Szd=?;E>oD1Yyx-6~qx_ver)@^UlX868OVWVn_`d$X5EZ9)2P6(*PV z^@fH!Yr6&-llr}|(C%v%t=^QBFnWEmh6G_dnG+~j3Ectm>%9v$pZsw0Z|R1H;G#2K zl6h~kch1-TvBLTg+2!oz4@ag5R$0CLa^eQ; zkB5b=@X_bmaH;2{p(^EXb>R*Idq3-txE1++;`dfbEi|rxou2sB6CfsjN;l}DXZcL) z=3{?~o5Fb!9;e59@WV?cx;%Mkx4V4Ci#yN=oYW?}QTV2Rcxxztd^mws)(7jp*{{SJ zz-f_2<12CL5GpRfB_=SJMycnNT{wtan6k+AiiEXKpL>g*Ykw+~$!()mC_J>PwVK`b z1-y$>D$9bT}7!zzW9@n3~w|Hi@_cY$d`W&p+>o(y~U`LdoHX@`Mon@{}@}i zh8wn@`q?)zQ{4t@LleKW4LramCFWFBsn;h~&;pn|tDjb*k z7VjBj1{-ztcU~Nalv>yw(=z1_Ki@i1mMzq+5v9%;b-YJf*w8J^h=X8vS5QN@t7DE{ zV@faH$_xI>E&|V9jztFxtkCig=f1w7t4#H7EU*1-?sW97e$N9R{;tZsPjtuqIkRwdna;;^apb}*Vc-3vXprA1~g|F*bZ^^ZLOtn-Yf z_UjW>eG1>yi*{T5pAOz_DVg|L4qW3bwcEKT!t{H6c<+_!JJOenrCl*vRWdJ+CdTW% zkM7fP%HyG;GpzSU)wpxvL^?V;=I|yG1^!rbN%kmcSAF@+Qu3>DuO6jc{8++ZZEu(H6Akw#|Tv+ zaP$h|kgif$Y_Yerw9Mi^04ylU7uZs$1LE>^2yIMFSyNdN$fkucwx@%hc^PTj8o?RG zP~B~-qUVr$Kc>u{-G0y(eswnNnFOTgF* z1%tb`(o@{Y)pw;r8?M){thq+8NLO28T79sI;Uf^7vWrqSyYcQ5)8Y!^88;u_-jlE) z8jA!Pzic9d$x&}=m;?tMpB~c%-FCKlt>SK*THAB_yB-(*;Jss_9lBonS(y98rO&(t z)%WuYNSQ87B!@8~Y`XwvYt^b-{GP9kP;8U2lE(6$j@X{x_`wgg>$lt8M+$V+yie5h zwLg~FX`+T`Y|=v-^Di`37XwxG7S*uMH9$cSFozbz3a&fXO`YHVer&;;zTqti=Oy*3 zOAL8=d2cxHuUtS_T^6UVmA>tib2WYAdtq=f^kO1~EY_a$#7NSoXUbXxm*6XNmBu_% zWZnjNfnr$wP&7&dwX;=IjbESxY@j|DXmvOI3HGh|PJ-sQ)fIm+r?#y(=Xl(8=&J8E zcG$&?r82HeR5=-5kaNhsGZ$iH$+^FSUt|kcZiORVPp}86n=agkL-KF< z4R8Pc?ZX{;1?3jI&sleto)Ny#o~-B(k!9W%GVdV|*w~uv^tKAG8kD|;gI%mcHN#?8 z&LNmhV?#+(a}@kseb;0N5%PfhzMm{H3@%@xm$I=VwAi}d<-gw6w+ z$o2ynLyDgCh0z8W?DG0}FQ=wKWXK2f!Jz_fLk*Vd16e-ot*or5UoHW{TOU!1xb1Vo z$MRd5F2OEU((apVQb$=5Jv;?CJIkrqgW9Z(E67aJ z{zri{A_-3@K%mppnz2Mf5a?RLSu=GlY3#{_Rz={^LaiJ;I6|DlekyZg1$>xecO-K7 z(}|j1how<;x~WvRtrGKtl75z}k&0Mq`m)s0T;XQV6Rr>Gj-lm$!>x;$mApAD6sLEM(TRWY--Q5xv_PC^^);G_FBzciz^W6zzMTNn2JLv4KANSlTeSOXG zkyLD3&yCgf>%HQ3*g7UAm^eONrxKKvMK}4lxzX*?6eE)LrABCtf$ZP5(J8;Y`X_1OAObT;3Ty1FCA zxRB7G(R~^3!#8BvU*80~xZd^n!H&6OWGCG~&&T?P1gP>$9bMjiXMGYp%e4h~rVHMA7Ho4m^l!1VlakyRXt3fVLg$X_#9c%;b;k zns_QBpeI90fls;lsPU;FJF-%76HtsiW+ukQ1VUHF!fb49EBHsk44hds7nAp)zilvm zo8gM}L{n@7o4_Jo+kAfN6!rk7<15MQWOug(2L?N`ckZ(^$_(%Q{rx|(WCsKgK|fvJ z!B3XQahevRsACAHuM-+Y&oE+QH2Dl>Cp`;P&p) zQwqw>jez*;a(#3&hF7-<6j5ou@?*Y}C(MPHEe6K0f!5Pl7x`_96wc+%DR;Uw5(<{G z*l57{4M9papzWB6moH!XZ3Q!oT#NMhJ!$nI_6~tCWRVqzm5-t8$`U=@mbB9XIWZ-{ zXa?Twy#FR}=Af65UoHI(#>FVEK{mfYQ!{f`vdh>5yYCR%Ff~5@nrERopixP@i&J3E~iuV-Y6r`^6@NU-z5CZ5_DN z-R{=vhL`T5>>6A!#d3VD&??V8+t355r)DR#rT67wjySaWnjD#z1SklE4i690ZUZ|( z*VPHC^A&{ZH~2sdv#fd25Jq)h=GAy{c8Rh%eN<7zX(k{oJ?ZL32{vExj-?U0sFRVA zaRr=UPB&>u+3G z+-7?^emjewgIW<2>@>g~0?F_0ny7Rj5E}eK$jirv*cz~xh+oxrn(g`a8-xG#hl|22-!0 zqYtO+m9@!mxEjDPLv8biJFCW>COYFXNC(E>>_U0Rp?LBzK~a}dqQN4|iOG%*QCT@E zin$|-utT?D1u&9j#5hDXW(}jWT5XJV`@|cT(%Ll(^_Z)dTEoQJDu%DdH}sXp0#YUn z>`$*Vwh;Li$K>oU$qinDvtn{B-rY@1Ow7wCi;s;}UPm|RJ1;FCnO2p^G^qBL2aH|= z;ms0q3R1^uSjdgkcA|x}dY0xpV>$q-Y;BIOmMH!XgTa)=$qG!52V*l7w-N?K!(u3! zfTpe#75(!xBT4EyApB5Y3b1liP6~YE!hP^?<|~;MeQb@_rX;;7@6X@1GWfeA1fqdm zSXg)uDEac8u;p+-DOT1$3oG#3$BdOW8GD|d9BcLZE+AMJ5q7@=2k5QjAND~n` z=;4?|+nqc)HTC%8$B&mx-S@w~yRl3dk*Nl!?J>LL0NdZZ26%g4sv0xYS`5cyzb35h z?!r4cS>q;oDVsR@bIsel!opkC0k66qezic2w*&4qqbqe^3W|JW1}5>8aC?UiL8Je& zki@O}e%j0!tax)EP*9`V-MQb}sWjsbHveTS5JvxUew=D6bZa&vlz-2&_OJliUp?No z(QrEDkl{FL?tZerW$d_$zvVOfQPAFCeihXn*ko-milGcn_Ncw#Pt?6iK2OhR$ z(W%9}dRq?IBZyZi-TRVYp43-?EnOdiW~)XV-xyL+t!fPA^!WxF(9zKiZf`oXq^xrc zY*hKboXv76TOS{PRm}s5p3xQ72?*@O;8d2MV8>gR+bO@gdG3sxzcK7P$IR!^Oj`kb z{&&AG&eu%eQ>{Lk_;p}oOL)4ff>M%@%^(rfA*uHxkjLiiOj7!JochLo3;DSc=;Hel zf49WV^p~syYmWk_8q^gDaD?=?%HzC;4!@2lwG8?$j^D=sGR*;>eZ#%uYDE#y*G~x} z#F$@J-f(&4sz)|P8Tg=-EKI@88s-1_%sM^_^ zcB4(Sz!@IF^Ej3A$k9kQO&z5fM{scu^bp{M*0w^_QV-|6}NX6ykpj{U1dCKcbF6-My9J+zz069t}h&j;mL% zcFfJ0q(ROqf*#uoswJhR(M+;FQr>)+SwPb)O91H(&qh$MM@HWnX^EYCy1HpoBA_)Y zDk|P%fyDMhe06zw`GOKq;o>AS z7JHH&nvm19w}#S17wR`~04b>opdDU?O&Kya0{No|kSM6|>Qwe!8O$0@0)oh7{qAM0 zFe{V|N%L!B?7w0FS7`I$A#~+b#%sT?Uzu6bl{+pu+4cy_51!7|EF7rZKsTUiM>zL8 z_5cB=47nXCl$!ltAvU@##F7-EZkPs}D`aaL*+YL}$$vCIl zoJX;y&;fp5>OHRVZ}oi%MCW`moeO%rY1rYD~lzU8zWQ+H>|&OO{e; zdh>DfrF)NKpGPG06sXKDLjhA=y3yF}ZRH8%RFL%>HbLfLWQ_Ez=et8$6U)uZE84Bv z&njqnjhG?1XpWCyuoILl78Avgs(DdU5Uwe^I-WMAs(JubX0E-9IS{n5$ymLticAM?Go7~_nM59{Z#WoW@v zuXqfdrDV=^81s0AJO$~uf;lrnt(o2v_1==lI;UUxgN`qaTQgL23bo;Zhvd)W*t3_M z&?Ex!JiJ=B4Lz$Alat4Z;{C!}GoxpHu?#XMGyJ~_E1P|WYBCk%t7pC=LvE2@bE^&( zDfL~|$n(GCo*}LD`8;MTe#kl;d(3x3Bn7h^nn zbo}scWifRO;m_n&Sh`{g= z!QfXWhxeHnPrwf|B|S|xJ`Pw{ieo|-p|oD(A6&ctMPxQ5Z;#!$39_6HoAO7?A~CuW z!rXZm`Gb00;L}(KV*ku-($GiKfb33&imPJ!O!Y#b%RVOuiwiB0_J!yoxcybh$=w2r zqiP=mtz=nPvIYI!yiTD&5IC&x-)pFB5%iTH2A>9o@^?OBW?~ZFIJw;Q0lN7Eq4`uz zmp|w*8H&IC$Yi}FG|a%&wa`|9E)Y60GJ-;CMy3}KWtloTm99Ch*;!lPsR?y{@-UO7 z*~_bzMc-czHBz&N^XIG*-xgt@lea^dL&9TCIG-a-Ccn4xLF0~u9$2N5Fy|KkL=(@c zH27MB$9Be8XQnY3x_@oH?CTuO&gQb`N&tE1aIR*;Y9Qn*drqcCn+P|3Bb08hZ&zxt zC+S~Kk=ZhPd>j`SXJTtxkbbR`RbSkk@6_jHr={gVb@yXMfzx9{z0Rx!Pp+V`OREOl zeZF?*z>xFX)Mc}f9j5>fX`Zuyy3~rcl!f*m$9yCDxH(RJ-y2Ic)4}Q>PTTUpME{N z;Q{u*=?74a&Y^SyEB)aiZGg&bw5ZFi}%DJ-;wN^n7#FO$U*{$OABuQvPTxZvPVV-ar}Itl2P|`*KHUXRvk5n_skQqdUiUi-MZy4tqL6cWT42@%BVq-oKi0o4G4w7!fy{cwSs!xcc1>Wyfe;aflC|xqAZML z(KT*-A{;C8s}+24JUoK0C+q2CYP=2{5514KfkP~FfT-yxHg1pK02_f^e3EFBLbKM| zg?;1quXM#Hd#b)6BN^%jaV>CD#H}~JHGf3JxS4q#`f|7~tb90{kI{!-TC);=`mk_& z;r@i6)QZ9&rK7tYJppGr{cf%b+xQEB?2_;9JhM9Zx%@OOxslQ{bMa?qI1I`l2f4%j zk|U|2^XTLe9z;|IvhX`Y_ANKM!r}1MYljL2G}OnTy~HBE@lsa;jer*6bJA%GIO@=~W_4T{83SF72tU~v+kF2e6I*pr#Xh$nx9)Pqr zLwediiHPr+`lv<$WwV>{e_yG%YekR+0gfn$PsTvSNf^?=I@JtvVAuu*^GSdBQiq z!JVj^(^6M4_0VHxq_(cEs<4x|R8O*W!jHi`wEg4M9#f2PLgk3hKGUopG3H;1aPwcg zKn?55pfDVex_95lrR`{PUH!VVz!YvtF453{zWS zjBgRT1-XdJ_AljDT2vGklx8Ybl9qIZ>zVg9U*)Lx0UK1RmqM9CpdLVeAOj8=w`MXAgXB{Aq@VnSqRHt=J-^h=uL=j~wS%O3enY30X+6`n} z?$XC0HeY5gHhzl6BVX-!L_(D{HRMyljGV7Z=6LP8gDSw4OSHHz&Db(EPx+ab7$^SY7OLPCpWnOo$jD|ou6Sp_naPz9KB`=DrfFaxfIF~`g2?q zek4L#rdx;V`8_?qoD0DP<(WYodOyd_mpoRHk|U6-b>s#}FQW9JjqQPfC%yafHk0Hj z_0dVB>9I{vh2CrRKIAD-`ewl;o7pt)ZM`~G;x%i8H!hr7u%8}}63I2cpJ8b@rl+4| zmJjVAW8$dLBUX1~C!>@v0yOZ;1I`(}C}}(utt(n6VmxC3cXa z!CsRp-|6t@aw@&qUN_nmj1PIbS}}HBnl|il&EdR$mL*7s1wJ?Rl3066Mc3qbdsT=tQOq~3f$O%UJ`N*Vh&jcECGwFHxPD#&jCC{%c5^E&5TRV}+bZz@XQX?hr zD7SHGNy&gns;8i@QQ<6L=}hW!rG1_D0*1k{AT2;fstS|UWghxW$U z9n4;ApXx1zQlF)E72#M>4{2Hsd}i@AJR7Wx`M>rd?(~@@q4R3V+S=NE*7WUZlb<2H z-=u_uq8SyF9*(Xay0U-`cD>|w{$2>GzUb!-dy0;+q}814e=s7RSE4#br+5V%rbiI2 z@$Pi{cZo3NT_sFBY>p>7?O~zCZY~E;S8p#JV}qB?nBff8yq3lL^6T4=`WsU%r%7;} z#aIV{-T1=#>UCyj&&DPbLc(KN z-d324x&-NEe99~WKgEFqF`$nYd{#3Q*8y|VjihGSlLJ>%;fIfvpAITxH52t=T7%e?Q@Zyskq*`#dqo1{d_TT#RhJ$TT?0DXF6@1r%BLxu;Vv3R z?!}7Dq1cbAryox>+8LV!fYxvXnU|Q~PeLO?et)342yD~0{8-s`k@tPq)UELui0k3o?L~I^xwlA2{1_?wIy%DNv|-}9BLr~b!o zvtR1`N%%n2sWhX&nfXT6zp2{UcASF$S3Z#aKRsbCmqdn@eNRp(60_LadG>s~io)Xu1@{eJ{~xX! Bwj=-m literal 0 HcmV?d00001 diff --git a/AntidoteTests/ReferenceImages_64/AntidoteTests.ChatIncomingFileCellSnapshotTest/testWaitingState_right-to-left@2x.png b/AntidoteTests/ReferenceImages_64/AntidoteTests.ChatIncomingFileCellSnapshotTest/testWaitingState_right-to-left@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..dd1ece8a00334f1f077d91949e5cf16d30881cb7 GIT binary patch literal 16451 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 HSUmY(;OFPz literal 0 HcmV?d00001 diff --git a/AntidoteTests/ReferenceImages_64/AntidoteTests.ChatIncomingTextCellSnapshotTest/testHugeMessage_normal@2x.png b/AntidoteTests/ReferenceImages_64/AntidoteTests.ChatIncomingTextCellSnapshotTest/testHugeMessage_normal@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..12961597a9b8c3b1c2147df3f6661abfcadca1e9 GIT binary patch literal 90942 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 literal 0 HcmV?d00001 diff --git a/AntidoteTests/ReferenceImages_64/AntidoteTests.ChatIncomingTextCellSnapshotTest/testMediumMessage_normal@2x.png b/AntidoteTests/ReferenceImages_64/AntidoteTests.ChatIncomingTextCellSnapshotTest/testMediumMessage_normal@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..ae015e24ee75a89c0354e94bb699b634b154ce83 GIT binary patch literal 8591 zcmd^k_ghm-*LDC8pg=%TDWS@tNf9IjLJcAyNJm5j1f)wRbVz6lA|)ssdKD0m-laDQ zz4scVlh8x2Z}dFR`~CF&0pIoIx+XJw&&<8ny4PNN&CCwfR9B+9#dr$<08lAEd#Vip z5c?C_*5sswe^Ujy6+%S>*H(H0DC%e0AY9yZdZrHt0Pb`CE=0=OfA11*GTA)UctNO% z3FY?>Oej46sR?cBq6GvO0g2jM`KjCsPom8ftN6PLENG*$(`%}I>xjgWJB~3e%rk1dYIIYVkD95TuM&Kv%PQmW&{T2@1w0_kqB0f@+90Ad<{!2f$q&AA)zR!7GQbq$PVbKSMt zI;Vrtd6kC|BJXf?Vxyw`ka|;p(m?SgmO;y;4-ZK!!ld8^I&)lc({kzd zH%EI7CVwPMoT78)@|3CN1OA<%3}&188?=(3oZM1%c(1eJHF-F_@YfWNe?-%Z8lC07 z^eY>ZdVv4H^VE<^8E__X&gcrb$9u!lH*dV76TmJB?DRkK3bB}qw}AgU?wJ-znNgXk zg;=sVc>q6cybQwoyfzpeDvmTP%q03f2393HD6Rz&=z%1Z$*1$*xX=G;HoMAnFWJt+ zlhkgSnkxPGu&W%RDezQP8NJry0NDMTp66WN-X!Q9N=AC%zk+ffQ(Xvx;uL076WBGi ziLX7bCWF2#vcxz@Qlqj`SbYX7WFyO^PC6tO;=GZ()b`rb+Pi7)&Q!z zgUvhqWLAC8GwM0n)B8#{PtBV7g-jOdU7UYwIc5!mpg{5}i`r4vvE)wGkNR2rSqUs# zFQ9S)(4qQeV=?!L^X?3ae7W*WNexJaD3K6A(*xRr*KT~nYDc|#Nq%y@+ajNuZ>b#A z!W0zwn{w*}(t{G~E8)NS-cYQlM)-Shj{-=;VyW)$2Gae;POk;C8N?@=a$%K)pG4As7^)!dh zQQXP3CWd3N<6lR_+`L~k6aVWEa}eLOr;a%J-<%6`d*F{PkuAV~I|gCVq~@ULX}v}H z^shHZ1>eyt=Qv^yO8o!&Z4iK}6Y{cR@0%0NGnHna-IW)llBAOVM`o10>O135>VQvN z3v*lGAa%^>hA9!nzx`461=dSyzu2N;VD^`br2n^xunv zUd)Xw_4EmCU9k9_F_fF4SiX6r$*e|rU@{R8Pgq%Gt}dR#yEm*(cC2#hqefm*+!u}a zqm=0_sG7#E_QL!7pm9}}�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 literal 0 HcmV?d00001 diff --git a/AntidoteTests/ReferenceImages_64/AntidoteTests.ChatIncomingTextCellSnapshotTest/testMediumMessage_right-to-left@2x.png b/AntidoteTests/ReferenceImages_64/AntidoteTests.ChatIncomingTextCellSnapshotTest/testMediumMessage_right-to-left@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..cbb5ea9cc55da18c8e1f03985f1c341e517f1727 GIT binary patch literal 8591 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 E05zc-f&c&j literal 0 HcmV?d00001 diff --git a/AntidoteTests/ReferenceImages_64/AntidoteTests.ChatIncomingTextCellSnapshotTest/testSmallMessage_normal@2x.png b/AntidoteTests/ReferenceImages_64/AntidoteTests.ChatIncomingTextCellSnapshotTest/testSmallMessage_normal@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..4496e56cdaff6c84a623c6ce9fbfa36f85853671 GIT binary patch literal 2793 zcmd5;i#t?X8{ab_#wEEwVYn{r%qku9fO&Z!L@X1pxqn ztPRc*4*>84;rN`Sgz)Zdb@Yp{gN5R)j{&sK?Nh=BDH6^#6aZAvKN`#izlSG$xjn$r zfgtSR!uI1b6t=x!FC2?^m+!wN{4SnnV|kPi37cg%1#WlVzL|G}gI0}McC7RY+TSAa z=7>htDfxAj60vk|;x5bRg(B;tRxxin(mc$>_IunOS2wp2+lqE3qjL`MqiE(2#NHhs1a>NqKc_0sw>m^9H(fEZr38_By4R$QMj{ zV6^F9y`N-md3nF-oLg&jl0a)hYC?KKP0mv`jPQ2IClsXyM!|^{dupALHscI1cIt5Q zi^m*YN-OSdmFV&(o9Kw{Hf^T5c3rF`#_X-|bn+b4Y?IQWP;QaN{@L?b^Zt>Zw!?FkDm$R(u| z9uxD)f3YVr0)uNA8Qr?(=56Nf_WOs+_8{Z9-;2I;M{BgNtNkhGJMnhoDAM!V;=Qw= z7+59B#tYACVqKooWG*U09_h!Qye)!;JE`ur!<`c>xRK1-bmxi_@$NKQB;#RaNz@({ zu5r8;c?8)Scm`L}j`J4*!rH>qszz$3G_!mRs8M*33T%-gg;ZFd$UG5r=>JBSf;9Z|g?-8wIujj~3cAwYAQAZs}CPu|_5GPWSzHMeB zwaqV^)lh^-{+nGEv(N|pZ9y~1YSqZ4y1KXv$ZKl!=;3(Yxr&EqP&aiLCHB;)D&WsZ zzG4mUE4GAq2&9}?%}r{2XhoemNSZ-YHADv8ffRNVr`K>PvQS*u&!jqS2R#*)V{2xX zvpL4naZYKR-gg93$W?{-*Y%!;fXM}nbYc^AK(WLG`a+~kkG~`)j_IzR)JwD@I&q*r2bWURQ#%jh>0n6zvKf0<##=jH_*FIQX$jT8`A1|?w80KAX&iHs5Z7X4Al z8r1rn&P^ZQ+Be30yDH5?&+{}>+RjzXe@si4&|wbbhWItR!!PAV5flY#N>bDeqG;! z(cM^$aRFwR5fH82rj*P?w~?+h5-hrrQP2RR4KEK7E=?)ETROJ@_foC8zXhUHjPjg9 zn+kz@U2W@yL@pA}Y@*FA{JM#w>KX5ZiU0EY^K$dMjJQpMEyubyi~LoZ!NWGW_kHq_ zU^!scXGyB0IxVlh;prWXW{+4nssEHL3RR&Lm7KFf3()UBc<_{HO?9-$JKW3m5w=_u z9}6$_R`&AAjF^J}CUn7v|1rJ)c!h4eVC8tXK5T!#f)Qw26ezNFkYJUKH;>I4t*_N- zQ6v-GE8y#(;_isQqyb=K!_YC=6#>Kk77>{p4aF7P*cyFPD-0E_a?ozRtvaDr_y$T75=hx^%Y{-8Cc~A+ZEF25QRXgaJL5D z(5b&Df_eR1e7H%k{|PY2ozn#cR?o$ju?A?nfwLp{bddlsI2+F8WKW+0X2T=0!IF9N zq`EUFa9}G?74)zb!gY}nPO=Nr1;QDocHrOeO7o^RuVzLvVTevR17WGfn$}Sds{jmk zK3L5peHC%atG16bgPaUC!6=sYIr@<7jGPMR&O?BoN)Z;V^0g0S5wxEBjwt;ENJbDA z$IBjYvd?Ev_LeY)AwU=4&TO{_h?D64RQ;htRzCq0!uua%^!C+JbI{M1rf7%$8@y5B z&XOPVrSx}J1zr0Y8AhB|(s$)nBC*W%p56Zdx`eonPb$7OeN}ebmrcCQpnI)F4y61@!bjcd_Kb?N?6aQ~`L6=`OqW%CWk{?WDwY9aG#PS#B@rk3Fp?~u4H>=duKwG_x zMNv-2`wI$rw$C&>k6h2MM1T^oRK$zJLOpDYh`~3;W7FQ8hDu%XZc*DOTAPecd^r)_b+~O zZ-FS|2GuC5=249Aemx;<=0tGBoRJQgI}&>;zqj06tqNg$9cl8;|43qsVIY$j2>4xa!pxj;!l0U^f!X{RhD4c=yp$m4bm2DJ&o6DVL~ LWp7D4=9Tz2bzcm4 literal 0 HcmV?d00001 diff --git a/AntidoteTests/ReferenceImages_64/AntidoteTests.ChatIncomingTextCellSnapshotTest/testSmallMessage_right-to-left@2x.png b/AntidoteTests/ReferenceImages_64/AntidoteTests.ChatIncomingTextCellSnapshotTest/testSmallMessage_right-to-left@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..0e09fb10d999649ac1eece561687e054d8a3675b GIT binary patch literal 2769 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 ZApXwzrD#|dW2QS3#OS7BsexnUe*kQSJ_G;& literal 0 HcmV?d00001 diff --git a/AntidoteTests/ReferenceImages_64/AntidoteTests.ChatListCellSnapshotTest/testDefault_normal@2x.png b/AntidoteTests/ReferenceImages_64/AntidoteTests.ChatListCellSnapshotTest/testDefault_normal@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..7cae63984c0bc5e2cb65e9f857384e132b4b9c5c GIT binary patch literal 12582 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 literal 0 HcmV?d00001 diff --git a/AntidoteTests/ReferenceImages_64/AntidoteTests.ChatListCellSnapshotTest/testLongMessage_normal@2x.png b/AntidoteTests/ReferenceImages_64/AntidoteTests.ChatListCellSnapshotTest/testLongMessage_normal@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..9f9b9d9a8596e38c31dfac4a13c7479798da6a6d GIT binary patch literal 15382 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 JiIhp;{|7L*jMo4F literal 0 HcmV?d00001 diff --git a/AntidoteTests/ReferenceImages_64/AntidoteTests.ChatListCellSnapshotTest/testLongMessage_right-to-left@2x.png b/AntidoteTests/ReferenceImages_64/AntidoteTests.ChatListCellSnapshotTest/testLongMessage_right-to-left@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..5057f3734755fae496496575bf83853bf9e2c41d GIT binary patch literal 14536 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 literal 0 HcmV?d00001 diff --git a/AntidoteTests/ReferenceImages_64/AntidoteTests.ChatListCellSnapshotTest/testUnread_right-to-left@2x.png b/AntidoteTests/ReferenceImages_64/AntidoteTests.ChatListCellSnapshotTest/testUnread_right-to-left@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..0cd56c5b245089a83dc358d56428bf505e7542c2 GIT binary patch literal 12722 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