├── .gitattributes ├── .github └── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── .gitignore ├── LICENSE ├── Localizations ├── en.xcloc │ ├── Localized Contents │ │ └── en.xliff │ ├── Source Contents │ │ ├── Pods │ │ │ └── en.lproj │ │ │ │ └── Localizable.strings │ │ ├── Tinodios │ │ │ ├── Base.lproj │ │ │ │ └── Main.storyboard │ │ │ ├── Settings.bundle │ │ │ │ └── en.lproj │ │ │ │ │ ├── ConnectionSettings.strings │ │ │ │ │ └── Root.strings │ │ │ ├── Supporting Files │ │ │ │ └── Base.lproj │ │ │ │ │ └── LaunchScreen.storyboard │ │ │ ├── en.lproj │ │ │ │ └── InfoPlist.strings │ │ │ └── widgets │ │ │ │ └── Base.lproj │ │ │ │ ├── MultilineAlertView.xib │ │ │ │ └── TagsEditDialogView.xib │ │ ├── TinodiosNSExtension │ │ │ └── en.lproj │ │ │ │ ├── InfoPlist.strings │ │ │ │ └── Localizable.strings │ │ └── en.lproj │ │ │ └── Localizable.strings │ └── contents.json ├── es.xcloc │ ├── Localized Contents │ │ └── es.xliff │ ├── Source Contents │ │ ├── Pods │ │ │ └── en.lproj │ │ │ │ └── Localizable.strings │ │ ├── Tinodios │ │ │ ├── Base.lproj │ │ │ │ └── Main.storyboard │ │ │ ├── Settings.bundle │ │ │ │ └── en.lproj │ │ │ │ │ ├── ConnectionSettings.strings │ │ │ │ │ └── Root.strings │ │ │ ├── Supporting Files │ │ │ │ └── Base.lproj │ │ │ │ │ └── LaunchScreen.storyboard │ │ │ ├── en.lproj │ │ │ │ └── InfoPlist.strings │ │ │ └── widgets │ │ │ │ └── Base.lproj │ │ │ │ ├── MultilineAlertView.xib │ │ │ │ └── TagsEditDialogView.xib │ │ ├── TinodiosNSExtension │ │ │ └── en.lproj │ │ │ │ ├── InfoPlist.strings │ │ │ │ └── Localizable.strings │ │ └── en.lproj │ │ │ └── Localizable.strings │ └── contents.json ├── ru.xcloc │ ├── Localized Contents │ │ └── ru.xliff │ ├── Source Contents │ │ ├── Pods │ │ │ └── en.lproj │ │ │ │ └── Localizable.strings │ │ ├── Tinodios │ │ │ ├── Base.lproj │ │ │ │ └── Main.storyboard │ │ │ ├── Settings.bundle │ │ │ │ └── en.lproj │ │ │ │ │ ├── ConnectionSettings.strings │ │ │ │ │ └── Root.strings │ │ │ ├── Supporting Files │ │ │ │ └── Base.lproj │ │ │ │ │ └── LaunchScreen.storyboard │ │ │ ├── en.lproj │ │ │ │ └── InfoPlist.strings │ │ │ └── widgets │ │ │ │ └── Base.lproj │ │ │ │ ├── MultilineAlertView.xib │ │ │ │ └── TagsEditDialogView.xib │ │ ├── TinodiosNSExtension │ │ │ └── en.lproj │ │ │ │ ├── InfoPlist.strings │ │ │ │ └── Localizable.strings │ │ └── en.lproj │ │ │ └── Localizable.strings │ └── contents.json ├── uk.xcloc │ ├── Localized Contents │ │ └── uk.xliff │ ├── Source Contents │ │ ├── Tinodios │ │ │ ├── Base.lproj │ │ │ │ └── Main.storyboard │ │ │ ├── Settings.bundle │ │ │ │ └── en.lproj │ │ │ │ │ ├── ConnectionSettings.strings │ │ │ │ │ └── Root.strings │ │ │ ├── Supporting Files │ │ │ │ └── Base.lproj │ │ │ │ │ └── LaunchScreen.storyboard │ │ │ ├── en.lproj │ │ │ │ └── InfoPlist.strings │ │ │ └── widgets │ │ │ │ └── Base.lproj │ │ │ │ ├── MultilineAlertView.xib │ │ │ │ └── TagsEditDialogView.xib │ │ ├── TinodiosNSExtension │ │ │ └── en.lproj │ │ │ │ ├── InfoPlist.strings │ │ │ │ └── Localizable.strings │ │ └── en.lproj │ │ │ └── Localizable.strings │ └── contents.json ├── zh-Hans.xcloc │ ├── Localized Contents │ │ └── zh-Hans.xliff │ ├── Source Contents │ │ ├── Pods │ │ │ └── en.lproj │ │ │ │ └── Localizable.strings │ │ ├── Tinodios │ │ │ ├── Base.lproj │ │ │ │ └── Main.storyboard │ │ │ ├── Settings.bundle │ │ │ │ └── en.lproj │ │ │ │ │ ├── ConnectionSettings.strings │ │ │ │ │ └── Root.strings │ │ │ ├── Supporting Files │ │ │ │ └── Base.lproj │ │ │ │ │ └── LaunchScreen.storyboard │ │ │ ├── en.lproj │ │ │ │ └── InfoPlist.strings │ │ │ └── widgets │ │ │ │ └── Base.lproj │ │ │ │ ├── MultilineAlertView.xib │ │ │ │ └── TagsEditDialogView.xib │ │ ├── TinodiosNSExtension │ │ │ └── en.lproj │ │ │ │ ├── InfoPlist.strings │ │ │ │ └── Localizable.strings │ │ └── en.lproj │ │ │ └── Localizable.strings │ └── contents.json └── zh-Hant.xcloc │ ├── Localized Contents │ └── zh-Hant.xliff │ ├── Source Contents │ ├── Pods │ │ └── en.lproj │ │ │ └── Localizable.strings │ ├── Tinodios │ │ ├── Base.lproj │ │ │ └── Main.storyboard │ │ ├── Settings.bundle │ │ │ └── en.lproj │ │ │ │ ├── ConnectionSettings.strings │ │ │ │ └── Root.strings │ │ ├── Supporting Files │ │ │ └── Base.lproj │ │ │ │ └── LaunchScreen.storyboard │ │ ├── en.lproj │ │ │ └── InfoPlist.strings │ │ └── widgets │ │ │ └── Base.lproj │ │ │ ├── MultilineAlertView.xib │ │ │ └── TagsEditDialogView.xib │ ├── TinodiosNSExtension │ │ └── en.lproj │ │ │ ├── InfoPlist.strings │ │ │ └── Localizable.strings │ └── en.lproj │ │ └── Localizable.strings │ └── contents.json ├── Podfile ├── Podfile.lock ├── README.md ├── Scripts ├── set_build_number.sh └── set_default_preferences.sh ├── TinodeSDK.xcodeproj ├── project.pbxproj └── xcshareddata │ └── xcbaselines │ └── 0A56CCE122759078006E2952.xcbaseline │ ├── E5D25F8D-C9DB-4BEE-A6FF-37F703A10D97.plist │ └── Info.plist ├── TinodeSDK ├── AuthScheme.swift ├── ComTopic.swift ├── Connection.swift ├── FndTopic.swift ├── Info.plist ├── Log.swift ├── MeTopic.swift ├── PromisedReply.swift ├── RFC3339Format.swift ├── Storage.swift ├── Tinode.swift ├── TinodeSDK.h ├── Topic.swift ├── User.swift ├── WebSocket.swift └── model │ ├── Acs.swift │ ├── AcsHelper.swift │ ├── ClientMessages.swift │ ├── Defacs.swift │ ├── Description.swift │ ├── Drafty.swift │ ├── JSONValue.swift │ ├── MsgRange.swift │ ├── ServerMessages.swift │ ├── Subscription.swift │ ├── TheCard.swift │ └── Types.swift ├── TinodeSDKTests ├── DraftyTest.swift ├── Info.plist └── TinodeSDKTests.swift ├── Tinodios.xcodeproj ├── project.pbxproj └── xcshareddata │ └── xcschemes │ └── Tinodios.xcscheme ├── Tinodios.xcworkspace ├── contents.xcworkspacedata └── xcshareddata │ ├── IDEWorkspaceChecks.plist │ └── WorkspaceSettings.xcsettings ├── Tinodios ├── AccountSettingsViewController.swift ├── AddByIDViewController.swift ├── AppDelegate.swift ├── ArchivedChatsTableViewController.swift ├── Base.lproj │ └── Main.storyboard ├── BlockedContactsTableViewController.swift ├── BrandingViewController.swift ├── Cache.swift ├── CallManager.swift ├── CallProviderDelegate.swift ├── CallViewController.swift ├── ChatListInteractor.swift ├── ChatListPresenter.swift ├── ChatListRouter.swift ├── ChatListViewController.swift ├── CredentialsChangeViewController.swift ├── CredentialsViewController.swift ├── EditMembersViewController.swift ├── FilePreviewController.swift ├── FindInteractor.swift ├── FindPresenter.swift ├── FindViewController.swift ├── ForwardToViewController.swift ├── ImagePreviewController.swift ├── Info.plist ├── KeyboardInfo.swift ├── LargeFileHelper.swift ├── LoginViewController.swift ├── MediaRecorder.swift ├── MessageBubbleDecorator.swift ├── MessageCell+VLCMediaPlayerDelegate.swift ├── MessageCell.swift ├── MessageInteractor.swift ├── MessagePresenter.swift ├── MessageView.swift ├── MessageViewController+Keyboard.swift ├── MessageViewController+MessageCellDelegate.swift ├── MessageViewController+SendMessageBarDelegate.swift ├── MessageViewController.swift ├── MessageViewLayout.swift ├── NewChatTabController.swift ├── NewGroupViewController.swift ├── QRScanner.swift ├── RecordedMediaPlayback.swift ├── ResetPasswordViewController.swift ├── Settings.bundle │ ├── Acknowledgements.plist │ ├── ConnectionSettings.plist │ ├── Root.plist │ ├── en.lproj │ │ ├── ConnectionSettings.strings │ │ └── Root.strings │ ├── es.lproj │ │ ├── ConnectionSettings.strings │ │ └── Root.strings │ ├── ru.lproj │ │ ├── ConnectionSettings.strings │ │ └── Root.strings │ ├── uk.lproj │ │ ├── ConnectionSettings.strings │ │ └── Root.strings │ ├── zh-Hans.lproj │ │ ├── ConnectionSettings.strings │ │ └── Root.strings │ └── zh-Hant.lproj │ │ ├── ConnectionSettings.strings │ │ └── Root.strings ├── SettingsHelpViewController.swift ├── SettingsNotificationsViewController.swift ├── SettingsPersonalViewController.swift ├── SettingsSecurityViewController.swift ├── SignupViewController.swift ├── Supporting Files │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── ios-logo-1024-1024.png │ │ │ ├── ios-logo-1024-20.png │ │ │ ├── ios-logo-1024-20@2x.png │ │ │ ├── ios-logo-1024-20@3x.png │ │ │ ├── ios-logo-1024-29.png │ │ │ ├── ios-logo-1024-29@2x.png │ │ │ ├── ios-logo-1024-29@3x.png │ │ │ ├── ios-logo-1024-40.png │ │ │ ├── ios-logo-1024-40@2x.png │ │ │ ├── ios-logo-1024-40@3x.png │ │ │ ├── ios-logo-1024-60@2x.png │ │ │ ├── ios-logo-1024-60@3x.png │ │ │ ├── ios-logo-1024-76.png │ │ │ ├── ios-logo-1024-76@2x.png │ │ │ └── ios-logo-1024-83.5@2x.png │ │ ├── Contents.json │ │ ├── Offline.colorset │ │ │ └── Contents.json │ │ ├── Online.colorset │ │ │ └── Contents.json │ │ ├── bell.badge.symbolset │ │ │ ├── Contents.json │ │ │ └── bell.badge.svg │ │ ├── broken-image.imageset │ │ │ ├── Contents.json │ │ │ ├── broken-image.png │ │ │ ├── broken-image@2x.png │ │ │ └── broken-image@3x.png │ │ ├── checkerboard.shield.symbolset │ │ │ ├── Contents.json │ │ │ └── checkerboard.shield.svg │ │ ├── done-30.imageset │ │ │ ├── Contents.json │ │ │ ├── done-30.png │ │ │ ├── done-30@2x.png │ │ │ └── done-30@3x.png │ │ ├── done-all-30.imageset │ │ │ ├── Contents.json │ │ │ ├── done-all-30.png │ │ │ ├── done-all-30@2x.png │ │ │ └── done-all-30@3x.png │ │ ├── exclamationmark.triangle.symbolset │ │ │ ├── Contents.json │ │ │ └── exclamationmark.triangle.svg │ │ ├── eye-30.imageset │ │ │ ├── Contents.json │ │ │ ├── eye-30.png │ │ │ ├── eye-30@2x.png │ │ │ └── eye-30@3x.png │ │ ├── file-audio-125.imageset │ │ │ ├── Contents.json │ │ │ ├── file-audio-125.png │ │ │ ├── file-audio-125@2x.png │ │ │ └── file-audio-125@3x.png │ │ ├── file-image-125.imageset │ │ │ ├── Contents.json │ │ │ ├── file-image-125.png │ │ │ ├── file-image-125@2x.png │ │ │ └── file-image-125@3x.png │ │ ├── file-text-125.imageset │ │ │ ├── Contents.json │ │ │ ├── file-text-125.png │ │ │ ├── file-text-125@2x.png │ │ │ └── file-text-125@3x.png │ │ ├── file-video-125.imageset │ │ │ ├── Contents.json │ │ │ ├── file-video-125.png │ │ │ ├── file-video-125@2x.png │ │ │ └── file-video-125@3x.png │ │ ├── file.symbolset │ │ │ ├── Contents.json │ │ │ └── doc.svg │ │ ├── image-wait.imageset │ │ │ ├── Contents.json │ │ │ ├── ios-image-wait.png │ │ │ ├── ios-image-wait@2x.png │ │ │ └── ios-image-wait@3x.png │ │ ├── important.symbolset │ │ │ ├── Contents.json │ │ │ └── exclamationmark.circle.svg │ │ ├── in-progress-30.imageset │ │ │ ├── Contents.json │ │ │ ├── in-progress-30.png │ │ │ ├── in-progress-30@2x.png │ │ │ └── in-progress-30@3x.png │ │ ├── info.symbolset │ │ │ ├── Contents.json │ │ │ └── info.circle.svg │ │ ├── invisible-30.imageset │ │ │ ├── Contents.json │ │ │ ├── invisible-30.png │ │ │ ├── invisible-30@2x.png │ │ │ └── invisible-30@3x.png │ │ ├── logo-ios.imageset │ │ │ ├── Contents.json │ │ │ ├── logo-ios.png │ │ │ ├── logo-ios@2x.png │ │ │ └── logo-ios@3x.png │ │ ├── paperclip.symbolset │ │ │ ├── Contents.json │ │ │ └── paperclip.svg │ │ ├── pause.circle.symbolset │ │ │ ├── Contents.json │ │ │ └── pause.circle.svg │ │ ├── play.circle.fill.symbolset │ │ │ ├── Contents.json │ │ │ └── play.circle.fill.svg │ │ ├── play.fill.symbolset │ │ │ ├── Contents.json │ │ │ └── play.fill.svg │ │ ├── puzzlepiece.extension.symbolset │ │ │ ├── Contents.json │ │ │ └── puzzlepiece.extension.svg │ │ ├── rectangle.3.group.symbolset │ │ │ ├── Contents.json │ │ │ └── rectangle.3.group.svg │ │ ├── rectangle.portrait.and.arrow.right.symbolset │ │ │ ├── Contents.json │ │ │ └── rectangle.portrait.and.arrow.right.svg │ │ ├── speaker.wave.3.fill.symbolset │ │ │ ├── Contents.json │ │ │ └── speaker.wave.3.fill.svg │ │ ├── stop.circle.symbolset │ │ │ ├── Contents.json │ │ │ └── stop.circle.svg │ │ ├── vc.fill.imageset │ │ │ ├── Contents.json │ │ │ └── vc.fill.svg │ │ ├── vc.slash.fill.imageset │ │ │ ├── Contents.json │ │ │ └── vc.slash.fill.svg │ │ ├── xmark.bin.fill.symbolset │ │ │ ├── Contents.json │ │ │ └── xmark.bin.fill.svg │ │ ├── xmark.bin.symbolset │ │ │ ├── Contents.json │ │ │ └── xmark.bin.svg │ │ └── xmark.bubble.symbolset │ │ │ ├── Contents.json │ │ │ └── xmark.bubble.svg │ ├── Base.lproj │ │ └── LaunchScreen.storyboard │ ├── es.lproj │ │ └── LaunchScreen.strings │ ├── ru.lproj │ │ └── LaunchScreen.strings │ ├── uk.lproj │ │ └── LaunchScreen.strings │ ├── zh-Hans.lproj │ │ └── LaunchScreen.strings │ └── zh-Hant.lproj │ │ └── LaunchScreen.strings ├── Tinodios.entitlements ├── TopicGeneralViewController.swift ├── TopicInfoViewController.swift ├── TopicSecurityViewController.swift ├── UiUtils.swift ├── Utils.swift ├── VideoPreviewController.swift ├── account │ ├── ContactsManager.swift │ └── ContactsSynchronizer.swift ├── en.lproj │ └── Main.strings ├── es.lproj │ ├── InfoPlist.strings │ └── Main.strings ├── format │ ├── AbstractFormatter.swift │ ├── AsyncImageTextAttachment.swift │ ├── ButtonAttachment.swift │ ├── EntityTextAttachment.swift │ ├── FormatNode.swift │ ├── FullFormatter.swift │ ├── MultiImageTextAttachment.swift │ ├── PreviewFormatter.swift │ ├── QuoteFormatter.swift │ ├── QuotedAttachment.swift │ ├── SendForwardedFormatter.swift │ ├── SendReplyFormatter.swift │ ├── ThumbnailTransformer.swift │ └── WaveTextAttachment.swift ├── ru.lproj │ ├── InfoPlist.strings │ └── Main.strings ├── uk.lproj │ ├── InfoPlist.strings │ └── Main.strings ├── widgets │ ├── AvatarWithOnlineIndicator+TypingAnimation.swift │ ├── AvatarWithOnlineIndicator.swift │ ├── AvatarWithOnlineIndicator.xib │ ├── Base.lproj │ │ ├── MultilineAlertView.xib │ │ └── TagsEditDialogView.xib │ ├── ChatListViewCell.swift │ ├── ChatListViewCell.xib │ ├── ContactViewCell.swift │ ├── ContactViewCell.xib │ ├── ForwardMessageBar.swift │ ├── ForwardMessageBar.xib │ ├── ImagePicker.swift │ ├── MessageMenuItem.swift │ ├── MultilineAlertView.swift │ ├── PaddedLabel.swift │ ├── PermissionsEditView.xib │ ├── PermissionsEditViewController.swift │ ├── PlaceholderTextView.swift │ ├── ProgressView.swift │ ├── ProgressView.xib │ ├── RichTextView.swift │ ├── RoundImageView.swift │ ├── SelectedMemberViewCell.swift │ ├── SelectedMemberViewCell.xib │ ├── SendImageBar.swift │ ├── SendImageBar.xib │ ├── SendMessageBar.swift │ ├── SendMessageBar.xib │ ├── TagsEditDialogView.swift │ ├── TagsEditView.swift │ ├── ValidatedCredential.swift │ ├── WaveImage.swift │ ├── WaveImageView.swift │ ├── es.lproj │ │ ├── MultilineAlertView.strings │ │ └── TagsEditDialogView.strings │ ├── ru.lproj │ │ ├── MultilineAlertView.strings │ │ └── TagsEditDialogView.strings │ ├── uk.lproj │ │ ├── MultilineAlertView.strings │ │ └── TagsEditDialogView.strings │ ├── zh-Hans.lproj │ │ ├── MultilineAlertView.strings │ │ └── TagsEditDialogView.strings │ └── zh-Hant.lproj │ │ ├── MultilineAlertView.strings │ │ └── TagsEditDialogView.strings ├── zh-Hans.lproj │ ├── InfoPlist.strings │ └── Main.strings └── zh-Hant.lproj │ ├── InfoPlist.strings │ └── Main.strings ├── TinodiosDB.xcodeproj └── project.pbxproj ├── TinodiosDB ├── AccountDb.swift ├── BaseDb.swift ├── ConnectionSettingsHelper.swift ├── Info.plist ├── MessageDb.swift ├── SharedUtils.swift ├── SqlStore.swift ├── StoredMessage.swift ├── SubscriberDb.swift ├── TinodiosDB.h ├── TopicDb.swift └── UserDb.swift ├── TinodiosNSExtension ├── Info.plist ├── NotificationService.swift ├── TinodiosNSExtension.entitlements ├── es.lproj │ └── Localizable.strings ├── ru.lproj │ └── Localizable.strings ├── uk.lproj │ └── Localizable.strings ├── zh-Hans.lproj │ └── Localizable.strings └── zh-Hant.lproj │ └── Localizable.strings ├── TinodiosUITests ├── TinodiosUITests.entitlements ├── TinodiosUITests.swift └── TinodiosUITestsLaunchTests.swift ├── app-store.svg ├── call-end.m4a ├── call-out.m4a ├── devel.xcconfig ├── dialing.m4a ├── en.lproj └── Localizable.strings ├── es.lproj └── Localizable.strings ├── ios-acc-personal.png ├── ios-chat.png ├── ios-contacts.png ├── ios-find-people.png ├── ios-forward-to.png ├── ios-video-call.png ├── prod.xcconfig ├── ru.lproj └── Localizable.strings ├── uk.lproj └── Localizable.strings ├── zh-Hans.lproj └── Localizable.strings └── zh-Hant.lproj └── Localizable.strings /.gitattributes: -------------------------------------------------------------------------------- 1 | Pods/MobileVLCKit/MobileVLCKit.xcframework/ios-arm64_i386_x86_64-simulator/MobileVLCKit.framework/MobileVLCKit filter=lfs diff=lfs merge=lfs -text 2 | Pods/MobileVLCKit/MobileVLCKit.xcframework/ios-arm64_armv7_armv7s/MobileVLCKit.framework/MobileVLCKit filter=lfs diff=lfs merge=lfs -text 3 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve Tinode 4 | title: '' 5 | labels: 'bug' 6 | assignees: '' 7 | 8 | --- 9 | ## If you are not reporting a bug, please post to https://groups.google.com/d/forum/tinode instead. 10 | 11 | **Describe the bug** 12 | A clear and concise description of what the bug is. 13 | 14 | **To Reproduce** 15 | Steps to reproduce the behavior: 16 | 1. Go to '...' 17 | 2. Click on '....' 18 | 3. Scroll down to '....' 19 | 4. See error 20 | 21 | **Expected behavior** 22 | A clear and concise description of what you expected to happen. 23 | 24 | **Screenshots** 25 | If applicable, add screenshots to help explain your problem. 26 | 27 | **Tinodios (please complete the following information):** 28 | - Version [e.g. 0.16.3-rc2] 29 | - Device [e.g. Simulator or iPhone 8] 30 | - iOS version, [e.g. 13.2.3 (17B111)] 31 | 32 | **Server** 33 | - Type [e.g. api.tinode.co or your own setup] 34 | - Server type [unmodified or customized] 35 | - Server version [e.g. 0.16.3-rc2] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | Attach server-side and client-side logs. 40 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | ## If you are not requesting a feature, please post to https://groups.google.com/d/forum/tinode instead. 10 | 11 | **Is your feature request related to a problem? Please describe.** 12 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 13 | 14 | **Describe the solution you'd like** 15 | A clear and concise description of what you want to happen. 16 | 17 | **Describe alternatives you've considered** 18 | A clear and concise description of any alternative solutions or features you've considered. 19 | 20 | **Additional context** 21 | Add any other context or screenshots about the feature request here. 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata 19 | *.developerprofile 20 | 21 | ## Other 22 | *.moved-aside 23 | *.xccheckout 24 | *.xcscmblueprint 25 | GoogleService-Info.plist 26 | Tinodios/GoogleService-Info-Development.plist 27 | Tinodios/GoogleService-Info-Production.plist 28 | 29 | ## Obj-C/Swift specific 30 | *.hmap 31 | *.ipa 32 | *.dSYM.zip 33 | *.dSYM 34 | 35 | ## Playgrounds 36 | timeline.xctimeline 37 | playground.xcworkspace 38 | 39 | # Swift Package Manager 40 | # 41 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 42 | # Packages/ 43 | # Package.pins 44 | # Package.resolved 45 | .build/ 46 | 47 | # CocoaPods 48 | # 49 | # We recommend against adding the Pods directory to your .gitignore. However 50 | # you should judge for yourself, the pros and cons are mentioned at: 51 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 52 | # 53 | Pods/ 54 | 55 | # Add this line if you want to avoid checking in source code from the Xcode workspace 56 | # *.xcworkspace 57 | 58 | # Carthage 59 | # 60 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 61 | # Carthage/Checkouts 62 | 63 | Carthage/Build 64 | 65 | # fastlane 66 | # 67 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 68 | # screenshots whenever they are needed. 69 | # For more information about the recommended setup visit: 70 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 71 | 72 | fastlane/report.xml 73 | fastlane/Preview.html 74 | fastlane/screenshots/**/*.png 75 | fastlane/test_output 76 | 77 | # Code Injection 78 | # 79 | # After new code Injection tools there's a generated folder /iOSInjectionProject 80 | # https://github.com/johnno1962/injectionforxcode 81 | 82 | iOSInjectionProject/ 83 | .DS_Store 84 | -------------------------------------------------------------------------------- /Localizations/en.xcloc/Source Contents/Pods/en.lproj/Localizable.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Localizations/en.xcloc/Source Contents/Pods/en.lproj/Localizable.strings -------------------------------------------------------------------------------- /Localizations/en.xcloc/Source Contents/Tinodios/Settings.bundle/en.lproj/ConnectionSettings.strings: -------------------------------------------------------------------------------- 1 | /* A single strings file, whose title is specified in your preferences schema. The strings files provide the localized content to display to the user for each of your preferences. */ 2 | 3 | "Wire transport" = "Wire transport"; 4 | "Host name" = "Host name"; 5 | "Use TLS" = "Use TLS"; 6 | -------------------------------------------------------------------------------- /Localizations/en.xcloc/Source Contents/Tinodios/Settings.bundle/en.lproj/Root.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Localizations/en.xcloc/Source Contents/Tinodios/Settings.bundle/en.lproj/Root.strings -------------------------------------------------------------------------------- /Localizations/en.xcloc/Source Contents/Tinodios/Supporting Files/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /Localizations/en.xcloc/Source Contents/Tinodios/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Bundle display name */ 2 | "CFBundleDisplayName" = "Tinode"; 3 | /* Bundle name */ 4 | "CFBundleName" = "Tinodios"; 5 | /* Privacy - Camera Usage Description */ 6 | "NSCameraUsageDescription" = "Tinode takes photos with the camera to use as avatar or to send them to your contacts"; 7 | /* Privacy - Contacts Usage Description */ 8 | "NSContactsUsageDescription" = "Tinode sends only emails and phone numbers to the Tinode server to help you connect with other users"; 9 | /* Privacy - Microphone Usage Description */ 10 | "NSMicrophoneUsageDescription" = "Tinode uses microphone to record audio messages you send to your contacts"; 11 | /* Privacy - Photo Library Additions Usage Description */ 12 | "NSPhotoLibraryAddUsageDescription" = "Images and pictures from Tinode can be saved in the photo library"; 13 | /* Privacy - Photo Library Usage Description */ 14 | "NSPhotoLibraryUsageDescription" = "Tinode needs access to your photos to let you you send them to your contacts"; 15 | -------------------------------------------------------------------------------- /Localizations/en.xcloc/Source Contents/TinodiosNSExtension/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Bundle display name */ 2 | "CFBundleDisplayName" = "TinodiosNSExtension"; 3 | /* Bundle name */ 4 | "CFBundleName" = "TinodiosNSExtension"; 5 | -------------------------------------------------------------------------------- /Localizations/en.xcloc/Source Contents/TinodiosNSExtension/en.lproj/Localizable.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Localizations/en.xcloc/Source Contents/TinodiosNSExtension/en.lproj/Localizable.strings -------------------------------------------------------------------------------- /Localizations/en.xcloc/contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "developmentRegion" : "en", 3 | "targetLocale" : "en", 4 | "toolInfo" : { 5 | "toolBuildNumber" : "15C500b", 6 | "toolID" : "com.apple.dt.xcode", 7 | "toolName" : "Xcode", 8 | "toolVersion" : "15.2" 9 | }, 10 | "version" : "1.0", 11 | "workspace" : "Tinodios.xcworkspace" 12 | } -------------------------------------------------------------------------------- /Localizations/es.xcloc/Source Contents/Pods/en.lproj/Localizable.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Localizations/es.xcloc/Source Contents/Pods/en.lproj/Localizable.strings -------------------------------------------------------------------------------- /Localizations/es.xcloc/Source Contents/Tinodios/Settings.bundle/en.lproj/ConnectionSettings.strings: -------------------------------------------------------------------------------- 1 | /* A single strings file, whose title is specified in your preferences schema. The strings files provide the localized content to display to the user for each of your preferences. */ 2 | 3 | "Wire transport" = "Wire transport"; 4 | "Host name" = "Host name"; 5 | "Use TLS" = "Use TLS"; 6 | -------------------------------------------------------------------------------- /Localizations/es.xcloc/Source Contents/Tinodios/Settings.bundle/en.lproj/Root.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Localizations/es.xcloc/Source Contents/Tinodios/Settings.bundle/en.lproj/Root.strings -------------------------------------------------------------------------------- /Localizations/es.xcloc/Source Contents/Tinodios/Supporting Files/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /Localizations/es.xcloc/Source Contents/Tinodios/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Bundle display name */ 2 | "CFBundleDisplayName" = "Tinode"; 3 | /* Bundle name */ 4 | "CFBundleName" = "Tinodios"; 5 | /* Privacy - Camera Usage Description */ 6 | "NSCameraUsageDescription" = "Tinode takes photos with the camera to use as avatar or to send them to your contacts"; 7 | /* Privacy - Contacts Usage Description */ 8 | "NSContactsUsageDescription" = "Tinode sends only emails and phone numbers to the Tinode server to help you connect with other users"; 9 | /* Privacy - Microphone Usage Description */ 10 | "NSMicrophoneUsageDescription" = "Tinode uses microphone to record audio messages you send to your contacts"; 11 | /* Privacy - Photo Library Additions Usage Description */ 12 | "NSPhotoLibraryAddUsageDescription" = "Images and pictures from Tinode can be saved in the photo library"; 13 | /* Privacy - Photo Library Usage Description */ 14 | "NSPhotoLibraryUsageDescription" = "Tinode needs access to your photos to let you you send them to your contacts"; 15 | -------------------------------------------------------------------------------- /Localizations/es.xcloc/Source Contents/TinodiosNSExtension/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Bundle display name */ 2 | "CFBundleDisplayName" = "TinodiosNSExtension"; 3 | /* Bundle name */ 4 | "CFBundleName" = "TinodiosNSExtension"; 5 | -------------------------------------------------------------------------------- /Localizations/es.xcloc/Source Contents/TinodiosNSExtension/en.lproj/Localizable.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Localizations/es.xcloc/Source Contents/TinodiosNSExtension/en.lproj/Localizable.strings -------------------------------------------------------------------------------- /Localizations/es.xcloc/contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "developmentRegion" : "en", 3 | "targetLocale" : "es", 4 | "toolInfo" : { 5 | "toolBuildNumber" : "15C500b", 6 | "toolID" : "com.apple.dt.xcode", 7 | "toolName" : "Xcode", 8 | "toolVersion" : "15.2" 9 | }, 10 | "version" : "1.0", 11 | "workspace" : "Tinodios.xcworkspace" 12 | } -------------------------------------------------------------------------------- /Localizations/ru.xcloc/Source Contents/Pods/en.lproj/Localizable.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Localizations/ru.xcloc/Source Contents/Pods/en.lproj/Localizable.strings -------------------------------------------------------------------------------- /Localizations/ru.xcloc/Source Contents/Tinodios/Settings.bundle/en.lproj/ConnectionSettings.strings: -------------------------------------------------------------------------------- 1 | /* A single strings file, whose title is specified in your preferences schema. The strings files provide the localized content to display to the user for each of your preferences. */ 2 | 3 | "Wire transport" = "Wire transport"; 4 | "Host name" = "Host name"; 5 | "Use TLS" = "Use TLS"; 6 | -------------------------------------------------------------------------------- /Localizations/ru.xcloc/Source Contents/Tinodios/Settings.bundle/en.lproj/Root.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Localizations/ru.xcloc/Source Contents/Tinodios/Settings.bundle/en.lproj/Root.strings -------------------------------------------------------------------------------- /Localizations/ru.xcloc/Source Contents/Tinodios/Supporting Files/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /Localizations/ru.xcloc/Source Contents/Tinodios/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Bundle display name */ 2 | "CFBundleDisplayName" = "Tinode"; 3 | /* Bundle name */ 4 | "CFBundleName" = "Tinodios"; 5 | /* Privacy - Camera Usage Description */ 6 | "NSCameraUsageDescription" = "Tinode takes photos with the camera to use as avatar or to send them to your contacts"; 7 | /* Privacy - Contacts Usage Description */ 8 | "NSContactsUsageDescription" = "Tinode sends only emails and phone numbers to the Tinode server to help you connect with other users"; 9 | /* Privacy - Microphone Usage Description */ 10 | "NSMicrophoneUsageDescription" = "Tinode uses microphone to record audio messages you send to your contacts"; 11 | /* Privacy - Photo Library Additions Usage Description */ 12 | "NSPhotoLibraryAddUsageDescription" = "Images and pictures from Tinode can be saved in the photo library"; 13 | /* Privacy - Photo Library Usage Description */ 14 | "NSPhotoLibraryUsageDescription" = "Tinode needs access to your photos to let you you send them to your contacts"; 15 | -------------------------------------------------------------------------------- /Localizations/ru.xcloc/Source Contents/TinodiosNSExtension/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Bundle display name */ 2 | "CFBundleDisplayName" = "TinodiosNSExtension"; 3 | /* Bundle name */ 4 | "CFBundleName" = "TinodiosNSExtension"; 5 | -------------------------------------------------------------------------------- /Localizations/ru.xcloc/Source Contents/TinodiosNSExtension/en.lproj/Localizable.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Localizations/ru.xcloc/Source Contents/TinodiosNSExtension/en.lproj/Localizable.strings -------------------------------------------------------------------------------- /Localizations/ru.xcloc/contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "developmentRegion" : "en", 3 | "targetLocale" : "ru", 4 | "toolInfo" : { 5 | "toolBuildNumber" : "15C500b", 6 | "toolID" : "com.apple.dt.xcode", 7 | "toolName" : "Xcode", 8 | "toolVersion" : "15.2" 9 | }, 10 | "version" : "1.0", 11 | "workspace" : "Tinodios.xcworkspace" 12 | } -------------------------------------------------------------------------------- /Localizations/uk.xcloc/Source Contents/Tinodios/Settings.bundle/en.lproj/ConnectionSettings.strings: -------------------------------------------------------------------------------- 1 | /* A single strings file, whose title is specified in your preferences schema. The strings files provide the localized content to display to the user for each of your preferences. */ 2 | 3 | "Wire transport" = "Wire transport"; 4 | "Host name" = "Host name"; 5 | "Use TLS" = "Use TLS"; 6 | -------------------------------------------------------------------------------- /Localizations/uk.xcloc/Source Contents/Tinodios/Settings.bundle/en.lproj/Root.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Localizations/uk.xcloc/Source Contents/Tinodios/Settings.bundle/en.lproj/Root.strings -------------------------------------------------------------------------------- /Localizations/uk.xcloc/Source Contents/Tinodios/Supporting Files/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /Localizations/uk.xcloc/Source Contents/Tinodios/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Bundle display name */ 2 | "CFBundleDisplayName" = "Tinode"; 3 | /* Bundle name */ 4 | "CFBundleName" = "Tinodios"; 5 | /* Privacy - Camera Usage Description */ 6 | "NSCameraUsageDescription" = "Tinode takes photos with the camera to use as avatar or to send them to your contacts"; 7 | /* Privacy - Contacts Usage Description */ 8 | "NSContactsUsageDescription" = "Tinode sends only emails and phone numbers to the Tinode server to help you connect with other users"; 9 | /* Privacy - Microphone Usage Description */ 10 | "NSMicrophoneUsageDescription" = "Tinode uses microphone to record audio messages you send to your contacts"; 11 | /* Privacy - Photo Library Additions Usage Description */ 12 | "NSPhotoLibraryAddUsageDescription" = "Images and pictures from Tinode can be saved in the photo library"; 13 | /* Privacy - Photo Library Usage Description */ 14 | "NSPhotoLibraryUsageDescription" = "Tinode needs access to your photos to let you you send them to your contacts"; 15 | -------------------------------------------------------------------------------- /Localizations/uk.xcloc/Source Contents/TinodiosNSExtension/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Bundle display name */ 2 | "CFBundleDisplayName" = "TinodiosNSExtension"; 3 | /* Bundle name */ 4 | "CFBundleName" = "TinodiosNSExtension"; 5 | -------------------------------------------------------------------------------- /Localizations/uk.xcloc/Source Contents/TinodiosNSExtension/en.lproj/Localizable.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Localizations/uk.xcloc/Source Contents/TinodiosNSExtension/en.lproj/Localizable.strings -------------------------------------------------------------------------------- /Localizations/uk.xcloc/contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "developmentRegion" : "en", 3 | "targetLocale" : "uk", 4 | "toolInfo" : { 5 | "toolBuildNumber" : "15C500b", 6 | "toolID" : "com.apple.dt.xcode", 7 | "toolName" : "Xcode", 8 | "toolVersion" : "15.2" 9 | }, 10 | "version" : "1.0", 11 | "workspace" : "Tinodios.xcworkspace" 12 | } -------------------------------------------------------------------------------- /Localizations/zh-Hans.xcloc/Source Contents/Pods/en.lproj/Localizable.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Localizations/zh-Hans.xcloc/Source Contents/Pods/en.lproj/Localizable.strings -------------------------------------------------------------------------------- /Localizations/zh-Hans.xcloc/Source Contents/Tinodios/Settings.bundle/en.lproj/ConnectionSettings.strings: -------------------------------------------------------------------------------- 1 | /* A single strings file, whose title is specified in your preferences schema. The strings files provide the localized content to display to the user for each of your preferences. */ 2 | 3 | "Wire transport" = "Wire transport"; 4 | "Host name" = "Host name"; 5 | "Use TLS" = "Use TLS"; 6 | -------------------------------------------------------------------------------- /Localizations/zh-Hans.xcloc/Source Contents/Tinodios/Settings.bundle/en.lproj/Root.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Localizations/zh-Hans.xcloc/Source Contents/Tinodios/Settings.bundle/en.lproj/Root.strings -------------------------------------------------------------------------------- /Localizations/zh-Hans.xcloc/Source Contents/Tinodios/Supporting Files/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /Localizations/zh-Hans.xcloc/Source Contents/Tinodios/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Bundle display name */ 2 | "CFBundleDisplayName" = "Tinode"; 3 | /* Bundle name */ 4 | "CFBundleName" = "Tinodios"; 5 | /* Privacy - Camera Usage Description */ 6 | "NSCameraUsageDescription" = "Tinode takes photos with the camera to use as avatar or to send them to your contacts"; 7 | /* Privacy - Contacts Usage Description */ 8 | "NSContactsUsageDescription" = "Tinode sends only emails and phone numbers to the Tinode server to help you connect with other users"; 9 | /* Privacy - Microphone Usage Description */ 10 | "NSMicrophoneUsageDescription" = "Tinode uses microphone to record audio messages you send to your contacts"; 11 | /* Privacy - Photo Library Additions Usage Description */ 12 | "NSPhotoLibraryAddUsageDescription" = "Images and pictures from Tinode can be saved in the photo library"; 13 | /* Privacy - Photo Library Usage Description */ 14 | "NSPhotoLibraryUsageDescription" = "Tinode needs access to your photos to let you you send them to your contacts"; 15 | -------------------------------------------------------------------------------- /Localizations/zh-Hans.xcloc/Source Contents/TinodiosNSExtension/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Bundle display name */ 2 | "CFBundleDisplayName" = "TinodiosNSExtension"; 3 | /* Bundle name */ 4 | "CFBundleName" = "TinodiosNSExtension"; 5 | -------------------------------------------------------------------------------- /Localizations/zh-Hans.xcloc/Source Contents/TinodiosNSExtension/en.lproj/Localizable.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Localizations/zh-Hans.xcloc/Source Contents/TinodiosNSExtension/en.lproj/Localizable.strings -------------------------------------------------------------------------------- /Localizations/zh-Hans.xcloc/contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "developmentRegion" : "en", 3 | "targetLocale" : "zh-Hans", 4 | "toolInfo" : { 5 | "toolBuildNumber" : "15C500b", 6 | "toolID" : "com.apple.dt.xcode", 7 | "toolName" : "Xcode", 8 | "toolVersion" : "15.2" 9 | }, 10 | "version" : "1.0", 11 | "workspace" : "Tinodios.xcworkspace" 12 | } -------------------------------------------------------------------------------- /Localizations/zh-Hant.xcloc/Source Contents/Pods/en.lproj/Localizable.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Localizations/zh-Hant.xcloc/Source Contents/Pods/en.lproj/Localizable.strings -------------------------------------------------------------------------------- /Localizations/zh-Hant.xcloc/Source Contents/Tinodios/Settings.bundle/en.lproj/ConnectionSettings.strings: -------------------------------------------------------------------------------- 1 | /* A single strings file, whose title is specified in your preferences schema. The strings files provide the localized content to display to the user for each of your preferences. */ 2 | 3 | "Wire transport" = "Wire transport"; 4 | "Host name" = "Host name"; 5 | "Use TLS" = "Use TLS"; 6 | -------------------------------------------------------------------------------- /Localizations/zh-Hant.xcloc/Source Contents/Tinodios/Settings.bundle/en.lproj/Root.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Localizations/zh-Hant.xcloc/Source Contents/Tinodios/Settings.bundle/en.lproj/Root.strings -------------------------------------------------------------------------------- /Localizations/zh-Hant.xcloc/Source Contents/Tinodios/Supporting Files/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /Localizations/zh-Hant.xcloc/Source Contents/Tinodios/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Bundle display name */ 2 | "CFBundleDisplayName" = "Tinode"; 3 | /* Bundle name */ 4 | "CFBundleName" = "Tinodios"; 5 | /* Privacy - Camera Usage Description */ 6 | "NSCameraUsageDescription" = "Tinode takes photos with the camera to use as avatar or to send them to your contacts"; 7 | /* Privacy - Contacts Usage Description */ 8 | "NSContactsUsageDescription" = "Tinode sends only emails and phone numbers to the Tinode server to help you connect with other users"; 9 | /* Privacy - Microphone Usage Description */ 10 | "NSMicrophoneUsageDescription" = "Tinode uses microphone to record audio messages you send to your contacts"; 11 | /* Privacy - Photo Library Additions Usage Description */ 12 | "NSPhotoLibraryAddUsageDescription" = "Images and pictures from Tinode can be saved in the photo library"; 13 | /* Privacy - Photo Library Usage Description */ 14 | "NSPhotoLibraryUsageDescription" = "Tinode needs access to your photos to let you you send them to your contacts"; 15 | -------------------------------------------------------------------------------- /Localizations/zh-Hant.xcloc/Source Contents/TinodiosNSExtension/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Bundle display name */ 2 | "CFBundleDisplayName" = "TinodiosNSExtension"; 3 | /* Bundle name */ 4 | "CFBundleName" = "TinodiosNSExtension"; 5 | -------------------------------------------------------------------------------- /Localizations/zh-Hant.xcloc/Source Contents/TinodiosNSExtension/en.lproj/Localizable.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Localizations/zh-Hant.xcloc/Source Contents/TinodiosNSExtension/en.lproj/Localizable.strings -------------------------------------------------------------------------------- /Localizations/zh-Hant.xcloc/contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "developmentRegion" : "en", 3 | "targetLocale" : "zh-Hant", 4 | "toolInfo" : { 5 | "toolBuildNumber" : "15C500b", 6 | "toolID" : "com.apple.dt.xcode", 7 | "toolName" : "Xcode", 8 | "toolVersion" : "15.2" 9 | }, 10 | "version" : "1.0", 11 | "workspace" : "Tinodios.xcworkspace" 12 | } -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment the next line to define a global platform for your project 2 | platform :ios, '12.0' 3 | 4 | # https://stackoverflow.com/a/58067562/6692196 !use_frameworks is no longer needed. 5 | # use_frameworks! 6 | 7 | # ignore all warnings from all pods 8 | inhibit_all_warnings! 9 | 10 | # The Swift pod `FirebaseCoreInternal` depends upon `GoogleUtilities`, which does not define modules. To opt into those targets generating module maps (which is necessary to import them from Swift when building as static libraries), you may set `use_modular_headers!` globally in your Podfile, or specify `:modular_headers => true` for particular dependencies. 11 | # use_modular_headers! 12 | 13 | workspace 'Tinodios' 14 | 15 | project 'Tinodios' 16 | project 'TinodeSDK' 17 | 18 | 19 | def db_pods 20 | pod 'SQLite.swift', '~> 0.15' 21 | pod 'SwiftKeychainWrapper', '~> 3.2' 22 | end 23 | 24 | target 'TinodeSDKTests' do 25 | project 'TinodeSDK' 26 | end 27 | 28 | target 'TinodiosDB' do 29 | project 'TinodiosDB' 30 | db_pods 31 | end 32 | 33 | def app_pods 34 | pod 'Firebase' 35 | pod 'FirebaseCore' 36 | pod 'FirebaseMessaging' 37 | pod 'FirebaseAnalytics' 38 | pod 'FirebaseCrashlytics' 39 | pod 'Kingfisher', '~> 5' 40 | pod 'MobileVLCKit', '~> 3' 41 | pod 'PhoneNumberKit', '~> 3' 42 | pod 'WebRTC-lib', '~> 96.0.0' 43 | end 44 | 45 | # UI tests. 46 | target 'TinodiosUITests' do 47 | project 'Tinodios' 48 | db_pods 49 | app_pods 50 | end 51 | 52 | target 'Tinodios' do 53 | project 'Tinodios' 54 | db_pods 55 | app_pods 56 | end 57 | 58 | post_install do | installer | 59 | require 'fileutils' 60 | FileUtils.cp_r('Pods/Target Support Files/Pods-Tinodios/Pods-Tinodios-acknowledgements.plist', 'Tinodios/Settings.bundle/Acknowledgements.plist', :remove_destination => true) 61 | installer.aggregate_targets.each do |aggregate_target| 62 | aggregate_target.xcconfigs.each do |config_name, config_file| 63 | xcconfig_path = aggregate_target.xcconfig_path(config_name) 64 | config_file.save_as(xcconfig_path) 65 | end 66 | end 67 | 68 | # See explanation here: https://github.com/firebase/firebase-ios-sdk/issues/6533 69 | installer.pods_project.targets.each do |target| 70 | target.build_configurations.each do |config| 71 | config.build_settings.delete 'IPHONEOS_DEPLOYMENT_TARGET' 72 | end 73 | end 74 | end 75 | -------------------------------------------------------------------------------- /Scripts/set_build_number.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Automatically sets version of target based on most recent tag in git 4 | # Automatically sets build number to number of commits 5 | # 6 | # Add script to build phase in xcode at the top of the chain named "set build number" 7 | # put this script in the root of the xcode project in a directory called scripts (good idea to version control this too) 8 | # call the script as $SRCROOT/scripts/set_build_number.sh in xcode 9 | 10 | cd "$SRCROOT" 11 | 12 | git=$(sh /etc/profile; which git) 13 | number_of_commits=$("$git" rev-list HEAD --count) 14 | tag=$("$git" describe --tags --always --abbrev=0) 15 | git_version=${tag#?} 16 | 17 | sed -i -e "/GIT_TAG =/ s/= .*/= $git_version/" prod.xcconfig 18 | sed -i -e "/GIT_COMMIT_COUNT =/ s/= .*/= $number_of_commits/" prod.xcconfig 19 | 20 | # Delete old version of the file. 21 | rm prod.xcconfig-e 22 | -------------------------------------------------------------------------------- /Scripts/set_default_preferences.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script assigns DefaultValue for host name and TLS in Settings.bundle/Root.plist preferences 4 | # reading them from build configuration Info.plist. 5 | 6 | # Location of Settings.bundle/Root.plist to update 7 | prefs_file="$TARGET_BUILD_DIR/$CONTENTS_FOLDER_PATH/Settings.bundle/Root.plist" 8 | # Location of Info.plist to read values from 9 | info_plist="$TARGET_BUILD_DIR/$INFOPLIST_PATH" 10 | 11 | # Find array entry with the necessary key 12 | # Iterate at most 10 array entries until either the key is found or all entries iterated. 13 | # @param: key to find 14 | find_array_entry() { 15 | for i in {0..10} 16 | do 17 | local key=$(/usr/libexec/PlistBuddy -c "Print PreferenceSpecifiers:${i}:Key" "$prefs_file" 2>/dev/null) 18 | if [ -z "$key" ]; then 19 | continue 20 | fi 21 | if [[ $key == "$1" ]]; then 22 | return $i 23 | fi 24 | done 25 | return -1 26 | } 27 | 28 | # Find key for the host name 29 | find_array_entry "host_name_preference" 30 | hn_index=$? 31 | if [ "$hn_index" -eq -1 ]; then 32 | echo "Entry host_name_preference not found" 33 | exit 1 34 | fi 35 | # Find key for TLS use 36 | find_array_entry "use_tls_preference" 37 | tls_index=$? 38 | if [ "$tls_index" -eq -1 ]; then 39 | echo "Entry use_tls_preference not found" 40 | exit 1 41 | fi 42 | # Find key for bundle version 43 | find_array_entry "bundle_version" 44 | bv_index=$? 45 | if [ "$bv_index" -eq -1 ]; then 46 | echo "Entry bundle_version not found" 47 | exit 1 48 | fi 49 | 50 | # Read values from Info.plist 51 | host_name=$(/usr/libexec/PlistBuddy -c "Print :HOST_NAME" "$info_plist" 2>/dev/null) 52 | use_tls=$(/usr/libexec/PlistBuddy -c "Print :USE_TLS" "$info_plist" 2>/dev/null) 53 | bundle_version=$(/usr/libexec/PlistBuddy -c "Print :CFBundleVersion" "$info_plist" 2>/dev/null) 54 | if [ -z "$host_name" ] || [ -z "$use_tls" ] || [ -z "$bundle_version" ]; then 55 | echo "Missing host name '$host_name' or TLS value '$use_tls' or bundle version value '$bundle_version'" 56 | exit 1 57 | fi 58 | 59 | # Assign values as appropriate 60 | echo "Modifying preference entries in '$prefs_file'" 61 | /usr/libexec/PlistBuddy -c "Set PreferenceSpecifiers:${hn_index}:DefaultValue $host_name" "$prefs_file" 62 | echo "Assigned '$host_name' to PreferenceSpecifiers:${hn_index}:DefaultValue" 63 | /usr/libexec/PlistBuddy -c "Set PreferenceSpecifiers:${tls_index}:DefaultValue $use_tls" "$prefs_file" 64 | echo "Assigned '$use_tls' to PreferenceSpecifiers:${tls_index}:DefaultValue" 65 | /usr/libexec/PlistBuddy -c "Set PreferenceSpecifiers:${bv_index}:DefaultValue $bundle_version" "$prefs_file" 66 | echo "Assigned '$bundle_version' to PreferenceSpecifiers:${bv_index}:DefaultValue" 67 | -------------------------------------------------------------------------------- /TinodeSDK.xcodeproj/xcshareddata/xcbaselines/0A56CCE122759078006E2952.xcbaseline/E5D25F8D-C9DB-4BEE-A6FF-37F703A10D97.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | classNames 6 | 7 | DraftyTest 8 | 9 | testPerformanceParse() 10 | 11 | com.apple.XCTPerformanceMetric_WallClockTime 12 | 13 | baselineAverage 14 | 0.339000 15 | baselineIntegrationDisplayName 16 | Local Baseline 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /TinodeSDK.xcodeproj/xcshareddata/xcbaselines/0A56CCE122759078006E2952.xcbaseline/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | runDestinationsByUUID 6 | 7 | E5D25F8D-C9DB-4BEE-A6FF-37F703A10D97 8 | 9 | localComputer 10 | 11 | busSpeedInMHz 12 | 0 13 | cpuCount 14 | 1 15 | cpuKind 16 | Apple M1 Max 17 | cpuSpeedInMHz 18 | 0 19 | logicalCPUCoresPerPackage 20 | 10 21 | modelCode 22 | MacBookPro18,2 23 | physicalCPUCoresPerPackage 24 | 10 25 | platformIdentifier 26 | com.apple.platform.macosx 27 | 28 | targetArchitecture 29 | arm64 30 | targetDevice 31 | 32 | modelCode 33 | iPhone12,1 34 | platformIdentifier 35 | com.apple.platform.iphonesimulator 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /TinodeSDK/FndTopic.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FndTopic.swift 3 | // TinodeSDK 4 | // 5 | // Copyright © 2020-2022 Tinode LLC. All rights reserved. 6 | // 7 | 8 | import Foundation 9 | 10 | public class FndTopic: Topic { 11 | init(tinode: Tinode?) { 12 | super.init(tinode: tinode, name: Tinode.kTopicFnd) 13 | } 14 | 15 | @discardableResult 16 | override public func setMeta(meta: MsgSetMeta) -> PromisedReply { 17 | if self.subs != nil { 18 | self.subs!.removeAll() 19 | self.subs = nil 20 | self.subsLastUpdated = nil 21 | self.listener?.onSubsUpdated() 22 | } 23 | return super.setMeta(meta: meta) 24 | } 25 | 26 | override func routeMetaSub(meta: MsgServerMeta) { 27 | if let subscriptions = meta.sub { 28 | for upd in subscriptions { 29 | var sub = getSubscription(for: upd.uniqueId) 30 | if sub != nil { 31 | _ = sub!.merge(sub: upd as! Subscription) 32 | } else { 33 | sub = upd as? Subscription 34 | self.addSubToCache(sub: sub!) 35 | } 36 | self.listener?.onMetaSub(sub: sub!) 37 | } 38 | } 39 | self.listener?.onSubsUpdated() 40 | } 41 | 42 | override public func getSubscriptions() -> [Subscription]? { 43 | guard let v = subs?.values else { return nil } 44 | return Array(v) 45 | } 46 | 47 | override func addSubToCache(sub: Subscription) { 48 | guard let unique = sub.user ?? sub.topic else { return } 49 | 50 | if subs == nil { 51 | subs = [:] 52 | } 53 | subs![unique] = sub 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /TinodeSDK/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | $(MARKETING_VERSION) 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | 22 | 23 | -------------------------------------------------------------------------------- /TinodeSDK/Log.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Log.swift 3 | // TinodeSDK 4 | // 5 | // Copyright © 2019 Tinode. All rights reserved. 6 | // 7 | 8 | import Foundation 9 | 10 | enum LogType { 11 | case debug 12 | case info 13 | case error 14 | case fault 15 | } 16 | 17 | open class Log { 18 | let prefix: String 19 | public static let `default` = Log(subsystem: "default") 20 | 21 | public init(subsystem: String = Bundle.main.bundleIdentifier ?? "") { 22 | self.prefix = "[" + subsystem + "] " 23 | } 24 | func log(type: LogType, message: StaticString, _ args: [CVarArg]) { 25 | #if !DEBUG 26 | guard type != .debug else { return } 27 | #endif 28 | let msg = self.prefix + message.description 29 | withVaList(args) { 30 | NSLogv(msg, $0) 31 | } 32 | } 33 | public func debug(_ message: StaticString, _ args: CVarArg...) { 34 | log(type: .debug, message: message, args) 35 | } 36 | public func info(_ message: StaticString, _ args: CVarArg...) { 37 | log(type: .info, message: message, args) 38 | } 39 | public func error(_ message: StaticString, _ args: CVarArg...) { 40 | log(type: .error, message: message, args) 41 | } 42 | public func fault(_ message: StaticString, _ args: CVarArg...) { 43 | log(type: .fault, message: message, args) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /TinodeSDK/RFC3339Format.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RFC3339Format.swift 3 | // ios 4 | // 5 | // Copyright © 2019 Tinode. All rights reserved. 6 | // 7 | 8 | import Foundation 9 | 10 | // Date extensions. 11 | // From: https://stackoverflow.com/questions/46458487/how-to-convert-a-date-string-with-optional-fractional-seconds-using-codable-in-s 12 | extension Formatter { 13 | public static let rfc3339: DateFormatter = { 14 | let formatter = DateFormatter() 15 | formatter.locale = Locale(identifier: "en_US_POSIX") 16 | formatter.dateFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.SSS'Z'" 17 | formatter.timeZone = TimeZone(secondsFromGMT: 0) 18 | return formatter 19 | }() 20 | public static let rfc3339short: DateFormatter = { 21 | let formatter = DateFormatter() 22 | formatter.locale = Locale(identifier: "en_US_POSIX") 23 | formatter.dateFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'" 24 | formatter.timeZone = TimeZone(secondsFromGMT: 0) 25 | return formatter 26 | }() 27 | } 28 | 29 | extension JSONDecoder.DateDecodingStrategy { 30 | static let customRFC3339 = custom { decoder throws -> Date in 31 | let container = try decoder.singleValueContainer() 32 | let string = try container.decode(String.self) 33 | if let date = Formatter.rfc3339.date(from: string) { 34 | return date 35 | } 36 | if let date = Formatter.rfc3339short.date(from: string) { 37 | return date 38 | } 39 | throw DecodingError.dataCorruptedError( 40 | in: container, debugDescription: "Invalid date: \(string)") 41 | } 42 | } 43 | extension JSONEncoder.DateEncodingStrategy { 44 | static let customRFC3339 = custom { date, encoder throws in 45 | var container = encoder.singleValueContainer() 46 | try container.encode(Formatter.rfc3339.string(from: date)) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /TinodeSDK/TinodeSDK.h: -------------------------------------------------------------------------------- 1 | // 2 | // TinodeSDK.h 3 | // TinodeSDK 4 | // 5 | // Copyright © 2019 Tinode. All rights reserved. 6 | // 7 | 8 | #import 9 | 10 | //! Project version number for TinodeSDK. 11 | FOUNDATION_EXPORT double TinodeSDKVersionNumber; 12 | 13 | //! Project version string for TinodeSDK. 14 | FOUNDATION_EXPORT const unsigned char TinodeSDKVersionString[]; 15 | 16 | // In this header, you should import all the public headers of your framework using statements like #import 17 | 18 | 19 | -------------------------------------------------------------------------------- /TinodeSDK/model/Types.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Types.swift 3 | // TinodeSDK 4 | // 5 | // Copyright © 2019-2022 Tinode LLC. All rights reserved. 6 | // 7 | 8 | public protocol Mergeable { 9 | // Merges self with |another|. 10 | // Retuns true if the target object was modified. 11 | mutating func merge(with another: Mergeable) -> Bool 12 | } 13 | 14 | extension String: Mergeable { 15 | public mutating func merge(with another: Mergeable) -> Bool { 16 | guard another is String else { return false } 17 | self = another as! String 18 | return true 19 | } 20 | } 21 | 22 | public typealias PrivateType = [String: JSONValue] 23 | 24 | extension PrivateType: Mergeable { 25 | public func getBoolValue(name: String) -> Bool? { 26 | return self[name]?.asBool() 27 | } 28 | public func getStringValue(name: String) -> String? { 29 | return self[name]?.asString() 30 | } 31 | 32 | public var comment: String? { 33 | get { 34 | return self["comment"]?.asString() 35 | } 36 | set { 37 | self["comment"] = .string(newValue ?? Tinode.kNullValue) 38 | } 39 | } 40 | public var archived: Bool? { 41 | get { 42 | self["arch"]?.asBool() 43 | } 44 | set { 45 | self["arch"] = newValue != nil ? .bool(newValue!) : nil 46 | } 47 | } 48 | public mutating func merge(with another: Mergeable) -> Bool { 49 | guard another is PrivateType else { return false } 50 | let anotherPT = another as! PrivateType 51 | for (k, v) in anotherPT { 52 | self[k] = v 53 | } 54 | return !anotherPT.isEmpty 55 | } 56 | } 57 | 58 | public typealias TrustedType = [String: JSONValue] 59 | 60 | extension TrustedType { 61 | public var isVerified: Bool? { 62 | return getBoolValue(name: "verified") 63 | } 64 | public var isStaffManaged: Bool? { 65 | return getBoolValue(name: "staff") 66 | } 67 | public var isDangerous: Bool? { 68 | return getBoolValue(name: "danger") 69 | } 70 | } 71 | 72 | // Topic and Subscription types. 73 | public typealias DefaultDescription = Description 74 | public typealias DefaultSubscription = Subscription 75 | public typealias FndDescription = Description 76 | public typealias FndSubscription = Subscription 77 | 78 | public typealias DefaultTopic = Topic 79 | public typealias DefaultComTopic = ComTopic 80 | public typealias DefaultMeTopic = MeTopic 81 | public typealias DefaultFndTopic = FndTopic 82 | -------------------------------------------------------------------------------- /TinodeSDKTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /TinodeSDKTests/TinodeSDKTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TinodeSDKTests.swift 3 | // TinodeSDKTests 4 | // 5 | // Copyright © 2019 Tinode. All rights reserved. 6 | // 7 | 8 | import XCTest 9 | 10 | // TODO: add tests for Tinode here. 11 | class TinodeSDKTests: XCTestCase { 12 | 13 | override func setUp() { 14 | // Put setup code here. This method is called before the invocation of each test method in the class. 15 | } 16 | 17 | override func tearDown() { 18 | // Put teardown code here. This method is called after the invocation of each test method in the class. 19 | } 20 | 21 | func testExample() { 22 | // This is an example of a functional test case. 23 | // Use XCTAssert and related functions to verify your tests produce the correct results. 24 | } 25 | 26 | func testPerformanceExample() { 27 | // This is an example of a performance test case. 28 | self.measure { 29 | // Put the code you want to measure the time of here. 30 | } 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /Tinodios.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 9 | 10 | 12 | 13 | 14 | 16 | 17 | 19 | 20 | 22 | 23 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Tinodios.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Tinodios.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Tinodios/AccountSettingsViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AccountSettingsViewController.swift 3 | // 4 | // Copyright © 2019-2022 Tinode LLC. All rights reserved. 5 | // 6 | 7 | import TinodeSDK 8 | import UIKit 9 | 10 | class AccountSettingsViewController: UITableViewController { 11 | private static let kSectionPersonal = 0 12 | private static let kPersonalVerified = 2 13 | private static let kPersonalStaff = 3 14 | private static let kPersonalDanger = 4 15 | 16 | @IBOutlet weak var avatarImageView: RoundImageView! 17 | @IBOutlet weak var userNameLabel: UILabel! 18 | @IBOutlet weak var subtitleLabel: UILabel! 19 | @IBOutlet weak var myUIDLabel: UILabel! 20 | 21 | weak var tinode: Tinode! 22 | weak var me: DefaultMeTopic! 23 | 24 | override func viewDidLoad() { 25 | super.viewDidLoad() 26 | setup() 27 | } 28 | 29 | override func viewWillAppear(_ animated: Bool) { 30 | super.viewWillAppear(animated) 31 | 32 | reloadData() 33 | } 34 | 35 | private func setup() { 36 | self.tinode = Cache.tinode 37 | self.me = self.tinode.getMeTopic()! 38 | } 39 | 40 | private func reloadData() { 41 | // Title. 42 | self.userNameLabel.text = me.pub?.fn ?? NSLocalizedString("Unknown", comment: "Placeholder for missing user name") 43 | 44 | // Avatar. 45 | self.avatarImageView.set(pub: me.pub, id: self.tinode.myUid, deleted: false) 46 | self.avatarImageView.letterTileFont = self.avatarImageView.letterTileFont.withSize(CGFloat(50)) 47 | 48 | self.subtitleLabel.text = me.pub?.note ?? me.tags?.joined(separator: ", ") 49 | 50 | // My UID/Address label. 51 | self.myUIDLabel.text = self.tinode.myUid 52 | self.myUIDLabel.sizeToFit() 53 | } 54 | 55 | override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { 56 | if indexPath.section == AccountSettingsViewController.kSectionPersonal { 57 | if (indexPath.row == AccountSettingsViewController.kPersonalVerified && !me.isVerified) || 58 | (indexPath.row == AccountSettingsViewController.kPersonalStaff && !me.isStaffManaged) || 59 | (indexPath.row == AccountSettingsViewController.kPersonalDanger && !me.isDangerous) { 60 | return CGFloat.leastNonzeroMagnitude 61 | } 62 | } 63 | 64 | return super.tableView(tableView, heightForRowAt: indexPath) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Tinodios/BrandingViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BrandingViewController.swift 3 | // Tinodios 4 | // 5 | // Copyright © 2023 Tinode LLC. All rights reserved. 6 | // 7 | 8 | import TinodiosDB 9 | import UIKit 10 | 11 | // Branding configuration VC. 12 | // Allows 13 | class BrandingViewController: UIViewController { 14 | static let kTinodeHostUriPrefix = "tinode:host/" 15 | 16 | private var qrScanner: QRScanner! 17 | 18 | @IBOutlet weak var configurationCodeField: UITextField! 19 | @IBOutlet weak var cameraPreviewView: UIView! 20 | 21 | override func viewDidLoad() { 22 | self.configurationCodeField.addTarget(self, action: #selector(textFieldDidChange(_:)), for: UIControl.Event.editingChanged) 23 | self.qrScanner = QRScanner(embedIn: self.cameraPreviewView, expectedCodePrefix: BrandingViewController.kTinodeHostUriPrefix, delegate: self) 24 | } 25 | 26 | override func viewDidAppear(_ animated: Bool) { 27 | self.qrScanner.start() 28 | } 29 | 30 | override func viewWillDisappear(_ animated: Bool) { 31 | super.viewWillDisappear(animated) 32 | 33 | self.qrScanner.stop() 34 | } 35 | 36 | @objc func textFieldDidChange(_ textField: UITextField) { 37 | textField.clearErrorSign() 38 | } 39 | 40 | @IBAction func okayClicked(_ sender: Any) { 41 | let code = UiUtils.ensureDataInTextField(configurationCodeField) 42 | guard !code.isEmpty else { 43 | return 44 | } 45 | handleCodeEntered(code) 46 | } 47 | 48 | private func handleCodeEntered(_ code: String) { 49 | UiUtils.showToast(message: "Configuring. Config ID: " + code, level: .info) 50 | SharedUtils.setUpBranding(withConfigurationCode: code) 51 | self.navigationController?.popViewController(animated: true) 52 | } 53 | } 54 | 55 | extension BrandingViewController: QRScannerDelegate { 56 | func qrScanner(didScanCode codeValue: String?) { 57 | guard let code = codeValue else { 58 | Cache.log.error("Invalid host QR code") 59 | DispatchQueue.main.async { 60 | UiUtils.showToast(message: "Invalid Tinode configuration QR code") 61 | } 62 | DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1)) { [weak self] in 63 | // Restart QR scanner. 64 | self?.qrScanner.start() 65 | } 66 | return 67 | } 68 | handleCodeEntered(code) 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Tinodios/CallProviderDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CallProviderDelegate.swift 3 | // Tinodios 4 | // 5 | // Copyright © 2022 Tinode LLC. All rights reserved. 6 | // 7 | 8 | import CallKit 9 | 10 | protocol CallManagerImpl: AnyObject { 11 | func acceptPendingCall() -> Bool 12 | func completeCallInProgress(reportToSystem: Bool, reportToPeer: Bool) 13 | } 14 | 15 | class CallProviderDelegate: NSObject, CXProviderDelegate { 16 | static let kProviderConfiguration: CXProviderConfiguration = { 17 | let providerConfiguration = CXProviderConfiguration(localizedName: "Tinode") // TODO: change 18 | 19 | providerConfiguration.supportsVideo = true 20 | providerConfiguration.maximumCallsPerCallGroup = 1 21 | providerConfiguration.supportedHandleTypes = [.generic] 22 | providerConfiguration.includesCallsInRecents = false 23 | 24 | return providerConfiguration 25 | }() 26 | 27 | private weak var callManager: CallManagerImpl? 28 | private let provider: CXProvider 29 | 30 | init(callManager: CallManagerImpl?) { 31 | self.callManager = callManager 32 | self.provider = CXProvider(configuration: CallProviderDelegate.kProviderConfiguration) 33 | 34 | super.init() 35 | self.provider.setDelegate(self, queue: nil) 36 | } 37 | 38 | func reportIncomingCall(uuid: UUID, handle: String, audioOnly: Bool, completion: ((Error?) -> Void)?) { 39 | let update = CXCallUpdate() 40 | update.remoteHandle = CXHandle(type: .generic, value: handle) 41 | update.hasVideo = !audioOnly 42 | 43 | self.provider.reportNewIncomingCall(with: uuid, update: update) { error in 44 | if let error = error { 45 | Cache.log.error("Report incoming call error: %@", error.localizedDescription) 46 | } 47 | completion?(error) 48 | } 49 | } 50 | 51 | func providerDidReset(_ provider: CXProvider) { 52 | callManager?.completeCallInProgress(reportToSystem: true, reportToPeer: true) 53 | } 54 | 55 | func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) { 56 | // User tapped "Accept". 57 | if let cm = callManager, cm.acceptPendingCall() { 58 | action.fulfill() 59 | } else { 60 | action.fail() 61 | } 62 | } 63 | 64 | func provider(_ provider: CXProvider, perform action: CXEndCallAction) { 65 | // User tapped "Decline/End call" in the incoming call view, 66 | // or end call action was requested programmatically. 67 | callManager?.completeCallInProgress(reportToSystem: false, reportToPeer: true) 68 | action.fulfill() 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Tinodios/ChatListPresenter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ChatListPresenter.swift 3 | // Tinodios 4 | // 5 | // Copyright © 2019 Tinode. All rights reserved. 6 | // 7 | 8 | import Foundation 9 | import TinodeSDK 10 | 11 | protocol ChatListPresentationLogic { 12 | func presentTopics(_ topics: [DefaultComTopic], archivedTopics: [DefaultComTopic]?) 13 | func topicUpdated(_ name: String) 14 | func topicDeleted(_ name: String) 15 | } 16 | 17 | class ChatListPresenter: ChatListPresentationLogic { 18 | weak var viewController: ChatListDisplayLogic? 19 | 20 | func presentTopics(_ topics: [DefaultComTopic], archivedTopics: [DefaultComTopic]?) { 21 | DispatchQueue.main.async { 22 | self.viewController?.displayChats(topics, archivedTopics: archivedTopics) 23 | } 24 | } 25 | 26 | func topicUpdated(_ name: String) { 27 | DispatchQueue.main.async { 28 | self.viewController?.updateChat(name) 29 | } 30 | } 31 | 32 | func topicDeleted(_ name: String) { 33 | DispatchQueue.main.async { 34 | self.viewController?.deleteChat(name) 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Tinodios/ChatListRouter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ChatListRouter.swift 3 | // Tinodios 4 | // 5 | // Copyright © 2019 Tinode. All rights reserved. 6 | // 7 | 8 | import UIKit 9 | 10 | protocol ChatListRoutingLogic { 11 | func routeToChat(withName name: String, for segue: UIStoryboardSegue) 12 | func routeToLogin() 13 | } 14 | 15 | class ChatListRouter: ChatListRoutingLogic { 16 | weak var viewController: ChatListViewController? 17 | 18 | func routeToChat(withName name: String, for segue: UIStoryboardSegue) { 19 | let messageController = segue.destination as! MessageViewController 20 | messageController.topicName = name 21 | } 22 | func routeToLogin() { 23 | self.viewController?.displayLoginView() 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Tinodios/CredentialsViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CredentialsViewController.swift 3 | // Tinodios 4 | // 5 | // Copyright © 2019 Tinode. All rights reserved. 6 | // 7 | 8 | import UIKit 9 | import TinodeSDK 10 | 11 | class CredentialsViewController: UIViewController { 12 | 13 | @IBOutlet weak var codeText: UITextField! 14 | 15 | var meth: String? 16 | var authToken: String? 17 | 18 | override func viewDidLoad() { 19 | super.viewDidLoad() 20 | if traitCollection.userInterfaceStyle == .dark { 21 | self.view.backgroundColor = .black 22 | } else { 23 | self.view.backgroundColor = .white 24 | } 25 | self.authToken = Cache.tinode.authToken 26 | UiUtils.dismissKeyboardForTaps(onView: self.view) 27 | } 28 | 29 | override func viewWillDisappear(_ animated: Bool) { 30 | super.viewWillDisappear(animated) 31 | if self.isMovingFromParent { 32 | // If the user's logged in and is voluntarily leaving the verification VC 33 | // by hitting the Back button. 34 | let tinode = Cache.tinode 35 | if tinode.isConnectionAuthenticated || tinode.myUid != nil { 36 | tinode.logout() 37 | } 38 | } 39 | } 40 | 41 | @IBAction func onConfirm(_ sender: UIButton) { 42 | guard let code = codeText.text else { 43 | return 44 | } 45 | guard let method = meth else { 46 | return 47 | } 48 | 49 | let tinode = Cache.tinode 50 | 51 | guard let token = self.authToken else { 52 | self.dismiss(animated: true, completion: nil) 53 | return 54 | } 55 | 56 | let c = Credential(meth: method, val: nil, resp: code, params: nil) 57 | var creds = [Credential]() 58 | creds.append(c) 59 | 60 | let errorMsgTemplate = NSLocalizedString("Verification failure: %d %@", comment: "Error message") 61 | tinode.loginToken(token: token, creds: creds) 62 | .then(onSuccess: { msg in 63 | if let ctrl = msg?.ctrl, ctrl.code >= 300 { 64 | DispatchQueue.main.async { 65 | UiUtils.showToast(message: String(format: errorMsgTemplate, ctrl.code, ctrl.text)) 66 | } 67 | } else { 68 | if let token = tinode.authToken { 69 | tinode.setAutoLoginWithToken(token: token) 70 | } 71 | UiUtils.routeToChatListVC() 72 | } 73 | return nil 74 | }, onFailure: { err in 75 | Cache.log.error("Error validating credentials: %@", err.localizedDescription) 76 | DispatchQueue.main.async { 77 | UiUtils.showToast(message: String(format: errorMsgTemplate, -1, "Invalid code")) 78 | } 79 | return nil 80 | }) 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /Tinodios/FindPresenter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FindPresenter.swift 3 | // Tinodios 4 | // 5 | // Copyright © 2019 Tinode. All rights reserved. 6 | // 7 | 8 | import Foundation 9 | 10 | protocol FindPresentationLogic { 11 | var viewController: FindDisplayLogic? { get set } 12 | func presentLocalContacts(contacts: [ContactHolder]) 13 | func presentRemoteContacts(contacts: [RemoteContactHolder]) 14 | } 15 | 16 | class FindPresenter: FindPresentationLogic { 17 | weak var viewController: FindDisplayLogic? 18 | 19 | func presentLocalContacts(contacts: [ContactHolder]) { 20 | DispatchQueue.main.async { 21 | self.viewController?.displayLocalContacts(contacts: contacts) 22 | } 23 | } 24 | func presentRemoteContacts(contacts: [RemoteContactHolder]) { 25 | DispatchQueue.main.async { 26 | self.viewController?.displayRemoteContacts(contacts: contacts) 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Tinodios/ForwardToViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ForwardToViewController.swift 3 | // 4 | // Copyright © 2019-2022 Tinode LLC. All rights reserved. 5 | // 6 | 7 | import TinodeSDK 8 | import UIKit 9 | 10 | protocol ForwardToDelegate: AnyObject { 11 | func forwardMessage(_ message: Drafty, preview: Drafty, from origin: String, to topicId: String) 12 | } 13 | 14 | class ForwardToInteractor: FindInteractor { 15 | private let filterTopic: String 16 | init(filterTopic topicName: String) { 17 | filterTopic = topicName 18 | } 19 | override func fetchLocalContacts() -> [ContactHolder] { 20 | guard let topics = Utils.fetchTopics(archived: false) else { return [] } 21 | let finalTopics = topics.filter { $0.name != filterTopic } 22 | return finalTopics.map { (topic) -> ContactHolder in 23 | return ContactHolder(pub: topic.pub, uniqueId: topic.name) 24 | } 25 | } 26 | } 27 | 28 | class ForwardToViewController: FindViewController { 29 | var delegate: ForwardToDelegate? 30 | var forwardedContent: Drafty! 31 | var forwardedFrom: String! 32 | var forwardedPreview: Drafty! 33 | 34 | // Use ForwardToInterator for the business logic. 35 | override func createDependencies() -> (FindBusinessLogic, FindPresentationLogic) { 36 | var sourceTopic = forwardedFrom! 37 | if let pos = sourceTopic.range(of: ":") { 38 | sourceTopic.removeSubrange(pos.lowerBound.. 2 | 3 | 4 | 5 | BGTaskSchedulerPermittedIdentifiers 6 | 7 | co.tinode.tinodios 8 | 9 | CFBundleDevelopmentRegion 10 | $(DEVELOPMENT_LANGUAGE) 11 | CFBundleDisplayName 12 | Tinode 13 | CFBundleExecutable 14 | $(EXECUTABLE_NAME) 15 | CFBundleIdentifier 16 | $(PRODUCT_BUNDLE_IDENTIFIER) 17 | CFBundleInfoDictionaryVersion 18 | 6.0 19 | CFBundleName 20 | $(APP_NAME) 21 | CFBundlePackageType 22 | APPL 23 | CFBundleShortVersionString 24 | $(MARKETING_VERSION) 25 | CFBundleVersion 26 | $(CURRENT_PROJECT_VERSION) 27 | HOST_NAME 28 | $(HOST_NAME) 29 | LSApplicationCategoryType 30 | public.app-category.productivity 31 | LSRequiresIPhoneOS 32 | 33 | NSCameraUsageDescription 34 | Tinode takes photos with the camera to use as avatar or to send them to your contacts 35 | NSMicrophoneUsageDescription 36 | Tinode uses microphone to record audio messages you send to your contacts 37 | NSContactsUsageDescription 38 | Tinode sends only emails and phone numbers to the Tinode server to help you connect with other users 39 | NSPhotoLibraryAddUsageDescription 40 | Images and pictures from Tinode can be saved in the photo library 41 | NSPhotoLibraryUsageDescription 42 | Tinode needs access to your photos to let you you send them to your contacts 43 | UIBackgroundModes 44 | 45 | fetch 46 | processing 47 | remote-notification 48 | voip 49 | 50 | UILaunchStoryboardName 51 | LaunchScreen 52 | UIMainStoryboardFile 53 | Main 54 | UIRequiredDeviceCapabilities 55 | 56 | armv7 57 | 58 | UISupportedInterfaceOrientations 59 | 60 | UIInterfaceOrientationPortrait 61 | UIInterfaceOrientationLandscapeLeft 62 | UIInterfaceOrientationLandscapeRight 63 | 64 | UISupportedInterfaceOrientations~ipad 65 | 66 | UIInterfaceOrientationPortrait 67 | UIInterfaceOrientationPortraitUpsideDown 68 | UIInterfaceOrientationLandscapeLeft 69 | UIInterfaceOrientationLandscapeRight 70 | 71 | UIViewControllerBasedStatusBarAppearance 72 | 73 | USE_TLS 74 | $(USE_TLS) 75 | 76 | 77 | -------------------------------------------------------------------------------- /Tinodios/KeyboardInfo.swift: -------------------------------------------------------------------------------- 1 | // 2 | // KeyboardInfo.swift 3 | // Tinodios 4 | // 5 | // Created by Nikita Timonin on 24/11/2019. 6 | // Copyright © 2019 Tinode. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | struct KeyboardInfo { 12 | 13 | let frameBegin: CGRect 14 | let frameEnd: CGRect 15 | let isLocal: Bool 16 | let animationDuration: TimeInterval 17 | let animationCurve: UIView.AnimationCurve 18 | 19 | init?(notification: Notification) { 20 | guard 21 | let userInfo = notification.userInfo, 22 | let frameBegin = userInfo[UIResponder.keyboardFrameBeginUserInfoKey] as? CGRect, 23 | let frameEnd = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect, 24 | let isLocal = userInfo[UIResponder.keyboardIsLocalUserInfoKey] as? Bool, 25 | let animationDuration = userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? TimeInterval, 26 | let rawCurve = userInfo[UIResponder.keyboardAnimationCurveUserInfoKey] as? Int, 27 | let animationCurve = UIView.AnimationCurve(rawValue: rawCurve) 28 | else { return nil } 29 | 30 | self.frameBegin = frameBegin 31 | self.frameEnd = frameEnd 32 | self.isLocal = isLocal 33 | self.animationDuration = animationDuration 34 | self.animationCurve = animationCurve 35 | } 36 | 37 | var animationOptions: UIView.AnimationOptions { 38 | let option = animationCurve.rawValue << 16 39 | return UIView.AnimationOptions(rawValue: UInt(option)) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Tinodios/MessageViewController+Keyboard.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MessageViewController+Keyboard.swift 3 | // Tinodios 4 | // 5 | // Copyright © 2019-2022 Tinode LLC. All rights reserved. 6 | // 7 | 8 | import UIKit 9 | 10 | extension MessageViewController { 11 | 12 | func addKeyboardObservers() { 13 | let notificationCenter = NotificationCenter.default 14 | notificationCenter.addObserver( 15 | self, 16 | selector: #selector(adjustForKeyboard(_:)), 17 | name: UIResponder.keyboardWillChangeFrameNotification, 18 | object: nil) 19 | notificationCenter.addObserver( 20 | self, 21 | selector: #selector(keyboardWillHide(_:)), 22 | name: UIResponder.keyboardWillHideNotification, 23 | object: nil) 24 | } 25 | 26 | @objc func adjustForKeyboard(_ notification: Notification) { 27 | // Apparently there is a bug in iOS 11 on iPad which sends useless notifications. This is a workaround. 28 | guard let keyboardInfo = KeyboardInfo(notification: notification), !keyboardInfo.frameBegin.isEmpty else { return } 29 | 30 | collectionView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: keyboardInfo.frameEnd.height, right: 0) 31 | let inputAccessoryViewHeight = inputAccessoryView?.frame.height ?? 0 32 | 33 | let overlap: CGFloat 34 | // Try to use frameBegin and frameEnd, when all available content is taller 35 | // than viewport less send bar. This can be done only on newer iOS versions. 36 | if collectionView.contentSize.height > collectionView.bounds.height - inputAccessoryViewHeight { 37 | overlap = keyboardInfo.frameEnd.height - keyboardInfo.frameBegin.height 38 | } else { 39 | overlap = 40 | collectionView.contentSize.height 41 | - collectionView.contentOffset.y 42 | - keyboardInfo.frameEnd.origin.y 43 | // 2x because keyboardInfo.frameEnd.origin.y accounts for inputAccessoryViewHeight 44 | + 2 * inputAccessoryViewHeight 45 | } 46 | 47 | if overlap > 0 && keyboardInfo.frameEnd.size.height != inputAccessoryViewHeight { 48 | let contentOffset = CGPoint( 49 | x: collectionView.contentOffset.x, 50 | y: collectionView.contentOffset.y + overlap) 51 | collectionView.setContentOffset(contentOffset, animated: false) 52 | } 53 | } 54 | 55 | @objc private func keyboardWillHide(_ notification: Notification) { 56 | collectionView.contentInset.bottom = inputAccessoryView?.frame.height ?? 0 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Tinodios/NewChatTabController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NewChatTabController.swift 3 | // Tinodios 4 | // 5 | // Copyright © 2019 Tinode. All rights reserved. 6 | // 7 | 8 | import UIKit 9 | 10 | class NewChatTabController: UITabBarController, UITabBarControllerDelegate { 11 | 12 | override func viewDidLoad() { 13 | super.viewDidLoad() 14 | self.delegate = self 15 | } 16 | 17 | func tabBarController(_ tabBarController: UITabBarController, 18 | shouldSelect viewController: UIViewController) -> Bool { 19 | guard let viewControllers = self.viewControllers else { return false } 20 | guard viewControllers[selectedIndex] !== viewController else { return false } 21 | for controller in viewControllers.compactMap({ $0 as? FindViewController }) { 22 | controller.cancelPendingSearchRequest(deactivateSearch: true) 23 | } 24 | return true 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Tinodios/RecordedMediaPlayback.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RecordedMediaPlayback.swift 3 | // Tinodios 4 | // 5 | // Copyright © 2022 Tinode LLC. All rights reserved. 6 | // 7 | 8 | import AVFoundation 9 | 10 | /// RecordedMediaPlayback plays media recorded from the microphone to a local file. 11 | class RecordedMediaPlayback: NSObject { 12 | static let shared = RecordedMediaPlayback() 13 | 14 | private var audioPlayer = AVAudioPlayer() 15 | 16 | /// Playback the latest record. 17 | public func play(record: URL) { 18 | if audioPlayer.isPlaying { 19 | return 20 | } 21 | 22 | do { 23 | audioPlayer = try AVAudioPlayer(contentsOf: record) 24 | audioPlayer.enableRate = false 25 | audioPlayer.rate = 1.0 26 | audioPlayer.delegate = self 27 | audioPlayer.numberOfLoops = 0 28 | audioPlayer.play() 29 | } catch { 30 | Cache.log.error("Unable to start playback: %@", error.localizedDescription) 31 | } 32 | } 33 | 34 | func stop() { 35 | audioPlayer.stop() 36 | } 37 | 38 | func restartPlayer() { 39 | audioPlayer.stop() 40 | audioPlayer.currentTime = 0 41 | audioPlayer.play() 42 | } 43 | } 44 | 45 | extension RecordedMediaPlayback: AVAudioPlayerDelegate{ 46 | func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) { 47 | } 48 | 49 | func audioPlayerDecodeErrorDidOccur(_ player: AVAudioPlayer, error: Error?) { 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Tinodios/Settings.bundle/ConnectionSettings.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | StringsTable 6 | Root 7 | PreferenceSpecifiers 8 | 9 | 10 | Type 11 | PSTextFieldSpecifier 12 | Title 13 | Host name 14 | Key 15 | host_name_preference 16 | DefaultValue 17 | 127.0.0.1:6060 18 | IsSecure 19 | 20 | KeyboardType 21 | Alphabet 22 | AutocapitalizationType 23 | None 24 | AutocorrectionType 25 | No 26 | 27 | 28 | Type 29 | PSToggleSwitchSpecifier 30 | Title 31 | Secure connection 32 | Key 33 | use_tls_preference 34 | DefaultValue 35 | 36 | 37 | 38 | Type 39 | PSMultiValueSpecifier 40 | Title 41 | Wire transport 42 | Key 43 | wire_transport_preference 44 | DefaultValue 45 | default 46 | Titles 47 | 48 | long polling 49 | websocket 50 | default 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /Tinodios/Settings.bundle/Root.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ApplicationGroupContainerIdentifier 6 | group.co.tinode.tinodios.db 7 | StringsTable 8 | Root 9 | PreferenceSpecifiers 10 | 11 | 12 | Type 13 | PSTitleValueSpecifier 14 | Title 15 | Bundle Version 16 | Key 17 | bundle_version 18 | DefaultValue 19 | 0 20 | 21 | 22 | Type 23 | PSChildPaneSpecifier 24 | Title 25 | Acknowledgements 26 | File 27 | Acknowledgements 28 | 29 | 30 | Type 31 | PSChildPaneSpecifier 32 | Title 33 | Connection settings 34 | File 35 | ConnectionSettings 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /Tinodios/Settings.bundle/en.lproj/ConnectionSettings.strings: -------------------------------------------------------------------------------- 1 | /* A single strings file, whose title is specified in your preferences schema. The strings files provide the localized content to display to the user for each of your preferences. */ 2 | 3 | "Wire transport" = "Wire transport"; 4 | "Host name" = "Host name"; 5 | "Use TLS" = "Use TLS"; 6 | -------------------------------------------------------------------------------- /Tinodios/Settings.bundle/en.lproj/Root.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Tinodios/Settings.bundle/en.lproj/Root.strings -------------------------------------------------------------------------------- /Tinodios/Settings.bundle/es.lproj/ConnectionSettings.strings: -------------------------------------------------------------------------------- 1 | /* (No Comment) */ 2 | "Host name" = "Nombre de host"; 3 | 4 | /* (No Comment) */ 5 | "Use TLS" = "Usar TLS"; 6 | 7 | /* A single strings file, whose title is specified in your preferences schema. The strings files provide the localized content to display to the user for each of your preferences. */ 8 | "Wire transport" = "Transporte por cable"; 9 | 10 | -------------------------------------------------------------------------------- /Tinodios/Settings.bundle/es.lproj/Root.strings: -------------------------------------------------------------------------------- 1 | /* A single strings file, whose title is specified in your preferences schema. The strings files provide the localized content to display to the user for each of your preferences. */ 2 | "Connection settings" = "Ajustes de conexión"; 3 | 4 | -------------------------------------------------------------------------------- /Tinodios/Settings.bundle/ru.lproj/ConnectionSettings.strings: -------------------------------------------------------------------------------- 1 | /* (No Comment) */ 2 | "Host name" = "Имя сервера"; 3 | 4 | /* (No Comment) */ 5 | "Use TLS" = "Использовать TLS"; 6 | 7 | /* A single strings file, whose title is specified in your preferences schema. The strings files provide the localized content to display to the user for each of your preferences. */ 8 | "Wire transport" = "Протокол обмена"; 9 | 10 | -------------------------------------------------------------------------------- /Tinodios/Settings.bundle/ru.lproj/Root.strings: -------------------------------------------------------------------------------- 1 | /* A single strings file, whose title is specified in your preferences schema. The strings files provide the localized content to display to the user for each of your preferences. */ 2 | "Connection settings" = "Настройки соединения"; 3 | 4 | -------------------------------------------------------------------------------- /Tinodios/Settings.bundle/uk.lproj/ConnectionSettings.strings: -------------------------------------------------------------------------------- 1 | /* (No Comment) */ 2 | "Host name" = "Назва сервера"; 3 | 4 | /* (No Comment) */ 5 | "Use TLS" = "Використовувати TLS"; 6 | 7 | /* A single strings file, whose title is specified in your preferences schema. The strings files provide the localized content to display to the user for each of your preferences. */ 8 | "Wire transport" = "Протокол обміну"; 9 | 10 | -------------------------------------------------------------------------------- /Tinodios/Settings.bundle/uk.lproj/Root.strings: -------------------------------------------------------------------------------- 1 | /* A single strings file, whose title is specified in your preferences schema. The strings files provide the localized content to display to the user for each of your preferences. */ 2 | "Connection settings" = "Налаштування з'єднання"; 3 | 4 | -------------------------------------------------------------------------------- /Tinodios/Settings.bundle/zh-Hans.lproj/ConnectionSettings.strings: -------------------------------------------------------------------------------- 1 | /* (No Comment) */ 2 | "Host name" = "主机名"; 3 | 4 | /* (No Comment) */ 5 | "Use TLS" = "使用TLS"; 6 | 7 | /* A single strings file, whose title is specified in your preferences schema. The strings files provide the localized content to display to the user for each of your preferences. */ 8 | "Wire transport" = "电线运输"; 9 | 10 | -------------------------------------------------------------------------------- /Tinodios/Settings.bundle/zh-Hans.lproj/Root.strings: -------------------------------------------------------------------------------- 1 | /* A single strings file, whose title is specified in your preferences schema. The strings files provide the localized content to display to the user for each of your preferences. */ 2 | "Connection settings" = "连接设置"; 3 | 4 | -------------------------------------------------------------------------------- /Tinodios/Settings.bundle/zh-Hant.lproj/ConnectionSettings.strings: -------------------------------------------------------------------------------- 1 | /* (No Comment) */ 2 | "Host name" = "主機名稱"; 3 | 4 | /* (No Comment) */ 5 | "Use TLS" = "使用TLS"; 6 | 7 | /* A single strings file, whose title is specified in your preferences schema. The strings files provide the localized content to display to the user for each of your preferences. */ 8 | "Wire transport" = "電線運輸"; 9 | 10 | -------------------------------------------------------------------------------- /Tinodios/Settings.bundle/zh-Hant.lproj/Root.strings: -------------------------------------------------------------------------------- 1 | /* A single strings file, whose title is specified in your preferences schema. The strings files provide the localized content to display to the user for each of your preferences. */ 2 | "Connection settings" = "連線設定"; 3 | 4 | -------------------------------------------------------------------------------- /Tinodios/SettingsNotificationsViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SettingsNotificationsViewController.swift 3 | // Tinodios 4 | // 5 | // Copyright © 2020 Tinode. All rights reserved. 6 | // 7 | 8 | import TinodeSDK 9 | import TinodiosDB 10 | import UIKit 11 | 12 | class SettingsNotificationsViewController: UITableViewController { 13 | @IBOutlet weak var incognitoModeSwitch: UISwitch! 14 | @IBOutlet weak var sendReadReceiptsSwitch: UISwitch! 15 | @IBOutlet weak var sendTypingNotificationsSwitch: UISwitch! 16 | 17 | weak var me: DefaultMeTopic! 18 | 19 | override func viewDidLoad() { 20 | super.viewDidLoad() 21 | setup() 22 | } 23 | override func viewDidAppear(_ animated: Bool) { 24 | super.viewDidAppear(animated) 25 | 26 | reloadData() 27 | } 28 | 29 | private func setup() { 30 | self.me = Cache.tinode.getMeTopic()! 31 | } 32 | 33 | private func reloadData() { 34 | // Read notifications and typing indicator checkboxes. 35 | self.incognitoModeSwitch.setOn(me.isMuted, animated: false) 36 | self.sendReadReceiptsSwitch.setOn( 37 | SharedUtils.kAppDefaults.bool(forKey: SharedUtils.kTinodePrefReadReceipts), 38 | animated: false) 39 | self.sendTypingNotificationsSwitch.setOn( 40 | SharedUtils.kAppDefaults.bool(forKey: SharedUtils.kTinodePrefTypingNotifications), 41 | animated: false) 42 | } 43 | 44 | @IBAction func incognitoModeClicked(_ sender: Any) { 45 | let isChecked = incognitoModeSwitch.isOn 46 | self.me.updateMuted(muted: isChecked).then( 47 | onSuccess: UiUtils.ToastSuccessHandler, 48 | onFailure: { err in 49 | DispatchQueue.main.async { self.incognitoModeSwitch.isOn = !isChecked } 50 | return UiUtils.ToastFailureHandler(err: err) 51 | }).thenFinally({ 52 | DispatchQueue.main.async { self.reloadData() } 53 | }) 54 | } 55 | 56 | @IBAction func readReceiptsClicked(_ sender: Any) { 57 | SharedUtils.kAppDefaults.set(self.sendReadReceiptsSwitch.isOn, forKey: SharedUtils.kTinodePrefReadReceipts) 58 | } 59 | 60 | @IBAction func typingNotificationsClicked(_ sender: Any) { 61 | SharedUtils.kAppDefaults.set(self.sendTypingNotificationsSwitch.isOn, forKey: SharedUtils.kTinodePrefTypingNotifications) 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "ios-logo-1024-20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "ios-logo-1024-20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "ios-logo-1024-29@2x.png", 19 | "scale" : "2x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "ios-logo-1024-29@3x.png", 25 | "scale" : "3x" 26 | }, 27 | { 28 | "size" : "40x40", 29 | "idiom" : "iphone", 30 | "filename" : "ios-logo-1024-40@2x.png", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "ios-logo-1024-40@3x.png", 37 | "scale" : "3x" 38 | }, 39 | { 40 | "size" : "60x60", 41 | "idiom" : "iphone", 42 | "filename" : "ios-logo-1024-60@2x.png", 43 | "scale" : "2x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "ios-logo-1024-60@3x.png", 49 | "scale" : "3x" 50 | }, 51 | { 52 | "size" : "20x20", 53 | "idiom" : "ipad", 54 | "filename" : "ios-logo-1024-20.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "ios-logo-1024-20@2x.png", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "size" : "29x29", 65 | "idiom" : "ipad", 66 | "filename" : "ios-logo-1024-29.png", 67 | "scale" : "1x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "ios-logo-1024-29@2x.png", 73 | "scale" : "2x" 74 | }, 75 | { 76 | "size" : "40x40", 77 | "idiom" : "ipad", 78 | "filename" : "ios-logo-1024-40.png", 79 | "scale" : "1x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "ios-logo-1024-40@2x.png", 85 | "scale" : "2x" 86 | }, 87 | { 88 | "size" : "76x76", 89 | "idiom" : "ipad", 90 | "filename" : "ios-logo-1024-76.png", 91 | "scale" : "1x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "ios-logo-1024-76@2x.png", 97 | "scale" : "2x" 98 | }, 99 | { 100 | "size" : "83.5x83.5", 101 | "idiom" : "ipad", 102 | "filename" : "ios-logo-1024-83.5@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "1024x1024", 107 | "idiom" : "ios-marketing", 108 | "filename" : "ios-logo-1024-1024.png", 109 | "scale" : "1x" 110 | } 111 | ], 112 | "info" : { 113 | "version" : 1, 114 | "author" : "xcode" 115 | } 116 | } -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/AppIcon.appiconset/ios-logo-1024-1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Tinodios/Supporting Files/Assets.xcassets/AppIcon.appiconset/ios-logo-1024-1024.png -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/AppIcon.appiconset/ios-logo-1024-20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Tinodios/Supporting Files/Assets.xcassets/AppIcon.appiconset/ios-logo-1024-20.png -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/AppIcon.appiconset/ios-logo-1024-20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Tinodios/Supporting Files/Assets.xcassets/AppIcon.appiconset/ios-logo-1024-20@2x.png -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/AppIcon.appiconset/ios-logo-1024-20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Tinodios/Supporting Files/Assets.xcassets/AppIcon.appiconset/ios-logo-1024-20@3x.png -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/AppIcon.appiconset/ios-logo-1024-29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Tinodios/Supporting Files/Assets.xcassets/AppIcon.appiconset/ios-logo-1024-29.png -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/AppIcon.appiconset/ios-logo-1024-29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Tinodios/Supporting Files/Assets.xcassets/AppIcon.appiconset/ios-logo-1024-29@2x.png -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/AppIcon.appiconset/ios-logo-1024-29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Tinodios/Supporting Files/Assets.xcassets/AppIcon.appiconset/ios-logo-1024-29@3x.png -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/AppIcon.appiconset/ios-logo-1024-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Tinodios/Supporting Files/Assets.xcassets/AppIcon.appiconset/ios-logo-1024-40.png -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/AppIcon.appiconset/ios-logo-1024-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Tinodios/Supporting Files/Assets.xcassets/AppIcon.appiconset/ios-logo-1024-40@2x.png -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/AppIcon.appiconset/ios-logo-1024-40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Tinodios/Supporting Files/Assets.xcassets/AppIcon.appiconset/ios-logo-1024-40@3x.png -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/AppIcon.appiconset/ios-logo-1024-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Tinodios/Supporting Files/Assets.xcassets/AppIcon.appiconset/ios-logo-1024-60@2x.png -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/AppIcon.appiconset/ios-logo-1024-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Tinodios/Supporting Files/Assets.xcassets/AppIcon.appiconset/ios-logo-1024-60@3x.png -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/AppIcon.appiconset/ios-logo-1024-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Tinodios/Supporting Files/Assets.xcassets/AppIcon.appiconset/ios-logo-1024-76.png -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/AppIcon.appiconset/ios-logo-1024-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Tinodios/Supporting Files/Assets.xcassets/AppIcon.appiconset/ios-logo-1024-76@2x.png -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/AppIcon.appiconset/ios-logo-1024-83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Tinodios/Supporting Files/Assets.xcassets/AppIcon.appiconset/ios-logo-1024-83.5@2x.png -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/Offline.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "colors" : [ 7 | { 8 | "idiom" : "universal", 9 | "color" : { 10 | "color-space" : "srgb", 11 | "components" : { 12 | "red" : "0xE0", 13 | "alpha" : "1.000", 14 | "blue" : "0xE0", 15 | "green" : "0xE0" 16 | } 17 | } 18 | } 19 | ] 20 | } -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/Online.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "colors" : [ 7 | { 8 | "idiom" : "universal", 9 | "color" : { 10 | "color-space" : "srgb", 11 | "components" : { 12 | "red" : "0x40", 13 | "alpha" : "1.000", 14 | "blue" : "0x40", 15 | "green" : "0xC0" 16 | } 17 | } 18 | } 19 | ] 20 | } -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/bell.badge.symbolset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | }, 6 | "symbols" : [ 7 | { 8 | "filename" : "bell.badge.svg", 9 | "idiom" : "universal" 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/broken-image.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "broken-image.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "broken-image@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "broken-image@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | }, 23 | "properties" : { 24 | "template-rendering-intent" : "template" 25 | } 26 | } -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/broken-image.imageset/broken-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Tinodios/Supporting Files/Assets.xcassets/broken-image.imageset/broken-image.png -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/broken-image.imageset/broken-image@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Tinodios/Supporting Files/Assets.xcassets/broken-image.imageset/broken-image@2x.png -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/broken-image.imageset/broken-image@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Tinodios/Supporting Files/Assets.xcassets/broken-image.imageset/broken-image@3x.png -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/checkerboard.shield.symbolset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | }, 6 | "symbols" : [ 7 | { 8 | "filename" : "checkerboard.shield.svg", 9 | "idiom" : "universal" 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/done-30.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "done-30.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "done-30@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "done-30@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | }, 23 | "properties" : { 24 | "template-rendering-intent" : "template" 25 | } 26 | } -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/done-30.imageset/done-30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Tinodios/Supporting Files/Assets.xcassets/done-30.imageset/done-30.png -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/done-30.imageset/done-30@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Tinodios/Supporting Files/Assets.xcassets/done-30.imageset/done-30@2x.png -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/done-30.imageset/done-30@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Tinodios/Supporting Files/Assets.xcassets/done-30.imageset/done-30@3x.png -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/done-all-30.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "done-all-30.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "done-all-30@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "done-all-30@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | }, 23 | "properties" : { 24 | "template-rendering-intent" : "template" 25 | } 26 | } -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/done-all-30.imageset/done-all-30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Tinodios/Supporting Files/Assets.xcassets/done-all-30.imageset/done-all-30.png -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/done-all-30.imageset/done-all-30@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Tinodios/Supporting Files/Assets.xcassets/done-all-30.imageset/done-all-30@2x.png -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/done-all-30.imageset/done-all-30@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Tinodios/Supporting Files/Assets.xcassets/done-all-30.imageset/done-all-30@3x.png -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/exclamationmark.triangle.symbolset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | }, 6 | "symbols" : [ 7 | { 8 | "filename" : "exclamationmark.triangle.svg", 9 | "idiom" : "universal" 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/eye-30.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "eye-30.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "eye-30@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "eye-30@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/eye-30.imageset/eye-30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Tinodios/Supporting Files/Assets.xcassets/eye-30.imageset/eye-30.png -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/eye-30.imageset/eye-30@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Tinodios/Supporting Files/Assets.xcassets/eye-30.imageset/eye-30@2x.png -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/eye-30.imageset/eye-30@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Tinodios/Supporting Files/Assets.xcassets/eye-30.imageset/eye-30@3x.png -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/file-audio-125.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "file-audio-125.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "file-audio-125@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "file-audio-125@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | }, 23 | "properties" : { 24 | "template-rendering-intent" : "template" 25 | } 26 | } -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/file-audio-125.imageset/file-audio-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Tinodios/Supporting Files/Assets.xcassets/file-audio-125.imageset/file-audio-125.png -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/file-audio-125.imageset/file-audio-125@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Tinodios/Supporting Files/Assets.xcassets/file-audio-125.imageset/file-audio-125@2x.png -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/file-audio-125.imageset/file-audio-125@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Tinodios/Supporting Files/Assets.xcassets/file-audio-125.imageset/file-audio-125@3x.png -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/file-image-125.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "file-image-125.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "file-image-125@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "file-image-125@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | }, 23 | "properties" : { 24 | "template-rendering-intent" : "template" 25 | } 26 | } -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/file-image-125.imageset/file-image-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Tinodios/Supporting Files/Assets.xcassets/file-image-125.imageset/file-image-125.png -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/file-image-125.imageset/file-image-125@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Tinodios/Supporting Files/Assets.xcassets/file-image-125.imageset/file-image-125@2x.png -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/file-image-125.imageset/file-image-125@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Tinodios/Supporting Files/Assets.xcassets/file-image-125.imageset/file-image-125@3x.png -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/file-text-125.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "file-text-125.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "file-text-125@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "file-text-125@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | }, 23 | "properties" : { 24 | "template-rendering-intent" : "template" 25 | } 26 | } -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/file-text-125.imageset/file-text-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Tinodios/Supporting Files/Assets.xcassets/file-text-125.imageset/file-text-125.png -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/file-text-125.imageset/file-text-125@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Tinodios/Supporting Files/Assets.xcassets/file-text-125.imageset/file-text-125@2x.png -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/file-text-125.imageset/file-text-125@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Tinodios/Supporting Files/Assets.xcassets/file-text-125.imageset/file-text-125@3x.png -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/file-video-125.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "file-video-125.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "file-video-125@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "file-video-125@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | }, 23 | "properties" : { 24 | "template-rendering-intent" : "template" 25 | } 26 | } -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/file-video-125.imageset/file-video-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Tinodios/Supporting Files/Assets.xcassets/file-video-125.imageset/file-video-125.png -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/file-video-125.imageset/file-video-125@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Tinodios/Supporting Files/Assets.xcassets/file-video-125.imageset/file-video-125@2x.png -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/file-video-125.imageset/file-video-125@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Tinodios/Supporting Files/Assets.xcassets/file-video-125.imageset/file-video-125@3x.png -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/file.symbolset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | }, 6 | "symbols" : [ 7 | { 8 | "filename" : "doc.svg", 9 | "idiom" : "universal" 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/image-wait.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "ios-image-wait.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "ios-image-wait@2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "ios-image-wait@3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/image-wait.imageset/ios-image-wait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Tinodios/Supporting Files/Assets.xcassets/image-wait.imageset/ios-image-wait.png -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/image-wait.imageset/ios-image-wait@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Tinodios/Supporting Files/Assets.xcassets/image-wait.imageset/ios-image-wait@2x.png -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/image-wait.imageset/ios-image-wait@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Tinodios/Supporting Files/Assets.xcassets/image-wait.imageset/ios-image-wait@3x.png -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/important.symbolset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | }, 6 | "symbols" : [ 7 | { 8 | "filename" : "exclamationmark.circle.svg", 9 | "idiom" : "universal" 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/in-progress-30.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "in-progress-30.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "in-progress-30@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "in-progress-30@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | }, 23 | "properties" : { 24 | "template-rendering-intent" : "template" 25 | } 26 | } -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/in-progress-30.imageset/in-progress-30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Tinodios/Supporting Files/Assets.xcassets/in-progress-30.imageset/in-progress-30.png -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/in-progress-30.imageset/in-progress-30@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Tinodios/Supporting Files/Assets.xcassets/in-progress-30.imageset/in-progress-30@2x.png -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/in-progress-30.imageset/in-progress-30@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Tinodios/Supporting Files/Assets.xcassets/in-progress-30.imageset/in-progress-30@3x.png -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/info.symbolset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | }, 6 | "symbols" : [ 7 | { 8 | "filename" : "info.circle.svg", 9 | "idiom" : "universal" 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/invisible-30.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "invisible-30.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "invisible-30@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "invisible-30@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/invisible-30.imageset/invisible-30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Tinodios/Supporting Files/Assets.xcassets/invisible-30.imageset/invisible-30.png -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/invisible-30.imageset/invisible-30@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Tinodios/Supporting Files/Assets.xcassets/invisible-30.imageset/invisible-30@2x.png -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/invisible-30.imageset/invisible-30@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Tinodios/Supporting Files/Assets.xcassets/invisible-30.imageset/invisible-30@3x.png -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/logo-ios.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "logo-ios.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "logo-ios@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "logo-ios@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/logo-ios.imageset/logo-ios.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Tinodios/Supporting Files/Assets.xcassets/logo-ios.imageset/logo-ios.png -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/logo-ios.imageset/logo-ios@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Tinodios/Supporting Files/Assets.xcassets/logo-ios.imageset/logo-ios@2x.png -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/logo-ios.imageset/logo-ios@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/Tinodios/Supporting Files/Assets.xcassets/logo-ios.imageset/logo-ios@3x.png -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/paperclip.symbolset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | }, 6 | "symbols" : [ 7 | { 8 | "filename" : "paperclip.svg", 9 | "idiom" : "universal" 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/pause.circle.symbolset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | }, 6 | "symbols" : [ 7 | { 8 | "filename" : "pause.circle.svg", 9 | "idiom" : "universal" 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/play.circle.fill.symbolset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | }, 6 | "symbols" : [ 7 | { 8 | "filename" : "play.circle.fill.svg", 9 | "idiom" : "universal" 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/play.fill.symbolset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | }, 6 | "symbols" : [ 7 | { 8 | "filename" : "play.fill.svg", 9 | "idiom" : "universal" 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/puzzlepiece.extension.symbolset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | }, 6 | "symbols" : [ 7 | { 8 | "filename" : "puzzlepiece.extension.svg", 9 | "idiom" : "universal" 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/rectangle.3.group.symbolset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | }, 6 | "symbols" : [ 7 | { 8 | "filename" : "rectangle.3.group.svg", 9 | "idiom" : "universal" 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/rectangle.portrait.and.arrow.right.symbolset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | }, 6 | "symbols" : [ 7 | { 8 | "filename" : "rectangle.portrait.and.arrow.right.svg", 9 | "idiom" : "universal" 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/speaker.wave.3.fill.symbolset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | }, 6 | "symbols" : [ 7 | { 8 | "filename" : "speaker.wave.3.fill.svg", 9 | "idiom" : "universal" 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/stop.circle.symbolset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | }, 6 | "symbols" : [ 7 | { 8 | "filename" : "stop.circle.svg", 9 | "idiom" : "universal" 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/vc.fill.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "vc.fill.svg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | }, 21 | "properties" : { 22 | "template-rendering-intent" : "template" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/vc.fill.imageset/vc.fill.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/vc.slash.fill.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "vc.slash.fill.svg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | }, 21 | "properties" : { 22 | "template-rendering-intent" : "template" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/vc.slash.fill.imageset/vc.slash.fill.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/xmark.bin.fill.symbolset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | }, 6 | "symbols" : [ 7 | { 8 | "filename" : "xmark.bin.fill.svg", 9 | "idiom" : "universal" 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/xmark.bin.symbolset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | }, 6 | "symbols" : [ 7 | { 8 | "filename" : "xmark.bin.svg", 9 | "idiom" : "universal" 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Assets.xcassets/xmark.bubble.symbolset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | }, 6 | "symbols" : [ 7 | { 8 | "filename" : "xmark.bubble.svg", 9 | "idiom" : "universal" 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /Tinodios/Supporting Files/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /Tinodios/Supporting Files/es.lproj/LaunchScreen.strings: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Tinodios/Supporting Files/ru.lproj/LaunchScreen.strings: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Tinodios/Supporting Files/uk.lproj/LaunchScreen.strings: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Tinodios/Supporting Files/zh-Hans.lproj/LaunchScreen.strings: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Tinodios/Supporting Files/zh-Hant.lproj/LaunchScreen.strings: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Tinodios/Tinodios.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | aps-environment 6 | production 7 | com.apple.developer.associated-domains 8 | 9 | applinks:*.tinode.co 10 | 11 | com.apple.developer.icloud-container-identifiers 12 | 13 | iCloud.co.tinode.tinodios 14 | 15 | com.apple.developer.icloud-services 16 | 17 | CloudDocuments 18 | 19 | com.apple.developer.ubiquity-container-identifiers 20 | 21 | iCloud.co.tinode.tinodios 22 | 23 | com.apple.developer.ubiquity-kvstore-identifier 24 | $(TeamIdentifierPrefix)$(CFBundleIdentifier) 25 | com.apple.security.application-groups 26 | 27 | group.co.tinode.tinodios.db 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /Tinodios/account/ContactsManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContactsManager.swift 3 | // 4 | // Copyright © 2019-2022 Tinode LLC. All rights reserved. 5 | // 6 | 7 | import Foundation 8 | import TinodeSDK 9 | import TinodiosDB 10 | 11 | public class ContactHolder { 12 | var pub: TheCard? 13 | var uniqueId: String? 14 | // This is used when the contact was found in search: what was matched. 15 | var subtitle: String? 16 | 17 | init(pub: TheCard?, uniqueId: String?, subtitle: String? = nil) { 18 | self.pub = pub 19 | self.uniqueId = uniqueId 20 | self.subtitle = subtitle 21 | } 22 | } 23 | 24 | class ContactsManager { 25 | public static var `default` = ContactsManager() 26 | 27 | private let queue = DispatchQueue(label: "co.tinode.contacts") 28 | private let userDb: UserDb! 29 | init() { 30 | self.userDb = BaseDb.sharedInstance.userDb! 31 | } 32 | public func processSubscription(sub: SubscriptionProto) { 33 | queue.sync { 34 | processSubsciptionInternal(sub: sub) 35 | } 36 | } 37 | private func processSubsciptionInternal(sub: SubscriptionProto) { 38 | guard let subId = sub.uniqueId else { return } 39 | let userId = userDb.getId(for: subId) 40 | if (sub.deleted) != nil { 41 | // Subscription deleted. Delete the user. 42 | if userId >= 0 { 43 | userDb.deleteRow(for: userId) 44 | } 45 | } else { 46 | if userId >= 0 { 47 | // Existing contact. 48 | if !userDb.update(userId: userId, updated: sub.updated, serializedPub: sub.serializePub()) { 49 | Cache.log.error("Could not update user db for userId [%d], subId [%@]", userId, subId) 50 | } 51 | } else { 52 | // New contact. 53 | userDb.insert(sub: sub) 54 | } 55 | } 56 | } 57 | 58 | public func processDescription(uid: String?, desc: Description) { 59 | queue.sync { 60 | processDescriptionInternal(uid: uid, desc: desc) 61 | } 62 | } 63 | 64 | private func processDescriptionInternal(uid: String?, desc: Description) { 65 | guard let uid = uid else { return } 66 | if let user = userDb.readOne(uid: uid) as? User { 67 | // Existing contact. 68 | if user.merge(from: desc) { 69 | userDb.update(user: user) 70 | } 71 | } else { 72 | let user = User(uid: uid, desc: desc) 73 | _ = userDb.insert(user: user) 74 | } 75 | } 76 | 77 | // Returns contacts from the sqlite database's UserDb. 78 | public func fetchContacts(withUids uids: [String]? = nil) -> [ContactHolder]? { 79 | let users: [UserProto]? 80 | if let uids = uids { 81 | users = userDb.read(uids: uids) 82 | } else { 83 | guard let uid = Cache.tinode.myUid else { return nil } 84 | users = userDb.readAll(for: uid) 85 | } 86 | // Turn users into contacts. 87 | return users?.map { user in 88 | let q = user as! DefaultUser 89 | return ContactHolder(pub: q.pub, uniqueId: q.uid) 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /Tinodios/en.lproj/Main.strings: -------------------------------------------------------------------------------- 1 | /* Class = "UITextView"; text = "Description"; ObjectID = "D3z-yf-zJA"; */ 2 | "D3z-yf-zJA.text" = "Topic subtitle (private)"; 3 | 4 | /* Class = "UILabel"; text = "Manage tags"; ObjectID = "eHa-mE-ZbY"; */ 5 | "eHa-mE-ZbY.text" = "Manage"; 6 | 7 | /* Class = "UITextView"; text = "Title"; ObjectID = "ity-bg-zqr"; */ 8 | "ity-bg-zqr.text" = "Topic title (public)"; 9 | 10 | /* Class = "UILabel"; text = "Group or user ID"; ObjectID = "RA0-dx-dSp"; */ 11 | "RA0-dx-dSp.text" = "Topic or user ID"; 12 | 13 | /* Class = "UITextField"; placeholder = "Email"; ObjectID = "zmL-3Y-R2r"; */ 14 | "zmL-3Y-R2r.placeholder" = "Email or phone number"; 15 | 16 | -------------------------------------------------------------------------------- /Tinodios/es.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Privacy - Camera Usage Description */ 2 | "NSCameraUsageDescription" = "Tinode toma fotos con la cámara para usarlas como avatar o para enviarlas a tus contactos"; 3 | 4 | /* Privacy - Contacts Usage Description */ 5 | "NSContactsUsageDescription" = "Tinode envía solo correos electrónicos y números de teléfono al servidor de Tinode para ayudarte a conectarte con otros usuarios"; 6 | 7 | /* Privacy - Microphone Usage Description */ 8 | "NSMicrophoneUsageDescription" = "Tinode utiliza el micrófono para grabar los mensajes de audio que envías a tus contactos"; 9 | 10 | /* Privacy - Photo Library Additions Usage Description */ 11 | "NSPhotoLibraryAddUsageDescription" = "Las imágenes e imágenes de Tinode se pueden guardar en la fototeca"; 12 | 13 | /* Privacy - Photo Library Usage Description */ 14 | "NSPhotoLibraryUsageDescription" = "Tinode necesita acceso a tus fotos para que puedas enviarlas a tus contactos"; 15 | 16 | -------------------------------------------------------------------------------- /Tinodios/format/AsyncImageTextAttachment.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AsyncTextAttachment.swift 3 | // 4 | // Copyright © 2020-2022 Tinode LLC. All rights reserved. 5 | // 6 | 7 | import TinodeSDK 8 | import UIKit 9 | 10 | /// An image text attachment which gets updated after loading an image from URL. 11 | public class AsyncImageTextAttachment: EntityTextAttachment { 12 | /// Container to be notified when the image is updated: successfully fetched or failed. 13 | private weak var textContainer: NSTextContainer? 14 | 15 | /// Source of the image 16 | public var url: URL 17 | 18 | /// Postprocessing callback after the image's been downloaded 19 | private var postprocessing: ((UIImage) -> UIImage?)? 20 | 21 | /// Designated initializer 22 | public init(url: URL, afterDownloaded: ((UIImage) -> UIImage?)? = nil) { 23 | self.url = url 24 | self.postprocessing = afterDownloaded 25 | 26 | super.init(data: nil, ofType: nil) 27 | self.type = "image" 28 | } 29 | 30 | required public init?(coder aDecoder: NSCoder) { 31 | fatalError("not implemented") 32 | } 33 | 34 | public func startDownload(onError errorImage: UIImage) { 35 | Utils.fetchTinodeResource(from: url) 36 | .then(onSuccess: { value in 37 | if let done = self.postprocessing { 38 | self.image = done(value!) ?? errorImage 39 | } else { 40 | self.image = value 41 | } 42 | return nil 43 | }, onFailure: { error in 44 | self.image = errorImage 45 | Cache.log.info("Failed to download image '%@': %@", self.url.absoluteString, error.localizedDescription) 46 | return nil 47 | }) 48 | .thenFinally { 49 | DispatchQueue.main.async { 50 | // Force container redraw. 51 | let length = self.textContainer?.layoutManager?.textStorage?.length 52 | self.textContainer?.layoutManager?.invalidateDisplay(forCharacterRange: NSRange(location: 0, length: length ?? 1)) 53 | } 54 | } 55 | } 56 | 57 | public override func image(forBounds imageBounds: CGRect, textContainer: NSTextContainer?, characterIndex charIndex: Int) -> UIImage? { 58 | // Keep reference to text container. It will be updated if image changes. 59 | self.textContainer = textContainer 60 | return image 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Tinodios/format/ButtonAttachment.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ButtonAttachment.swift 3 | // 4 | // Copyright © 2019-2022 Tinode LLC. All rights reserved. 5 | // 6 | 7 | import UIKit 8 | import TinodeSDK 9 | 10 | // An NSTextAttachment which draws a button-like image for use in Drafty forms. 11 | class ButtonAttachment: NSTextAttachment { 12 | private enum Constants { 13 | // Mimumum button width in points 14 | static let kMinWidth: CGFloat = 40 15 | // Button height mulitplier (forntHeight * 1.4) 16 | static let kHeightMultiplier: CGFloat = 1.4 17 | // Button width padding in characters. 18 | static let kWidthPadding: CGFloat = 3 19 | static let kDefaultButtonBackgroundColor: UIColor = UIColor.white.withAlphaComponent(0.8) 20 | } 21 | 22 | var payload: URL? 23 | var faceText: NSAttributedString 24 | 25 | let traceBorder: Bool 26 | let widthPadding: CGFloat 27 | let heightMultiplier: CGFloat 28 | let backgroundColor: UIColor 29 | 30 | init(face: NSAttributedString, data: URL?, traceBorder: Bool = false, widthPadding: CGFloat = Constants.kWidthPadding, heightMultiplier: CGFloat = Constants.kHeightMultiplier, backgroundColor: UIColor = Constants.kDefaultButtonBackgroundColor, verticalOffset: CGFloat = 0) { 31 | faceText = face 32 | payload = data 33 | self.traceBorder = traceBorder 34 | self.widthPadding = widthPadding 35 | self.heightMultiplier = heightMultiplier 36 | self.backgroundColor = backgroundColor 37 | super.init(data: nil, ofType: "public.text") 38 | let textBounds = face.boundingRect(with: CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude), context: nil) 39 | 40 | // Calculate button width: string width + some characters extra, but no less than kMinWidth 41 | let width = max(Constants.kMinWidth, textBounds.width / CGFloat(face.length) * (CGFloat(face.length) + self.widthPadding)) 42 | 43 | image = renderButtonImage(textBounds: textBounds, buttonBounds: CGRect(x: 0, y: 0, width: width, height: textBounds.height * heightMultiplier)) 44 | bounds = CGRect(x: 0, y: verticalOffset, width: width, height: textBounds.height * heightMultiplier) 45 | } 46 | 47 | required init?(coder aDecoder: NSCoder) { 48 | fatalError("init(coder:) has not been implemented") 49 | } 50 | 51 | // Create button as image 52 | private func renderButtonImage(textBounds: CGRect, buttonBounds: CGRect) -> UIImage { 53 | UIGraphicsBeginImageContextWithOptions(CGSize(width: buttonBounds.width, height: buttonBounds.height), false, UIScreen.main.scale) 54 | 55 | defer { UIGraphicsEndImageContext() } 56 | let context = UIGraphicsGetCurrentContext()! 57 | 58 | context.saveGState() 59 | context.clip(to: buttonBounds) 60 | 61 | // Draw background. 62 | context.setFillColor(self.backgroundColor.cgColor) 63 | // UIBezierPath with rounded corners 64 | let bkgRect = buttonBounds.insetBy(dx: 1, dy: 1) 65 | let path = UIBezierPath(roundedRect: bkgRect, cornerRadius: bkgRect.height * 0.5) 66 | path.fill() 67 | if traceBorder { 68 | path.stroke(with: .colorBurn, alpha: 0.67) 69 | } 70 | // Draw string 71 | faceText.draw(at: CGPoint(x: (buttonBounds.width - textBounds.width) * 0.5, y: (buttonBounds.height - textBounds.height) * 0.5)) 72 | context.restoreGState() 73 | 74 | guard let renderedImage = UIGraphicsGetImageFromCurrentImageContext() else { 75 | assertionFailure("Could not create image from context") 76 | return UIImage() 77 | } 78 | return renderedImage 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /Tinodios/format/EntityTextAttachment.swift: -------------------------------------------------------------------------------- 1 | // 2 | // EntityTextAttachment.swift 3 | // Tinodios 4 | // 5 | // Copyright © 2022 Tinode LLC. All rights reserved. 6 | // 7 | 8 | import TinodeSDK 9 | import UIKit 10 | 11 | public protocol EntityTextAttachmentDelegate: AnyObject { 12 | func action(_ action: String, payload: Any?) 13 | } 14 | 15 | public class EntityTextAttachment: NSTextAttachment { 16 | public var draftyEntityKey: Int? 17 | public var type: String? 18 | public var delegate: EntityTextAttachmentDelegate? 19 | } 20 | -------------------------------------------------------------------------------- /Tinodios/format/MultiImageTextAttachment.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MultistateImageTextAttachment.swift 3 | // Tinodios 4 | // 5 | // Copyright © 2022 Tinode LLC. All rights reserved. 6 | // 7 | 8 | import TinodeSDK 9 | import UIKit 10 | 11 | /// An image text attachment with multiple images and ability to flip through them. 12 | public class MultiImageTextAttachment: EntityTextAttachment { 13 | /// Container to be notified when the image is changed. 14 | private weak var textContainer: NSTextContainer? 15 | 16 | var images: [UIImage] 17 | var index: Int = 0 18 | 19 | /// Designated initializer 20 | public init(images: [UIImage]) { 21 | self.images = images 22 | super.init(data: nil, ofType: nil) 23 | } 24 | 25 | required public init?(coder aDecoder: NSCoder) { 26 | fatalError("not implemented") 27 | } 28 | 29 | // Show specific image. 30 | public func setFrame(_ frame: Int) { 31 | index = frame 32 | DispatchQueue.main.async { 33 | // Force container redraw. 34 | let length = self.textContainer?.layoutManager?.textStorage?.length 35 | self.textContainer?.layoutManager?.invalidateDisplay(forCharacterRange: NSRange(location: 0, length: length ?? 1)) 36 | } 37 | } 38 | 39 | /// Show the next image in stack. If the end is reached, go back to the first image. 40 | public func next() { 41 | setFrame((index + 1) % images.count) 42 | } 43 | 44 | /// Reset the attachment to initial state. 45 | public func reset() { 46 | setFrame(0) 47 | } 48 | 49 | public override func image(forBounds imageBounds: CGRect, textContainer: NSTextContainer?, characterIndex charIndex: Int) -> UIImage? { 50 | // Keep reference to text container. It will be updated if image changes. 51 | self.textContainer = textContainer 52 | return images[index] 53 | } 54 | } 55 | 56 | -------------------------------------------------------------------------------- /Tinodios/format/SendForwardedFormatter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SendForwardedFormatter.swift 3 | // Tinodios 4 | // 5 | // Copyright © 2022 Tinode LLC. All rights reserved. 6 | // 7 | 8 | import Foundation 9 | import TinodeSDK 10 | import UIKit 11 | 12 | // Formatter for displaying forwarded previews before they are sent. 13 | class SendForwardedFormatter: QuoteFormatter { 14 | override func apply(type: String?, data: [String : JSONValue]?, key: Int?, content: [FormattedString], stack: [String]?) -> FormattedString { 15 | if let stack = stack, stack.contains("QQ") { 16 | if let type = type, type == "QQ" { 17 | // Quote inside quote, convert to icon. 18 | return self.handleQuoteInsideQuote([]) 19 | } 20 | } 21 | return super.apply(type: type, data: data, key: key, content: content, stack: stack) 22 | } 23 | 24 | func handleQuoteInsideQuote(_ nodes: [FormatNode]) -> FormatNode { 25 | return FormatNode([annotatedIcon(iconName: "text.quote"), FormatNode(" ")]) 26 | } 27 | 28 | override func handleQuote(_ nodes: [FormatNode]) -> FormatNode { 29 | let node = FormatNode(nodes) 30 | node.attachment(Attachment(content: .quote, fullWidth: true)) 31 | return node 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Tinodios/format/SendReplyFormatter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SendReplyFormatter.swift 3 | // Tinodios 4 | // 5 | // Copyright © 2022 Tinode LLC. All rights reserved. 6 | // 7 | 8 | import Foundation 9 | import TinodeSDK 10 | import UIKit 11 | 12 | // TODO: remove? 13 | class SendReplyFormatter: QuoteFormatter { 14 | override func handleQuote(_ nodes: [FormatNode]) -> FormatNode { 15 | let node = FormatNode(nodes) 16 | node.attachment(Attachment(content: .quote, fullWidth: true)) 17 | return node 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Tinodios/ru.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Privacy - Camera Usage Description */ 2 | "NSCameraUsageDescription" = "Tinode использует камеру для того, чтобы создать аватар или для того, чтобы отправить фото вашим контактам"; 3 | 4 | /* Privacy - Contacts Usage Description */ 5 | "NSContactsUsageDescription" = "Tinode сохраняет емейлы и номера телефонов на сервере для того, чтобы найти по ним ваших знакомых"; 6 | 7 | /* Privacy - Microphone Usage Description */ 8 | "NSMicrophoneUsageDescription" = "Tinode использует микрофон для записи аудио, которое вы отправляете в своих сообщениях"; 9 | 10 | /* Privacy - Photo Library Additions Usage Description */ 11 | "NSPhotoLibraryAddUsageDescription" = "Фото и картинки из Tinode могут быть сохранены в фото-библиотеке"; 12 | 13 | /* Privacy - Photo Library Usage Description */ 14 | "NSPhotoLibraryUsageDescription" = "Tinode-у нужно получить доступ к вашим фото для того, чтобы вы могли прикреплять их к сообщениям"; 15 | 16 | -------------------------------------------------------------------------------- /Tinodios/uk.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Privacy - Camera Usage Description */ 2 | "NSCameraUsageDescription" = "Tinode використовує камеру щоб зробити фото в якості аватара, а також, щоб надіслати фото вашим контактам"; 3 | 4 | /* Privacy - Contacts Usage Description */ 5 | "NSContactsUsageDescription" = "Tinode зберігає емейлы і номери телефонів на сервері для того, щоб знайти по ним ваших знайомих"; 6 | 7 | /* Privacy - Microphone Usage Description */ 8 | "NSMicrophoneUsageDescription" = "Tinode використовує мікрофон для запису аудіо, які ви надсилаєте у своїх повідомленнях"; 9 | 10 | /* Privacy - Photo Library Additions Usage Description */ 11 | "NSPhotoLibraryAddUsageDescription" = "Фото і картинки з Tinode можна зберегти в бібліотеці фотографій"; 12 | 13 | /* Privacy - Photo Library Usage Description */ 14 | "NSPhotoLibraryUsageDescription" = "Tinode потрібен доступ до ваших фотографій, щоб ви змогли приєднати їх до повідомлень"; 15 | 16 | -------------------------------------------------------------------------------- /Tinodios/widgets/AvatarWithOnlineIndicator+TypingAnimation.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AvatarWithOnlineIndicator+TypingAnimation.swift 3 | // Tinodios 4 | // 5 | // Copyright © 2019 Tinode. All rights reserved. 6 | // 7 | 8 | import Foundation 9 | import UIKit 10 | 11 | extension AvatarWithOnlineIndicator { 12 | static let kTypingAnimationSize = 4 13 | static let kAnimationColorSequence = [ 14 | UIColor(fromHexCode: 0xFF40C040), 15 | UIColor(fromHexCode: 0xFF30D030), 16 | UIColor(fromHexCode: 0xFF10EE10), 17 | UIColor(fromHexCode: 0xFF00FF00) 18 | ] 19 | // Runs typing animation over the online indicator 20 | // every 1/20th of a second |steps| times. 21 | func presentTypingAnimation(steps: Int) { 22 | guard 1..<100 ~= steps else { 23 | fatalError("Steps must be between 0 and 100.") 24 | } 25 | // Note that we can do it (there will be no race condition), 26 | // since UI thread synchronizes this write and possibly 27 | // other reads/write triggered by timer. 28 | self.tag = steps 29 | guard self.onlineIndicator.subviews.isEmpty else { 30 | // If we are already presenting another typing animation, 31 | // setting tag to |steps| will increase its duration. 32 | return 33 | } 34 | // Add animation view on top of the online indicator. 35 | let animation = UIView(frame: CGRect(x: 0, y: 0, width: AvatarWithOnlineIndicator.kTypingAnimationSize, height: AvatarWithOnlineIndicator.kTypingAnimationSize)) 36 | // Rounded corners. 37 | animation.layer.cornerRadius = CGFloat(AvatarWithOnlineIndicator.kTypingAnimationSize / 2) 38 | animation.layer.masksToBounds = true 39 | self.onlineIndicator.addSubview(animation) 40 | // Place it in the center of the online indicator. 41 | animation.translatesAutoresizingMaskIntoConstraints = false 42 | NSLayoutConstraint.activate([ 43 | animation.heightAnchor.constraint( 44 | equalToConstant: CGFloat(AvatarWithOnlineIndicator.kTypingAnimationSize)), 45 | animation.widthAnchor.constraint( 46 | equalToConstant: CGFloat(AvatarWithOnlineIndicator.kTypingAnimationSize)), 47 | animation.centerXAnchor.constraint(equalTo: animation.superview!.centerXAnchor), 48 | animation.centerYAnchor.constraint(equalTo: animation.superview!.centerYAnchor) 49 | ]) 50 | _ = Timer.scheduledTimer( 51 | timeInterval: 0.05, // 1/20th of a second. 52 | target: self, 53 | selector: #selector(animationStep), 54 | userInfo: nil, 55 | repeats: true) 56 | } 57 | @objc private func animationStep(timer: Timer) { 58 | guard !self.onlineIndicator.subviews.isEmpty else { 59 | timer.invalidate() 60 | return 61 | } 62 | let animationView = self.onlineIndicator.subviews[0] 63 | animationView.backgroundColor = 64 | AvatarWithOnlineIndicator.kAnimationColorSequence[ 65 | self.tag % AvatarWithOnlineIndicator.kAnimationColorSequence.count] 66 | self.tag -= 1 67 | if self.tag <= 0 { 68 | timer.invalidate() 69 | animationView.removeFromSuperview() 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /Tinodios/widgets/AvatarWithOnlineIndicator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AvatarWithOnlineIndicator.swift 3 | // 4 | // Copyright © 2019-2022 Tinode LLC. All rights reserved. 5 | // 6 | 7 | import UIKit 8 | import TinodeSDK 9 | 10 | class AvatarWithOnlineIndicator: UIView { 11 | @IBOutlet var contentView: UIView! 12 | @IBOutlet weak var avatar: RoundImageView! 13 | @IBOutlet weak var onlineIndicator: UIView! 14 | @IBOutlet weak var deletedIndicator: UIImageView! 15 | 16 | override init(frame: CGRect) { 17 | super.init(frame: frame) 18 | loadNib() 19 | } 20 | 21 | required init?(coder aDecoder: NSCoder) { 22 | super.init(coder: aDecoder) 23 | loadNib() 24 | } 25 | 26 | private func loadNib() { 27 | Bundle.main.loadNibNamed("AvatarWithOnlineIndicator", owner: self, options: nil) 28 | addSubview(contentView) 29 | contentView.frame = self.bounds 30 | contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight] 31 | } 32 | 33 | /// Three states: true (show green dot), false (gray dot), nil (no dot). 34 | public var online: Bool? { 35 | didSet { 36 | if deleted { 37 | self.onlineIndicator.isHidden = true 38 | return 39 | } 40 | 41 | guard let online = online else { 42 | self.onlineIndicator.isHidden = true 43 | return 44 | } 45 | self.deletedIndicator.isHidden = true 46 | self.onlineIndicator.isHidden = false 47 | self.onlineIndicator.backgroundColor = online ? 48 | UIColor.init(fromHexCode: 0xFF40C040) : UIColor.init(fromHexCode: 0xFFE0E0E0) 49 | } 50 | } 51 | 52 | /// Three states: true (show green dot), false (gray dot), nil (no dot). 53 | public var deleted: Bool = false { 54 | didSet { 55 | if deleted { 56 | self.deletedIndicator.isHidden = false 57 | self.onlineIndicator.isHidden = true 58 | } else { 59 | self.deletedIndicator.isHidden = true 60 | self.onlineIndicator.isHidden = false 61 | } 62 | } 63 | } 64 | 65 | public func set(pub: TheCard?, id: String?, online: Bool?, deleted: Bool) { 66 | self.avatar.set(pub: pub, id: id, deleted: deleted) 67 | self.online = online 68 | self.deleted = deleted 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Tinodios/widgets/ContactViewCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContactViewCell.swift 3 | // Tinodios 4 | // 5 | // Copyright © 2019 Tinode. All rights reserved. 6 | // 7 | 8 | import UIKit 9 | 10 | protocol ContactViewCellDelegate: AnyObject { 11 | func selected(from: UITableViewCell) 12 | } 13 | 14 | class ContactViewCell: UITableViewCell { 15 | private static let kSelectedBackgroundColor = UIColor(red: 0xC2/255, green: 0xC9/255, blue: 0xF9/255, alpha: 0.5) 16 | private static let kNormalBackgroundColor = UIColor.clear 17 | 18 | public weak var delegate: ContactViewCellDelegate? 19 | 20 | @IBOutlet weak var avatar: RoundImageView! 21 | @IBOutlet weak var title: UILabel! 22 | @IBOutlet weak var subtitle: UILabel! 23 | @IBOutlet var statusLabels: [ContactViewCellStatusLabel]! 24 | 25 | override func awakeFromNib() { 26 | super.awakeFromNib() 27 | } 28 | 29 | override func setSelected(_ selected: Bool, animated: Bool) { 30 | super.setSelected(selected, animated: animated) 31 | 32 | if selected { 33 | delegate?.selected(from: self) 34 | } 35 | } 36 | } 37 | 38 | class ContactViewCellStatusLabel: PaddedLabel { 39 | override init(frame: CGRect) { 40 | super.init(frame: frame) 41 | } 42 | 43 | required init?(coder aDecoder: NSCoder) { 44 | super.init(coder: aDecoder) 45 | } 46 | 47 | override var intrinsicContentSize: CGSize { 48 | let size = super.intrinsicContentSize 49 | let insets = super.textInsets 50 | return CGSize(width: size.width + insets.left + insets.right, 51 | height: size.height + insets.top + insets.bottom) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Tinodios/widgets/ForwardMessageBar.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ForwardMessageBar.swift 3 | // Tinodios 4 | // 5 | // Copyright © 2021 Tinode. All rights reserved. 6 | // 7 | 8 | import UIKit 9 | 10 | class ForwardMessageBar: UIView { 11 | @IBOutlet weak var previewView: RichTextView! 12 | @IBOutlet weak var previewViewHeight: NSLayoutConstraint! 13 | 14 | weak var delegate: (SendMessageBarDelegate & PendingMessagePreviewDelegate)? 15 | 16 | required init?(coder aDecoder: NSCoder) { 17 | super.init(coder: aDecoder) 18 | loadNib() 19 | } 20 | 21 | override init(frame: CGRect) { 22 | super.init(frame: frame) 23 | loadNib() 24 | } 25 | 26 | private func loadNib() { 27 | let nib = UINib(nibName: "ForwardMessageBar", bundle: Bundle(for: type(of: self))) 28 | let nibView = nib.instantiate(withOwner: self, options: nil).first as! UIView 29 | nibView.backgroundColor = UIColor.lightGray.withAlphaComponent(0.5) 30 | nibView.translatesAutoresizingMaskIntoConstraints = false 31 | self.autoresizingMask = .flexibleHeight 32 | 33 | addSubview(nibView) 34 | 35 | NSLayoutConstraint.activate([ 36 | nibView.topAnchor.constraint(equalTo: topAnchor), 37 | nibView.bottomAnchor.constraint(equalTo: bottomAnchor), 38 | nibView.rightAnchor.constraint(equalTo: rightAnchor), 39 | nibView.leftAnchor.constraint(equalTo: leftAnchor) 40 | ]) 41 | } 42 | 43 | override var intrinsicContentSize: CGSize { 44 | // Calculate intrinsicContentSize that will fit the preview. 45 | let textSize = self.previewView.sizeThatFits(CGSize(width: self.previewView.bounds.width, height: CGFloat.greatestFiniteMagnitude)) 46 | return CGSize(width: self.bounds.width, height: textSize.height) 47 | } 48 | 49 | @IBAction func cancelPreviewClicked(_ sender: Any) { 50 | self.togglePendingPreviewBar(with: nil) 51 | self.delegate?.dismissPendingMessagePreview() 52 | } 53 | 54 | @IBAction func send(_ sender: Any) { 55 | // The delegate keeps track of the message being forwarded. 56 | // Let it know the user wants the pending message to be sent. 57 | delegate?.sendMessageBar(sendText: "") 58 | } 59 | 60 | public func togglePendingPreviewBar(with message: NSAttributedString?) { 61 | if let message = message, let delegate = self.delegate { 62 | let textBounds = delegate.pendingPreviewMessageSize(forMessage: message) 63 | previewViewHeight.constant = textBounds.height 64 | previewView.attributedText = message 65 | previewView.isHidden = false 66 | } else { 67 | previewViewHeight.constant = CGFloat.zero 68 | previewView.attributedText = nil 69 | previewView.isHidden = true 70 | } 71 | layoutIfNeeded() 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /Tinodios/widgets/MessageMenuItem.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MessageMenuItem.swift 3 | // Tinodios 4 | // 5 | // Copyright © 2019 Tinode. All rights reserved. 6 | // 7 | 8 | import UIKit 9 | 10 | class MessageMenuItem: UIMenuItem { 11 | var seqId: Int = -1 12 | 13 | init(title: String, action: Selector, seqId: Int) { 14 | super.init(title: title, action: action) 15 | self.seqId = seqId 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Tinodios/widgets/MultilineAlertView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MultilineAlertView.swift 3 | // 4 | // Copyright © 2022 Tinode LLC. All rights reserved. 5 | // 6 | 7 | import TinodeSDK 8 | import UIKit 9 | 10 | class MultilineAlertViewController: UIViewController { 11 | private static let kButtonBorderColor = UIColor.lightGray 12 | 13 | @IBOutlet weak var alertView: UIView! 14 | @IBOutlet weak var okButton: UIButton! 15 | @IBOutlet weak var cancelButton: UIButton! 16 | @IBOutlet weak var textEditView: UITextView! 17 | @IBOutlet weak var titleLabel: UILabel! 18 | 19 | private var initialText: String = "" 20 | 21 | public typealias CompletionHandler = ((_: String?) -> Void) 22 | public var completionHandler: CompletionHandler? 23 | 24 | init(with text: String?, placeholder: String? = nil) { 25 | super.init(nibName: nil, bundle: nil) 26 | modalTransitionStyle = .crossDissolve 27 | modalPresentationStyle = .overCurrentContext 28 | 29 | self.initialText = text ?? "" 30 | } 31 | 32 | required init?(coder aDecoder: NSCoder) { 33 | fatalError("init(coder:) has not been implemented") 34 | } 35 | 36 | override func viewDidLoad() { 37 | super.viewDidLoad() 38 | 39 | titleLabel.text = title 40 | cancelButton.addBorder(side: .top, color: MultilineAlertViewController.kButtonBorderColor, width: 0.5) 41 | cancelButton.addBorder(side: .right, color: MultilineAlertViewController.kButtonBorderColor, width: 0.5) 42 | okButton.addBorder(side: .top, color: MultilineAlertViewController.kButtonBorderColor, width: 0.5) 43 | 44 | textEditView.font = UIFont.systemFont(ofSize: 16) 45 | textEditView.layer.cornerRadius = 8 46 | textEditView.text = initialText 47 | textEditView.layer.borderColor = MultilineAlertViewController.kButtonBorderColor.cgColor 48 | textEditView.layer.borderWidth = 0.5 49 | textEditView.becomeFirstResponder() 50 | } 51 | 52 | func show(over viewController: UIViewController?) { 53 | guard let viewController = viewController else { return } 54 | viewController.present(self, animated: true, completion: nil) 55 | } 56 | 57 | // MARK: - Button clicks 58 | @IBAction func cancelClicked(_ sender: Any) { 59 | self.dismiss(animated: true, completion: nil) 60 | } 61 | 62 | @IBAction func okayClicked(_ sender: Any) { 63 | if (textEditView.text ?? "") != initialText { 64 | completionHandler?(textEditView.text) 65 | } 66 | self.dismiss(animated: true, completion: nil) 67 | } 68 | } 69 | 70 | -------------------------------------------------------------------------------- /Tinodios/widgets/PaddedLabel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PaddedLabel.swift 3 | // Tinodios 4 | // 5 | // Copyright © 2019-2022 Tinode. All rights reserved. 6 | // 7 | 8 | import UIKit 9 | 10 | public class PaddedLabel: UILabel { 11 | @IBInspectable var topInset: CGFloat = 0.0 { 12 | didSet { updateInsets() } 13 | } 14 | @IBInspectable var bottomInset: CGFloat = 0.0 { 15 | didSet { updateInsets() } 16 | } 17 | @IBInspectable var leftInset: CGFloat = 0.0 { 18 | didSet { updateInsets() } 19 | } 20 | @IBInspectable var rightInset: CGFloat = 0.0 { 21 | didSet { updateInsets() } 22 | } 23 | @IBInspectable var cornerRadius: CGFloat = 0.0 { 24 | didSet { updateCornerRadius() } 25 | } 26 | 27 | required init?(coder aDecoder: NSCoder) { 28 | super.init(coder: aDecoder) 29 | updateInsets() 30 | updateCornerRadius() 31 | } 32 | 33 | override init(frame: CGRect) { 34 | super.init(frame: frame) 35 | updateInsets() 36 | updateCornerRadius() 37 | } 38 | 39 | private func updateInsets() { 40 | textInsets = UIEdgeInsets(top: topInset, left: leftInset, bottom: bottomInset, right: rightInset) 41 | } 42 | 43 | private func updateCornerRadius() { 44 | layer.masksToBounds = true 45 | clipsToBounds = true 46 | layer.cornerRadius = cornerRadius 47 | } 48 | 49 | public var textInsets: UIEdgeInsets = .zero { 50 | didSet { setNeedsDisplay() } 51 | } 52 | 53 | override public var intrinsicContentSize: CGSize { 54 | let size = super.intrinsicContentSize 55 | return CGSize(width: size.width + leftInset + rightInset, height: size.height + topInset + bottomInset) 56 | } 57 | 58 | override public func drawText(in rect: CGRect) { 59 | super.drawText(in: rect.inset(by: textInsets)) 60 | } 61 | 62 | override public var bounds: CGRect { 63 | didSet { 64 | // ensures this works within stack views if multi-line 65 | preferredMaxLayoutWidth = bounds.width - (leftInset + rightInset) 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /Tinodios/widgets/ProgressView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ProgressView.swift 3 | // Tinodios 4 | // 5 | // Copyright © 2020 Tinode. All rights reserved. 6 | // 7 | 8 | import UIKit 9 | 10 | class ProgressView: UIView { 11 | 12 | @IBOutlet weak var containerView: UIView! 13 | @IBOutlet weak var progressView: UIProgressView! 14 | @IBOutlet weak var cancelButton: UIButton! 15 | 16 | override init(frame: CGRect) { 17 | super.init(frame: frame) 18 | loadNib() 19 | } 20 | required init?(coder aDecoder: NSCoder) { 21 | super.init(coder: aDecoder) 22 | loadNib() 23 | } 24 | 25 | private func loadNib() { 26 | Bundle.main.loadNibNamed("ProgressView", owner: self, options: nil) 27 | addSubview(containerView) 28 | containerView.frame = self.bounds 29 | containerView.autoresizingMask = [.flexibleWidth] 30 | } 31 | 32 | @IBAction func cancelProgress(_ sender: Any) { 33 | } 34 | 35 | public func setProgress(_ progress: Float) { 36 | progressView.setProgress(progress, animated: true) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Tinodios/widgets/SelectedMemberViewCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SelectedMemberViewCell.swift 3 | // Tinodios 4 | // 5 | // Copyright © 2019 Tinode. All rights reserved. 6 | // 7 | 8 | import UIKit 9 | 10 | class SelectedMemberViewCell: UICollectionViewCell { 11 | 12 | @IBOutlet weak var avatarImageView: RoundImageView! 13 | 14 | override func awakeFromNib() { 15 | super.awakeFromNib() 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Tinodios/widgets/SelectedMemberViewCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /Tinodios/widgets/TagsEditDialogView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TagsEditDialogView.swift 3 | // 4 | // Copyright © 2019-2022 Tinode LLC. All rights reserved. 5 | // 6 | 7 | import Foundation 8 | import TinodeSDK 9 | import UIKit 10 | 11 | class TagsEditDialogViewController: UIViewController { 12 | private static let kButtonBorderColor = UIColor.lightGray 13 | 14 | private static let kDefaultMaxTagCount: Int64 = 16 15 | 16 | public typealias CompletionHandler = ((_ newTags: [TinodeTag]) -> Void) 17 | 18 | @IBOutlet weak var alertView: UIView! 19 | @IBOutlet weak var okButton: UIButton! 20 | @IBOutlet weak var cancelButton: UIButton! 21 | @IBOutlet weak var tagsEditView: TagsEditView! 22 | 23 | private var initialTags: [TinodeTag] = [] 24 | public var completionHandler: CompletionHandler? 25 | 26 | init(with tags: [TinodeTag]) { 27 | super.init(nibName: nil, bundle: nil) 28 | modalTransitionStyle = .crossDissolve 29 | modalPresentationStyle = .overCurrentContext 30 | 31 | self.initialTags = tags 32 | } 33 | 34 | required init?(coder aDecoder: NSCoder) { 35 | fatalError("init(coder:) has not been implemented") 36 | } 37 | 38 | override func viewDidLoad() { 39 | super.viewDidLoad() 40 | 41 | cancelButton.addBorder(side: .top, color: TagsEditDialogViewController.kButtonBorderColor, width: 1) 42 | cancelButton.addBorder(side: .right, color: TagsEditDialogViewController.kButtonBorderColor, width: 1) 43 | okButton.addBorder(side: .top, color: TagsEditDialogViewController.kButtonBorderColor, width: 1) 44 | 45 | let maxTagCount = Cache.tinode.getServerLimit(for: Tinode.kMaxTagCount, withDefault: TagsEditDialogViewController.kDefaultMaxTagCount) 46 | tagsEditView.fontSize = 17 47 | tagsEditView.layer.cornerRadius = 8 48 | tagsEditView.layer.borderColor = TagsEditDialogViewController.kButtonBorderColor.cgColor 49 | tagsEditView.layer.borderWidth = 0.5 50 | tagsEditView.onShouldAcceptTag = { v in 51 | // Make sure we don't add more than maxTagCount. 52 | return v.tagViews.count < maxTagCount 53 | } 54 | tagsEditView.onVerifyTag = { (_, tag) in 55 | return Utils.isValidTag(tag: tag) 56 | } 57 | tagsEditView.addTags(initialTags) 58 | tagsEditView.becomeFirstResponder() 59 | } 60 | 61 | func show(over viewController: UIViewController?) { 62 | guard let viewController = viewController else { return } 63 | viewController.present(self, animated: true, completion: nil) 64 | } 65 | 66 | // MARK: - Button clicks 67 | @IBAction func cancelClicked(_ sender: Any) { 68 | self.dismiss(animated: true, completion: nil) 69 | } 70 | 71 | @IBAction func okayClicked(_ sender: Any) { 72 | let newTags = tagsEditView.tags 73 | if !newTags.elementsEqual(initialTags) { 74 | completionHandler?(newTags) 75 | } 76 | self.dismiss(animated: true, completion: nil) 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Tinodios/widgets/ValidatedCredential.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ValidatedCredential.swift 3 | // Tinodios 4 | // 5 | // Copyright © 2019 Tinode. All rights reserved. 6 | // 7 | 8 | import Foundation 9 | import Contacts 10 | 11 | enum ValidatedCredential { 12 | case email(_: String) 13 | case phoneNum(_: String) 14 | case URL(_: String) 15 | case IP(_: String) 16 | 17 | mutating func isValid() -> Bool { 18 | var predicateStr: String! 19 | var currObject: String! 20 | switch self { 21 | case let .email(str): 22 | predicateStr = "^([a-z0-9_\\.+-]+)@([\\da-z\\.-]+)\\.([a-z\\.]{2,6})$" 23 | currObject = str 24 | case let .phoneNum(str): 25 | do { 26 | let phoneNumber = try Utils.phoneNumberKit.parse(str, ignoreType: true) 27 | self = .phoneNum(Utils.phoneNumberKit.format(phoneNumber, toType: .e164)) 28 | return true 29 | } catch { 30 | Cache.log.error("Failed to parse phone number credential: %@, error: %@", str, error.localizedDescription) 31 | } 32 | return false 33 | case let .URL(str): 34 | predicateStr = "^(https?:\\/\\/)?([\\da-z\\.-]+)\\.([a-z\\.]{2,6})([\\/\\w \\.-]*)*\\/?$" 35 | currObject = str 36 | case let .IP(str): 37 | predicateStr = "^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$" 38 | currObject = str 39 | } 40 | 41 | let predicate = NSPredicate(format: "SELF MATCHES %@", predicateStr) 42 | return predicate.evaluate(with: currObject) 43 | } 44 | 45 | static public func parse(from str: String?) -> ValidatedCredential? { 46 | guard let str = str, !str.isEmpty else { return nil } 47 | var email = ValidatedCredential.email(str) 48 | if email.isValid() { return email } 49 | var phone = ValidatedCredential.phoneNum(str) 50 | if phone.isValid() { return phone } 51 | var url = ValidatedCredential.URL(str) 52 | if url.isValid() { return url } 53 | var ip = ValidatedCredential.IP(str) 54 | if ip.isValid() { return ip } 55 | return nil 56 | } 57 | 58 | func methodName() -> String { 59 | switch self { 60 | case .email: return "email" 61 | case .phoneNum: return "tel" 62 | case .URL: return "url" 63 | case .IP: return "ip" 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Tinodios/widgets/WaveImageView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WaveImageView.swift 3 | // Tinodios 4 | // 5 | // Copyright © 2022 Tinode LLC. All rights reserved. 6 | // 7 | 8 | import UIKit 9 | 10 | @IBDesignable 11 | public class WaveImageView: UIImageView { 12 | private var wave: WaveImage! 13 | 14 | // When the current bar started from the beginning of the record. 15 | private var barStarted: TimeInterval = 0 16 | private var ampAccumulator: Float = 0 17 | 18 | // Duration represented by one bar. 19 | public var barDuration: TimeInterval = 0.1 20 | 21 | // MARK: - Initializers. 22 | 23 | override public init(frame: CGRect) { 24 | super.init(frame: frame) 25 | self.wave = WaveImage(size: CGSize(width: frame.width, height: frame.height)) 26 | self.image = self.wave.image 27 | } 28 | 29 | required public init?(coder aDecoder: NSCoder) { 30 | super.init(coder: aDecoder) 31 | self.wave = WaveImage(size: CGSize(width: frame.width, height: frame.height)) 32 | self.image = self.wave.image 33 | } 34 | 35 | // MARK: public vars 36 | 37 | @IBInspectable 38 | public var waveInsets: UIEdgeInsets = UIEdgeInsets() { 39 | didSet { 40 | self.wave.insets = self.waveInsets 41 | self.image = self.wave.image 42 | } 43 | } 44 | 45 | // MARK: - Instance methods. 46 | 47 | /// Add another amplitute for recording visualization. 48 | public func put(amplitude: Float, atTime: TimeInterval) { 49 | if atTime < barStarted + barDuration { 50 | self.ampAccumulator += amplitude 51 | return 52 | } 53 | 54 | self.wave.put(self.ampAccumulator) 55 | self.image = self.wave.image 56 | 57 | self.barStarted += barDuration 58 | self.ampAccumulator = 0 59 | } 60 | 61 | /// Switch from recording visualization to playback mode. 62 | public func playbackPreview(_ data: Data, duration: TimeInterval) { 63 | self.wave = WaveImage(size: CGSize(width: frame.width, height: frame.height), data: data) 64 | self.wave.duration = Int(duration * 1000) 65 | self.wave.insets = self.waveInsets 66 | self.wave.delegate = self 67 | self.barStarted = 0 68 | self.ampAccumulator = 0 69 | } 70 | 71 | /// Reset view to blank recording visualization state. 72 | public func reset() { 73 | self.wave = WaveImage(size: CGSize(width: frame.width, height: frame.height)) 74 | self.wave.insets = self.waveInsets 75 | self.barStarted = 0 76 | self.ampAccumulator = 0 77 | } 78 | 79 | /// Start playback visualization. 80 | public func play() { 81 | self.wave.play() 82 | } 83 | 84 | /// Pause playback visualization. 85 | public func pause(rewind: Bool) { 86 | if rewind { 87 | self.wave.resetPlayback() 88 | } else { 89 | self.wave.pause() 90 | } 91 | } 92 | } 93 | 94 | extension WaveImageView: WaveImageDelegate { 95 | public func invalidate(in wave: WaveImage) { 96 | DispatchQueue.main.async { 97 | self.image = wave.image 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /Tinodios/widgets/es.lproj/MultilineAlertView.strings: -------------------------------------------------------------------------------- 1 | /* Class = "UIButton"; normalTitle = "OK"; ObjectID = "A57-2v-ao9"; */ 2 | "A57-2v-ao9.normalTitle" = "OK"; 3 | 4 | /* Class = "UIButton"; normalTitle = "Cancel"; ObjectID = "AMx-JQ-2f8"; */ 5 | "AMx-JQ-2f8.normalTitle" = "Cancelar"; 6 | 7 | /* Class = "UILabel"; text = "Title"; ObjectID = "W0P-gB-P5h"; */ 8 | "W0P-gB-P5h.text" = "Reivindicación"; 9 | 10 | -------------------------------------------------------------------------------- /Tinodios/widgets/es.lproj/TagsEditDialogView.strings: -------------------------------------------------------------------------------- 1 | /* Class = "UILabel"; text = "Tags (content discovery)"; ObjectID = "eeW-SH-URg"; */ 2 | "eeW-SH-URg.text" = "Etiquetas (descubrimiento de contenido)"; 3 | 4 | /* Class = "UIButton"; normalTitle = "Cancel"; ObjectID = "vOv-C1-oEb"; */ 5 | "vOv-C1-oEb.normalTitle" = "Cancelar"; 6 | 7 | -------------------------------------------------------------------------------- /Tinodios/widgets/ru.lproj/MultilineAlertView.strings: -------------------------------------------------------------------------------- 1 | /* Class = "UIButton"; normalTitle = "Cancel"; ObjectID = "AMx-JQ-2f8"; */ 2 | "AMx-JQ-2f8.normalTitle" = "Отменить"; 3 | 4 | /* Class = "UILabel"; text = "Title"; ObjectID = "W0P-gB-P5h"; */ 5 | "W0P-gB-P5h.text" = "Название"; 6 | 7 | -------------------------------------------------------------------------------- /Tinodios/widgets/ru.lproj/TagsEditDialogView.strings: -------------------------------------------------------------------------------- 1 | /* Class = "UILabel"; text = "Tags (content discovery)"; ObjectID = "eeW-SH-URg"; */ 2 | "eeW-SH-URg.text" = "Тэги (поиск контактов)"; 3 | 4 | /* Class = "UIButton"; normalTitle = "Cancel"; ObjectID = "vOv-C1-oEb"; */ 5 | "vOv-C1-oEb.normalTitle" = "Отменить"; 6 | 7 | -------------------------------------------------------------------------------- /Tinodios/widgets/uk.lproj/MultilineAlertView.strings: -------------------------------------------------------------------------------- 1 | /* Class = "UIButton"; normalTitle = "Cancel"; ObjectID = "AMx-JQ-2f8"; */ 2 | "AMx-JQ-2f8.normalTitle" = "Скасувати"; 3 | 4 | /* Class = "UILabel"; text = "Title"; ObjectID = "W0P-gB-P5h"; */ 5 | "W0P-gB-P5h.text" = "Назва"; 6 | 7 | -------------------------------------------------------------------------------- /Tinodios/widgets/uk.lproj/TagsEditDialogView.strings: -------------------------------------------------------------------------------- 1 | /* Class = "UILabel"; text = "Tags (content discovery)"; ObjectID = "eeW-SH-URg"; */ 2 | "eeW-SH-URg.text" = "Теги (пошук контактів)"; 3 | 4 | /* Class = "UIButton"; normalTitle = "Cancel"; ObjectID = "vOv-C1-oEb"; */ 5 | "vOv-C1-oEb.normalTitle" = "Скасувати"; 6 | 7 | -------------------------------------------------------------------------------- /Tinodios/widgets/zh-Hans.lproj/MultilineAlertView.strings: -------------------------------------------------------------------------------- 1 | /* Class = "UIButton"; normalTitle = "OK"; ObjectID = "A57-2v-ao9"; */ 2 | "A57-2v-ao9.normalTitle" = "好的"; 3 | 4 | /* Class = "UIButton"; normalTitle = "Cancel"; ObjectID = "AMx-JQ-2f8"; */ 5 | "AMx-JQ-2f8.normalTitle" = "取消"; 6 | 7 | /* Class = "UILabel"; text = "Title"; ObjectID = "W0P-gB-P5h"; */ 8 | "W0P-gB-P5h.text" = "标题"; 9 | 10 | -------------------------------------------------------------------------------- /Tinodios/widgets/zh-Hans.lproj/TagsEditDialogView.strings: -------------------------------------------------------------------------------- 1 | /* Class = "UILabel"; text = "Tags (content discovery)"; ObjectID = "eeW-SH-URg"; */ 2 | "eeW-SH-URg.text" = "标签(内容发现)"; 3 | 4 | /* Class = "UIButton"; normalTitle = "OK"; ObjectID = "PJ7-dH-ATp"; */ 5 | "PJ7-dH-ATp.normalTitle" = "好的"; 6 | 7 | /* Class = "UIButton"; normalTitle = "Cancel"; ObjectID = "vOv-C1-oEb"; */ 8 | "vOv-C1-oEb.normalTitle" = "取消"; 9 | 10 | -------------------------------------------------------------------------------- /Tinodios/widgets/zh-Hant.lproj/MultilineAlertView.strings: -------------------------------------------------------------------------------- 1 | /* Class = "UIButton"; normalTitle = "OK"; ObjectID = "A57-2v-ao9"; */ 2 | "A57-2v-ao9.normalTitle" = "好的"; 3 | 4 | /* Class = "UIButton"; normalTitle = "Cancel"; ObjectID = "AMx-JQ-2f8"; */ 5 | "AMx-JQ-2f8.normalTitle" = "刪去"; 6 | 7 | /* Class = "UILabel"; text = "Title"; ObjectID = "W0P-gB-P5h"; */ 8 | "W0P-gB-P5h.text" = "標題"; 9 | 10 | -------------------------------------------------------------------------------- /Tinodios/widgets/zh-Hant.lproj/TagsEditDialogView.strings: -------------------------------------------------------------------------------- 1 | /* Class = "UILabel"; text = "Tags (content discovery)"; ObjectID = "eeW-SH-URg"; */ 2 | "eeW-SH-URg.text" = "標籤(內容發現)"; 3 | 4 | /* Class = "UIButton"; normalTitle = "OK"; ObjectID = "PJ7-dH-ATp"; */ 5 | "PJ7-dH-ATp.normalTitle" = "好的"; 6 | 7 | /* Class = "UIButton"; normalTitle = "Cancel"; ObjectID = "vOv-C1-oEb"; */ 8 | "vOv-C1-oEb.normalTitle" = "刪去"; 9 | 10 | -------------------------------------------------------------------------------- /Tinodios/zh-Hans.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Privacy - Camera Usage Description */ 2 | "NSCameraUsageDescription" = "Tinode用相机拍照,用作头像或发送给您的联系人"; 3 | 4 | /* Privacy - Contacts Usage Description */ 5 | "NSContactsUsageDescription" = "Tinode只向Tinode服务器发送电子邮件和电话号码,以帮助您与其他用户联系"; 6 | 7 | /* Privacy - Microphone Usage Description */ 8 | "NSMicrophoneUsageDescription" = "Tinode使用麦克风录制您发送给联系人的音频消息"; 9 | 10 | /* Privacy - Photo Library Additions Usage Description */ 11 | "NSPhotoLibraryAddUsageDescription" = "来自Tinode的图像和图片可以保存在照片库中"; 12 | 13 | /* Privacy - Photo Library Usage Description */ 14 | "NSPhotoLibraryUsageDescription" = "Tinode需要访问您的照片,以便您将它们发送给联系人"; 15 | 16 | -------------------------------------------------------------------------------- /Tinodios/zh-Hant.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Privacy - Camera Usage Description */ 2 | "NSCameraUsageDescription" = "Tinode用相機拍照,用作頭像或傳送給您的聯絡人"; 3 | 4 | /* Privacy - Contacts Usage Description */ 5 | "NSContactsUsageDescription" = "Tinode只向Tinode伺服器傳送電子郵件和電話號碼,以幫助您與其他使用者聯絡"; 6 | 7 | /* Privacy - Microphone Usage Description */ 8 | "NSMicrophoneUsageDescription" = "Tinode使用麥克風錄製您傳送給聯絡人的音訊訊息"; 9 | 10 | /* Privacy - Photo Library Additions Usage Description */ 11 | "NSPhotoLibraryAddUsageDescription" = "Tinode的影象和圖片可以儲存在照片庫中"; 12 | 13 | /* Privacy - Photo Library Usage Description */ 14 | "NSPhotoLibraryUsageDescription" = "Tinode需要訪問您的照片,以便您將它們傳送給您的聯絡人"; 15 | 16 | -------------------------------------------------------------------------------- /TinodiosDB/ConnectionSettingsHelper.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SettingsHelper.swift 3 | // TinodiosDB 4 | // 5 | // Copyright © 2019 Tinode. All rights reserved. 6 | // 7 | 8 | import Foundation 9 | 10 | public class ConnectionSettingsHelper { 11 | 12 | struct SettingsBundleKeys { 13 | static let hostName = "host_name_preference" 14 | static let useTLS = "use_tls_preference" 15 | static let wireTransport = "wire_transport_preference" 16 | } 17 | 18 | class func getConnectionSettings() -> (hostName: String?, useTLS: Bool?, wireTransport: String?) { 19 | return (hostName: SharedUtils.kAppDefaults.string(forKey: SettingsBundleKeys.hostName), useTLS: SharedUtils.kAppDefaults.bool(forKey: SettingsBundleKeys.useTLS), wireTransport: SharedUtils.kAppDefaults.string(forKey: SettingsBundleKeys.wireTransport)) 20 | } 21 | 22 | class func setHostName(_ hostName: String?) { 23 | guard hostName != nil else { return } 24 | SharedUtils.kAppDefaults.set(hostName, forKey: SettingsBundleKeys.hostName) 25 | } 26 | 27 | class func setUseTLS(_ useTLS: String?) { 28 | guard let useTLS = useTLS else { return } 29 | SharedUtils.kAppDefaults.set(NSString(string: useTLS).boolValue, forKey: SettingsBundleKeys.useTLS) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /TinodiosDB/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | $(MARKETING_VERSION) 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | 22 | 23 | -------------------------------------------------------------------------------- /TinodiosDB/StoredMessage.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StoredMessage.swift 3 | // ios 4 | // 5 | // Copyright © 2019 Tinode. All rights reserved. 6 | // 7 | 8 | import Foundation 9 | import TinodeSDK 10 | 11 | public class StoredMessage: MsgServerData, Message { 12 | public var msgId: Int64 = 0 13 | 14 | public var seqId: Int { return seq ?? 0 } 15 | 16 | var topicId: Int64? 17 | var userId: Int64? 18 | 19 | var dbStatus: BaseDb.Status? 20 | public var status: Int? { 21 | return dbStatus?.rawValue 22 | } 23 | 24 | public var isDraft: Bool { get { return dbStatus == .draft } } 25 | public var isReady: Bool { get { return dbStatus == .queued } } 26 | public var isDeleted: Bool { 27 | return dbStatus == .deletedHard || dbStatus == .deletedSoft || dbStatus == .deletedSynced 28 | } 29 | public func isDeleted(hard: Bool) -> Bool { 30 | return hard ? 31 | dbStatus == .deletedHard : 32 | dbStatus == .deletedSoft 33 | } 34 | public var isSynced: Bool { return dbStatus == .synced } 35 | 36 | /// Message has not been delivered to the server yet. 37 | public var isPending: Bool { return dbStatus == nil || dbStatus! <= .sending } 38 | 39 | /// True if message was forwarded from another topic. 40 | public var isForwarded: Bool { 41 | return !(head?["forwarded"]?.asString()?.isEmpty ?? true) 42 | } 43 | 44 | /// True if message has been edited. 45 | public var isEdited: Bool { 46 | return head?["replace"] != nil && head?["webrtc"] == nil 47 | } 48 | 49 | /// True if the acount owner is the author of the message. 50 | public var isMine: Bool { 51 | return BaseDb.sharedInstance.isMe(uid: self.from) 52 | } 53 | 54 | /// Cached representation of message content as attributed string. 55 | public var cachedContent: NSAttributedString? 56 | 57 | /// Cached representation of message preview as attributed string. 58 | public var cachedPreview: NSAttributedString? 59 | 60 | // MARK: initializers 61 | 62 | public override init() { super.init() } 63 | 64 | convenience init(from m: MsgServerData) { 65 | self.init() 66 | self.topic = m.topic 67 | self.head = m.head 68 | self.from = m.from 69 | self.ts = m.ts 70 | self.seq = m.seq 71 | self.content = m.content 72 | } 73 | 74 | convenience init(from m: MsgServerData, status: BaseDb.Status) { 75 | self.init(from: m) 76 | self.dbStatus = status 77 | } 78 | 79 | required init(from decoder: Decoder) throws { 80 | fatalError("init(from:) has not been implemented") 81 | } 82 | 83 | // Makes a shallow copy of self. 84 | public func copyOf() -> StoredMessage { 85 | let cp = StoredMessage(from: self) 86 | cp.msgId = self.msgId 87 | cp.topicId = self.topicId 88 | cp.userId = self.userId 89 | cp.dbStatus = self.dbStatus 90 | cp.cachedContent = self.cachedContent 91 | cp.cachedPreview = self.cachedPreview 92 | return cp 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /TinodiosDB/TinodiosDB.h: -------------------------------------------------------------------------------- 1 | // 2 | // TinodiosDB.h 3 | // TinodiosDB 4 | // 5 | // Copyright © 2019 Tinode. All rights reserved. 6 | // 7 | 8 | #import 9 | 10 | //! Project version number for TinodiosDB. 11 | FOUNDATION_EXPORT double TinodiosDBVersionNumber; 12 | 13 | //! Project version string for TinodiosDB. 14 | FOUNDATION_EXPORT const unsigned char TinodiosDBVersionString[]; 15 | 16 | // In this header, you should import all the public headers of your framework using statements like #import 17 | 18 | 19 | -------------------------------------------------------------------------------- /TinodiosNSExtension/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | TinodiosNSExtension 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 19 | CFBundleShortVersionString 20 | $(MARKETING_VERSION) 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSExtension 24 | 25 | NSExtensionPointIdentifier 26 | com.apple.usernotifications.service 27 | NSExtensionPrincipalClass 28 | $(PRODUCT_MODULE_NAME).NotificationService 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /TinodiosNSExtension/TinodiosNSExtension.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.application-groups 6 | 7 | group.co.tinode.tinodios.db 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /TinodiosNSExtension/es.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* Push notification title */ 2 | "New chat" = "Nuevo chat"; 3 | 4 | /* Placeholder for missing topic name 5 | Placeholder for missing user name */ 6 | "Unknown" = "Desconocido"; 7 | 8 | -------------------------------------------------------------------------------- /TinodiosNSExtension/ru.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* Push notification title */ 2 | "New chat" = "Новый чат"; 3 | 4 | /* Placeholder for missing topic name 5 | Placeholder for missing user name */ 6 | "Unknown" = "Неизвестно"; 7 | 8 | -------------------------------------------------------------------------------- /TinodiosNSExtension/uk.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* Push notification title */ 2 | "New chat" = "Новий чат"; 3 | 4 | /* Placeholder for missing topic name 5 | Placeholder for missing user name */ 6 | "Unknown" = "Невідомий"; 7 | 8 | -------------------------------------------------------------------------------- /TinodiosNSExtension/zh-Hans.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* Push notification title */ 2 | "New chat" = "新聊天"; 3 | 4 | /* Placeholder for missing topic name 5 | Placeholder for missing user name */ 6 | "Unknown" = "陌生人"; 7 | 8 | -------------------------------------------------------------------------------- /TinodiosNSExtension/zh-Hant.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* Push notification title */ 2 | "New chat" = "新聊天"; 3 | 4 | /* Placeholder for missing topic name 5 | Placeholder for missing user name */ 6 | "Unknown" = "未知"; 7 | 8 | -------------------------------------------------------------------------------- /TinodiosUITests/TinodiosUITests.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.network.client 6 | 7 | com.apple.security.network.server 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /TinodiosUITests/TinodiosUITestsLaunchTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TinodiosUITestsLaunchTests.swift 3 | // TinodiosUITests 4 | // 5 | // Copyright © 2022 Tinode LLC. All rights reserved. 6 | // 7 | 8 | import XCTest 9 | 10 | final class TinodiosUITestsLaunchTests: XCTestCase { 11 | 12 | override class var runsForEachTargetApplicationUIConfiguration: Bool { 13 | true 14 | } 15 | 16 | override func setUpWithError() throws { 17 | continueAfterFailure = false 18 | } 19 | 20 | func testLaunch() throws { 21 | let app = XCUIApplication() 22 | app.launch() 23 | 24 | // Insert steps here to perform after app launch but before taking a screenshot, 25 | // such as logging into a test account or navigating somewhere in the app 26 | 27 | let attachment = XCTAttachment(screenshot: app.screenshot()) 28 | attachment.name = "Launch Screen" 29 | attachment.lifetime = .keepAlways 30 | add(attachment) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /call-end.m4a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/call-end.m4a -------------------------------------------------------------------------------- /call-out.m4a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/call-out.m4a -------------------------------------------------------------------------------- /devel.xcconfig: -------------------------------------------------------------------------------- 1 | // 2 | // Development .xcconfig 3 | // 4 | 5 | // Include Pods config. 6 | #include "Pods/Target Support Files/Pods-Tinodios/Pods-Tinodios.debug.xcconfig" 7 | 8 | // Server URL 9 | HOST_NAME = 127.0.0.1:6060 10 | // Use TLS (https, wss) 11 | USE_TLS = NO 12 | 13 | // App Settings 14 | APP_NAME = Tinode (test) 15 | -------------------------------------------------------------------------------- /dialing.m4a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/dialing.m4a -------------------------------------------------------------------------------- /ios-acc-personal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/ios-acc-personal.png -------------------------------------------------------------------------------- /ios-chat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/ios-chat.png -------------------------------------------------------------------------------- /ios-contacts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/ios-contacts.png -------------------------------------------------------------------------------- /ios-find-people.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/ios-find-people.png -------------------------------------------------------------------------------- /ios-forward-to.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/ios-forward-to.png -------------------------------------------------------------------------------- /ios-video-call.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinode/ios/b5c793cbeab4745dead1aba84177e35436fee0b5/ios-video-call.png -------------------------------------------------------------------------------- /prod.xcconfig: -------------------------------------------------------------------------------- 1 | // 2 | // Production .xcconfig 3 | // 4 | 5 | // Include Pods config. 6 | #include "Pods/Target Support Files/Pods-Tinodios/Pods-Tinodios.release.xcconfig" 7 | 8 | // Server URL 9 | HOST_NAME = api.tinode.co 10 | // Use TLS (https, wss) 11 | USE_TLS = YES 12 | 13 | // App Settings 14 | APP_NAME = Tinode 15 | 16 | // Versioning. The values are automatically updated by a build script. 17 | GIT_TAG = 1.23.0 18 | GIT_COMMIT_COUNT = 1741 19 | --------------------------------------------------------------------------------