├── .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 |
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 |
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 |
--------------------------------------------------------------------------------