diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 0848ab106..5cda56555 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,28 +1,20 @@ +> This library is ⚠️ [deprecated](https://www.jessesquires.com/blog/officially-deprecating-jsqmessagesviewcontroller/) ⚠️ and is **only** accepting pull requests for critical bug fixes. Consider using [MessageKit](https://github.com/MessageKit/MessageKit) for new projects. + + ## New issue checklist -- [ ] I have read all of the [`README`](https://github.com/jessesquires/JSQMessagesViewController/blob/develop/README.md), [documentation](http://cocoadocs.org/docsets/JSQMessagesViewController/), and [FAQ](https://github.com/jessesquires/JSQMessagesViewController/blob/develop/Documentation/faq.md). -- [ ] I have reviewed the [contributing guidelines](https://github.com/jessesquires/JSQMessagesViewController/blob/develop/.github/CONTRIBUTING.md). Confirmation: ____ +- [ ] I understand that this library is ⚠️ [deprecated](https://www.jessesquires.com/blog/officially-deprecating-jsqmessagesviewcontroller/) ⚠️ and is **only** accepting pull requests for critical bug fixes. +- [ ] I have read the [`README`](https://github.com/jessesquires/JSQMessagesViewController/blob/develop/README.md), [documentation](http://cocoadocs.org/docsets/JSQMessagesViewController/), and [FAQ](https://github.com/jessesquires/JSQMessagesViewController/blob/develop/Documentation/faq.md). +- [ ] [Contributing guidelines](https://github.com/jessesquires/JSQMessagesViewController/blob/develop/.github/CONTRIBUTING.md) confirmation: ____ - [ ] I have searched [existing issues](https://github.com/jessesquires/JSQMessagesViewController/issues?q=is%3Aissue+sort%3Acreated-desc) and **this is not a duplicate**. -### General information +## General information -- Library version(s): -- iOS version(s): -- Devices/Simulators affected: +- `JSQMessagesViewController` version: +- iOS version: +- Devices/Simulators: - Reproducible in the demo project? (Yes/No): -- Related issues: - -## Bug report - -### Expected behavior - - -### Actual behavior - - -### Steps to reproduce - - -### Crash log? Screenshots? Videos? Sample project? +- Any related issues: +## What happened? diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 781065416..a6c342bb9 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,8 +1,14 @@ +> This library is ⚠️ [deprecated](https://www.jessesquires.com/blog/officially-deprecating-jsqmessagesviewcontroller/) ⚠️ and is **only** accepting pull requests for critical bug fixes. Consider using [MessageKit](https://github.com/MessageKit/MessageKit) for new projects. + ## Pull request checklist -- [ ] All tests pass. Demo project builds and runs. -- [ ] I have resolved any merge conflicts. -- [ ] I have followed the [coding style](https://github.com/jessesquires/HowToContribute#style-guidelines), and reviewed the [contributing guidelines](https://github.com/jessesquires/JSQMessagesViewController/blob/develop/.github/CONTRIBUTING.md). Confirmation: ____ +- [ ] I understand that this library is ⚠️ [deprecated](https://www.jessesquires.com/blog/officially-deprecating-jsqmessagesviewcontroller/) ⚠️ and is **only** accepting pull requests for critical bug fixes. +- [ ] All tests pass. +- [ ] Demo project builds and runs. +- [ ] I have resolved merge conflicts. +- [ ] I have followed the [coding style](https://github.com/jessesquires/HowToContribute#style-guidelines). + +[Contributing guidelines](https://github.com/jessesquires/JSQMessagesViewController/blob/develop/.github/CONTRIBUTING.md) confirmation: ____ #### This fixes issue # diff --git a/.travis.yml b/.travis.yml index 2d1b3eb64..fac0eebe8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,6 @@ language: objective-c -osx_image: xcode7.3 +osx_image: xcode8 +cache: cocoapods env: global: @@ -7,30 +8,28 @@ env: - WORKSPACE="JSQMessages.xcworkspace" - IOS_SCHEME="JSQMessages" - - IOS_SDK=iphonesimulator9.3 + - IOS_SDK=iphonesimulator10.0 matrix: - - DESTINATION="OS=8.1,name=iPhone 4s" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="YES" POD_LINT="NO" RUN_UI_TESTS="NO" - - DESTINATION="OS=8.2,name=iPhone 5" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="NO" POD_LINT="NO" RUN_UI_TESTS="NO" - - DESTINATION="OS=8.3,name=iPhone 5s" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="NO" POD_LINT="NO" RUN_UI_TESTS="NO" - - DESTINATION="OS=8.4,name=iPhone 6" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="NO" POD_LINT="NO" RUN_UI_TESTS="NO" + - DESTINATION="OS=8.1,name=iPhone 4s" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="NO" BUILD_EXAMPLE="YES" POD_LINT="YES" RUN_UI_TESTS="NO" + - DESTINATION="OS=8.2,name=iPhone 5" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="NO" BUILD_EXAMPLE="NO" POD_LINT="NO" RUN_UI_TESTS="NO" + - DESTINATION="OS=8.3,name=iPhone 5s" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="NO" BUILD_EXAMPLE="NO" POD_LINT="NO" RUN_UI_TESTS="NO" + - DESTINATION="OS=8.4,name=iPhone 6" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="NO" BUILD_EXAMPLE="NO" POD_LINT="NO" RUN_UI_TESTS="NO" - - DESTINATION="OS=9.0,name=iPhone 5s" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="YES" POD_LINT="NO" RUN_UI_TESTS="NO" + - DESTINATION="OS=9.0,name=iPhone 6 Plus" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="YES" POD_LINT="NO" RUN_UI_TESTS="NO" - DESTINATION="OS=9.1,name=iPhone 6s" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="NO" POD_LINT="NO" RUN_UI_TESTS="NO" - - DESTINATION="OS=9.2,name=iPhone 6 Plus" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="NO" POD_LINT="NO" RUN_UI_TESTS="NO" - - DESTINATION="OS=9.3,name=iPhone 6s Plus" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="NO" POD_LINT="NO" RUN_UI_TESTS="NO" + - DESTINATION="OS=9.2,name=iPhone 6s Plus" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="NO" POD_LINT="NO" RUN_UI_TESTS="NO" + - DESTINATION="OS=9.3,name=iPad Air 2" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="NO" POD_LINT="NO" RUN_UI_TESTS="NO" + + - DESTINATION="OS=10.0,name=iPhone 6s" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="YES" POD_LINT="NO" RUN_UI_TESTS="NO" - - DESTINATION="OS=8.1,name=iPad 2" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="YES" POD_LINT="NO" RUN_UI_TESTS="NO" - - DESTINATION="OS=8.4,name=iPad 2" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="NO" POD_LINT="NO" RUN_UI_TESTS="NO" - - DESTINATION="OS=9.0,name=iPad Retina" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="NO" POD_LINT="NO" RUN_UI_TESTS="NO" - - DESTINATION="OS=9.1,name=iPad Air" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="NO" POD_LINT="NO" RUN_UI_TESTS="NO" - - DESTINATION="OS=9.2,name=iPad Air 2" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="NO" POD_LINT="NO" RUN_UI_TESTS="NO" - - DESTINATION="OS=9.3,name=iPad Pro" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="YES" POD_LINT="NO" RUN_UI_TESTS="NO" +before_install: + - gem install cocoapods --pre script: - +- set -o pipefail + - if [ $POD_LINT == "YES" ]; then - pod spec lint; pod lib lint; fi @@ -53,9 +52,9 @@ script: # Build for reporting test coverage -- if [ $RUN_TESTS == "YES" ]; then - xcodebuild test -workspace JSQMessages.xcworkspace -scheme JSQMessages -sdk iphonesimulator GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES GCC_GENERATE_TEST_COVERAGE_FILES=YES; - fi +#- if [ $RUN_TESTS == "YES" ]; then +# xcodebuild test -workspace JSQMessages.xcworkspace -scheme JSQMessages -sdk iphonesimulator GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES GCC_GENERATE_TEST_COVERAGE_FILES=YES; +# fi after_success: - bash <(curl -s https://codecov.io/bash); diff --git a/Assets/JSQmessages.png b/Assets/JSQmessages.png index 844931424..5af74b08a 100644 Binary files a/Assets/JSQmessages.png and b/Assets/JSQmessages.png differ diff --git a/Assets/jsq_message_chat_icon.png b/Assets/jsq_message_chat_icon.png index 3ff20054c..30e7e443d 100644 Binary files a/Assets/jsq_message_chat_icon.png and b/Assets/jsq_message_chat_icon.png differ diff --git a/Assets/jsq_messages_banner.png b/Assets/jsq_messages_banner.png index cb6404c19..0bb8c11d1 100644 Binary files a/Assets/jsq_messages_banner.png and b/Assets/jsq_messages_banner.png differ diff --git a/CHANGELOG.md b/CHANGELOG.md index 287d7d126..4cadcf61f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,7 +23,10 @@ This release closes the [8.0.0 milestone](https://github.com/jessesquires/JSQMes - Animated typing indicator. Typing indicator now animates like iMessage. (#1382) Thanks @radekcieciwa! - Dynamic text support. (#497, #1747) Thanks @MacMeDan! - Message cells now have a customizable accessory view. (#1519, #1719) Thanks @adubr! -- Send button now can be turned on/off manually. (#1575 #1609) Thanks @sebastianludwig! +- Send button now can be turned on/off manually. (#1575, #1609) Thanks @sebastianludwig! +- Video message items now have a custom thumbnail option. (#628, #709, #1408, #1823) Thanks @weekwood, @benjaminhallock! +- A new class `JSQMessagesVideoThumbnailFactory` now can generate thumbnail images from `AVURLAsset`. (#709, #1823) Thanks @weekwood, @Lucashuang0802! +- Added a `placeHolderInsets` property to `JSQMessagesComposerTextView` to allow insetting the placeholder text. (#1908) ### Fixes diff --git a/Documentation/apps_using_this_library.md b/Documentation/apps_using_this_library.md index e9db26dca..2db9c0463 100644 --- a/Documentation/apps_using_this_library.md +++ b/Documentation/apps_using_this_library.md @@ -46,4 +46,9 @@ These are the (known) apps that use `JSQMessagesViewController`. Submit a [pull * [SnipSnap](http://go.snipsnap.it/messageui-scout) * [BubbleMe](https://itunes.apple.com/us/app/bubbleme/id1125325038) * [Social-Go](https://github.com/kingreza/Social-Go) +* [StudyBuddy](https://itunes.apple.com/ca/app/studybuddy/id948997336?mt=8) +* [multipeer-chat](https://github.com/J4awesome/multipeer-chat) +* [FriendlyU](https://itunes.apple.com/us/app/friendlyu/id963421205) +* [LŌC](https://itunes.apple.com/us/app/loc-location-based-social/id957193908?mt=8) +* [Ginger.io](https://itunes.apple.com/us/app/ginger.io-coaching-therapy/id515118602) * *Your app here, submit a [pull request](https://github.com/jessesquires/JSQMessagesViewController/compare)!* diff --git a/JSQMessages.xcodeproj/project.pbxproj b/JSQMessages.xcodeproj/project.pbxproj index 38fac4dd6..aa19806ad 100644 --- a/JSQMessages.xcodeproj/project.pbxproj +++ b/JSQMessages.xcodeproj/project.pbxproj @@ -106,6 +106,7 @@ 88C00A501A44D4D800B004B3 /* JSQPhotoMediaItemTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 88C00A4F1A44D4D800B004B3 /* JSQPhotoMediaItemTests.m */; }; 88C00A521A44D4E500B004B3 /* JSQVideoMediaItemTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 88C00A511A44D4E500B004B3 /* JSQVideoMediaItemTests.m */; }; 88C4583019F5F7A0008FD427 /* JSQMessagesMediaViewBubbleImageMasker.m in Sources */ = {isa = PBXBuildFile; fileRef = 88C4582F19F5F7A0008FD427 /* JSQMessagesMediaViewBubbleImageMasker.m */; }; + A04B0EBF1D6ADE5800FBDC47 /* JSQMessagesVideoThumbnailFactory.m in Sources */ = {isa = PBXBuildFile; fileRef = A04B0EBE1D6ADE5800FBDC47 /* JSQMessagesVideoThumbnailFactory.m */; }; BF10D6AA1D062AD10072D215 /* JSQMessagesTypingView.m in Sources */ = {isa = PBXBuildFile; fileRef = BF10D6A91D062AD10072D215 /* JSQMessagesTypingView.m */; }; /* End PBXBuildFile section */ @@ -269,6 +270,8 @@ 88C00A511A44D4E500B004B3 /* JSQVideoMediaItemTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQVideoMediaItemTests.m; sourceTree = ""; }; 88C4582E19F5F7A0008FD427 /* JSQMessagesMediaViewBubbleImageMasker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSQMessagesMediaViewBubbleImageMasker.h; sourceTree = ""; }; 88C4582F19F5F7A0008FD427 /* JSQMessagesMediaViewBubbleImageMasker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQMessagesMediaViewBubbleImageMasker.m; sourceTree = ""; }; + A04B0EBD1D6ADE5800FBDC47 /* JSQMessagesVideoThumbnailFactory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSQMessagesVideoThumbnailFactory.h; sourceTree = ""; }; + A04B0EBE1D6ADE5800FBDC47 /* JSQMessagesVideoThumbnailFactory.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQMessagesVideoThumbnailFactory.m; sourceTree = ""; }; BF10D6A81D062AD10072D215 /* JSQMessagesTypingView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSQMessagesTypingView.h; sourceTree = ""; }; BF10D6A91D062AD10072D215 /* JSQMessagesTypingView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQMessagesTypingView.m; sourceTree = ""; }; /* End PBXFileReference section */ @@ -451,6 +454,8 @@ 88A25F6B19D8E01A00924534 /* JSQMessagesTimestampFormatter.m */, 88A25F6C19D8E01A00924534 /* JSQMessagesToolbarButtonFactory.h */, 88A25F6D19D8E01A00924534 /* JSQMessagesToolbarButtonFactory.m */, + A04B0EBD1D6ADE5800FBDC47 /* JSQMessagesVideoThumbnailFactory.h */, + A04B0EBE1D6ADE5800FBDC47 /* JSQMessagesVideoThumbnailFactory.m */, ); path = Factories; sourceTree = ""; @@ -741,6 +746,7 @@ 88A25FCB19D8E01A00924534 /* JSQMessagesCollectionViewCell.m in Sources */, 88A25FBB19D8E01A00924534 /* JSQMessagesViewController.m in Sources */, 8885734D19DE55D000E89D20 /* NSUserDefaults+DemoSettings.m in Sources */, + A04B0EBF1D6ADE5800FBDC47 /* JSQMessagesVideoThumbnailFactory.m in Sources */, 544A32211CB2EE380084BFC0 /* JSQAudioMediaViewAttributes.m in Sources */, 883C11781A09FB100092A16D /* JSQMessagesCellTextView.m in Sources */, 88A25FB919D8E01A00924534 /* UIView+JSQMessages.m in Sources */, diff --git a/JSQMessagesDemo/Base.lproj/Localizable.strings b/JSQMessagesDemo/Base.lproj/Localizable.strings index bfb7f30e5..5e9685532 100644 --- a/JSQMessagesDemo/Base.lproj/Localizable.strings +++ b/JSQMessagesDemo/Base.lproj/Localizable.strings @@ -21,6 +21,7 @@ "Send photo" = "Send photo"; "Send location" = "Send location"; "Send video" = "Send video"; +"Send video thumbnail" = "Send video with thumbnail"; "Custom Action" = "Custom Action"; "OK" = "OK"; diff --git a/JSQMessagesDemo/DemoMessagesViewController.m b/JSQMessagesDemo/DemoMessagesViewController.m index 6e97f9c95..70bc3ee3e 100644 --- a/JSQMessagesDemo/DemoMessagesViewController.m +++ b/JSQMessagesDemo/DemoMessagesViewController.m @@ -365,7 +365,7 @@ - (void)didPressAccessoryButton:(UIButton *)sender delegate:self cancelButtonTitle:NSLocalizedString(@"Cancel", nil) destructiveButtonTitle:nil - otherButtonTitles:NSLocalizedString(@"Send photo", nil), NSLocalizedString(@"Send location", nil), NSLocalizedString(@"Send video", nil), NSLocalizedString(@"Send audio", nil), nil]; + otherButtonTitles:NSLocalizedString(@"Send photo", nil), NSLocalizedString(@"Send location", nil), NSLocalizedString(@"Send video", nil), NSLocalizedString(@"Send video thumbnail", nil), NSLocalizedString(@"Send audio", nil), nil]; [sheet showFromToolbar:self.inputToolbar]; } @@ -397,6 +397,10 @@ - (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSIn break; case 3: + [self.demoData addVideoMediaMessageWithThumbnail]; + break; + + case 4: [self.demoData addAudioMediaMessage]; break; } diff --git a/JSQMessagesDemo/DemoModelData.h b/JSQMessagesDemo/DemoModelData.h index b24487d84..658ec8a0a 100644 --- a/JSQMessagesDemo/DemoModelData.h +++ b/JSQMessagesDemo/DemoModelData.h @@ -58,6 +58,8 @@ static NSString * const kJSQDemoAvatarIdWoz = @"309-41802-93823"; - (void)addVideoMediaMessage; +- (void)addVideoMediaMessageWithThumbnail; + - (void)addAudioMediaMessage; @end diff --git a/JSQMessagesDemo/DemoModelData.m b/JSQMessagesDemo/DemoModelData.m index c158b394e..463a5416c 100644 --- a/JSQMessagesDemo/DemoModelData.m +++ b/JSQMessagesDemo/DemoModelData.m @@ -200,4 +200,16 @@ - (void)addVideoMediaMessage [self.messages addObject:videoMessage]; } +- (void)addVideoMediaMessageWithThumbnail +{ + // don't have a real video, just pretending + NSURL *videoURL = [NSURL URLWithString:@"file://"]; + + JSQVideoMediaItem *videoItem = [[JSQVideoMediaItem alloc] initWithFileURL:videoURL isReadyToPlay:YES thumbnailImage:[UIImage imageNamed:@"goldengate"]]; + JSQMessage *videoMessage = [JSQMessage messageWithSenderId:kJSQDemoAvatarIdSquires + displayName:kJSQDemoAvatarDisplayNameSquires + media:videoItem]; + [self.messages addObject:videoMessage]; +} + @end diff --git a/JSQMessagesDemo/Images.xcassets/AppIcon.appiconset/Contents.json b/JSQMessagesDemo/Images.xcassets/AppIcon.appiconset/Contents.json index 179e20b02..ac3b9ecc3 100644 --- a/JSQMessagesDemo/Images.xcassets/AppIcon.appiconset/Contents.json +++ b/JSQMessagesDemo/Images.xcassets/AppIcon.appiconset/Contents.json @@ -1,5 +1,15 @@ { "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, { "size" : "29x29", "idiom" : "iphone", @@ -36,6 +46,16 @@ "filename" : "Icon-180.png", "scale" : "3x" }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "2x" + }, { "size" : "29x29", "idiom" : "ipad", diff --git a/JSQMessagesDemo/Images.xcassets/AppIcon.appiconset/Icon-120-1.png b/JSQMessagesDemo/Images.xcassets/AppIcon.appiconset/Icon-120-1.png index 8755a01ef..499b308de 100644 Binary files a/JSQMessagesDemo/Images.xcassets/AppIcon.appiconset/Icon-120-1.png and b/JSQMessagesDemo/Images.xcassets/AppIcon.appiconset/Icon-120-1.png differ diff --git a/JSQMessagesDemo/Images.xcassets/AppIcon.appiconset/Icon-120.png b/JSQMessagesDemo/Images.xcassets/AppIcon.appiconset/Icon-120.png index 8755a01ef..499b308de 100644 Binary files a/JSQMessagesDemo/Images.xcassets/AppIcon.appiconset/Icon-120.png and b/JSQMessagesDemo/Images.xcassets/AppIcon.appiconset/Icon-120.png differ diff --git a/JSQMessagesDemo/Images.xcassets/AppIcon.appiconset/Icon-180.png b/JSQMessagesDemo/Images.xcassets/AppIcon.appiconset/Icon-180.png index a21cca223..89f667a81 100644 Binary files a/JSQMessagesDemo/Images.xcassets/AppIcon.appiconset/Icon-180.png and b/JSQMessagesDemo/Images.xcassets/AppIcon.appiconset/Icon-180.png differ diff --git a/JSQMessagesDemo/Images.xcassets/AppIcon.appiconset/Icon-76.png b/JSQMessagesDemo/Images.xcassets/AppIcon.appiconset/Icon-76.png index 2e0962bd9..da561c898 100644 Binary files a/JSQMessagesDemo/Images.xcassets/AppIcon.appiconset/Icon-76.png and b/JSQMessagesDemo/Images.xcassets/AppIcon.appiconset/Icon-76.png differ diff --git a/JSQMessagesDemo/Images.xcassets/AppIcon.appiconset/Icon-76@2x.png b/JSQMessagesDemo/Images.xcassets/AppIcon.appiconset/Icon-76@2x.png index 513ac7809..01bfdd37b 100644 Binary files a/JSQMessagesDemo/Images.xcassets/AppIcon.appiconset/Icon-76@2x.png and b/JSQMessagesDemo/Images.xcassets/AppIcon.appiconset/Icon-76@2x.png differ diff --git a/JSQMessagesDemo/Images.xcassets/AppIcon.appiconset/Icon-87.png b/JSQMessagesDemo/Images.xcassets/AppIcon.appiconset/Icon-87.png index d985b9b42..cfb5f48f1 100644 Binary files a/JSQMessagesDemo/Images.xcassets/AppIcon.appiconset/Icon-87.png and b/JSQMessagesDemo/Images.xcassets/AppIcon.appiconset/Icon-87.png differ diff --git a/JSQMessagesDemo/Images.xcassets/AppIcon.appiconset/Icon-Small.png b/JSQMessagesDemo/Images.xcassets/AppIcon.appiconset/Icon-Small.png index 56ba08479..e82d15ea2 100644 Binary files a/JSQMessagesDemo/Images.xcassets/AppIcon.appiconset/Icon-Small.png and b/JSQMessagesDemo/Images.xcassets/AppIcon.appiconset/Icon-Small.png differ diff --git a/JSQMessagesDemo/Images.xcassets/AppIcon.appiconset/Icon-Small@2x-1.png b/JSQMessagesDemo/Images.xcassets/AppIcon.appiconset/Icon-Small@2x-1.png index 4e72ce6d9..6ba17f3ef 100644 Binary files a/JSQMessagesDemo/Images.xcassets/AppIcon.appiconset/Icon-Small@2x-1.png and b/JSQMessagesDemo/Images.xcassets/AppIcon.appiconset/Icon-Small@2x-1.png differ diff --git a/JSQMessagesDemo/Images.xcassets/AppIcon.appiconset/Icon-Small@2x.png b/JSQMessagesDemo/Images.xcassets/AppIcon.appiconset/Icon-Small@2x.png index 4e72ce6d9..6ba17f3ef 100644 Binary files a/JSQMessagesDemo/Images.xcassets/AppIcon.appiconset/Icon-Small@2x.png and b/JSQMessagesDemo/Images.xcassets/AppIcon.appiconset/Icon-Small@2x.png differ diff --git a/JSQMessagesDemo/Images.xcassets/AppIcon.appiconset/Icon-Spotlight-iOS7.png b/JSQMessagesDemo/Images.xcassets/AppIcon.appiconset/Icon-Spotlight-iOS7.png index b51ac1267..2fff91001 100644 Binary files a/JSQMessagesDemo/Images.xcassets/AppIcon.appiconset/Icon-Spotlight-iOS7.png and b/JSQMessagesDemo/Images.xcassets/AppIcon.appiconset/Icon-Spotlight-iOS7.png differ diff --git a/JSQMessagesDemo/Images.xcassets/AppIcon.appiconset/Icon-Spotlight-iOS7@2x-1.png b/JSQMessagesDemo/Images.xcassets/AppIcon.appiconset/Icon-Spotlight-iOS7@2x-1.png index f384eb7b3..1f80b4a64 100644 Binary files a/JSQMessagesDemo/Images.xcassets/AppIcon.appiconset/Icon-Spotlight-iOS7@2x-1.png and b/JSQMessagesDemo/Images.xcassets/AppIcon.appiconset/Icon-Spotlight-iOS7@2x-1.png differ diff --git a/JSQMessagesDemo/Images.xcassets/AppIcon.appiconset/Icon-Spotlight-iOS7@2x.png b/JSQMessagesDemo/Images.xcassets/AppIcon.appiconset/Icon-Spotlight-iOS7@2x.png index f384eb7b3..1f80b4a64 100644 Binary files a/JSQMessagesDemo/Images.xcassets/AppIcon.appiconset/Icon-Spotlight-iOS7@2x.png and b/JSQMessagesDemo/Images.xcassets/AppIcon.appiconset/Icon-Spotlight-iOS7@2x.png differ diff --git a/JSQMessagesDemo/Images.xcassets/DemoAvatars/demo_avatar_cook.imageset/demo_avatar_cook.png b/JSQMessagesDemo/Images.xcassets/DemoAvatars/demo_avatar_cook.imageset/demo_avatar_cook.png index dc8615eab..ad28f56b0 100644 Binary files a/JSQMessagesDemo/Images.xcassets/DemoAvatars/demo_avatar_cook.imageset/demo_avatar_cook.png and b/JSQMessagesDemo/Images.xcassets/DemoAvatars/demo_avatar_cook.imageset/demo_avatar_cook.png differ diff --git a/JSQMessagesDemo/Images.xcassets/DemoAvatars/demo_avatar_cook.imageset/demo_avatar_cook@2x.png b/JSQMessagesDemo/Images.xcassets/DemoAvatars/demo_avatar_cook.imageset/demo_avatar_cook@2x.png index 4e2b03659..0e484c588 100644 Binary files a/JSQMessagesDemo/Images.xcassets/DemoAvatars/demo_avatar_cook.imageset/demo_avatar_cook@2x.png and b/JSQMessagesDemo/Images.xcassets/DemoAvatars/demo_avatar_cook.imageset/demo_avatar_cook@2x.png differ diff --git a/JSQMessagesDemo/Images.xcassets/DemoAvatars/demo_avatar_cook.imageset/demo_avatar_cook@3x.png b/JSQMessagesDemo/Images.xcassets/DemoAvatars/demo_avatar_cook.imageset/demo_avatar_cook@3x.png index 8a01e97a2..1bceca3c0 100644 Binary files a/JSQMessagesDemo/Images.xcassets/DemoAvatars/demo_avatar_cook.imageset/demo_avatar_cook@3x.png and b/JSQMessagesDemo/Images.xcassets/DemoAvatars/demo_avatar_cook.imageset/demo_avatar_cook@3x.png differ diff --git a/JSQMessagesDemo/Images.xcassets/DemoAvatars/demo_avatar_jobs.imageset/demo_avatar_jobs.png b/JSQMessagesDemo/Images.xcassets/DemoAvatars/demo_avatar_jobs.imageset/demo_avatar_jobs.png index 356a3e2ec..4911c3fd7 100644 Binary files a/JSQMessagesDemo/Images.xcassets/DemoAvatars/demo_avatar_jobs.imageset/demo_avatar_jobs.png and b/JSQMessagesDemo/Images.xcassets/DemoAvatars/demo_avatar_jobs.imageset/demo_avatar_jobs.png differ diff --git a/JSQMessagesDemo/Images.xcassets/DemoAvatars/demo_avatar_jobs.imageset/demo_avatar_jobs@2x.png b/JSQMessagesDemo/Images.xcassets/DemoAvatars/demo_avatar_jobs.imageset/demo_avatar_jobs@2x.png index 82249ceb2..b6c6e5d7e 100644 Binary files a/JSQMessagesDemo/Images.xcassets/DemoAvatars/demo_avatar_jobs.imageset/demo_avatar_jobs@2x.png and b/JSQMessagesDemo/Images.xcassets/DemoAvatars/demo_avatar_jobs.imageset/demo_avatar_jobs@2x.png differ diff --git a/JSQMessagesDemo/Images.xcassets/DemoAvatars/demo_avatar_jobs.imageset/demo_avatar_jobs@3x.png b/JSQMessagesDemo/Images.xcassets/DemoAvatars/demo_avatar_jobs.imageset/demo_avatar_jobs@3x.png index 267bb5f90..fd7506c20 100644 Binary files a/JSQMessagesDemo/Images.xcassets/DemoAvatars/demo_avatar_jobs.imageset/demo_avatar_jobs@3x.png and b/JSQMessagesDemo/Images.xcassets/DemoAvatars/demo_avatar_jobs.imageset/demo_avatar_jobs@3x.png differ diff --git a/JSQMessagesDemo/Images.xcassets/DemoAvatars/demo_avatar_woz.imageset/demo_avatar_woz.png b/JSQMessagesDemo/Images.xcassets/DemoAvatars/demo_avatar_woz.imageset/demo_avatar_woz.png index d72851267..3b9b8be83 100644 Binary files a/JSQMessagesDemo/Images.xcassets/DemoAvatars/demo_avatar_woz.imageset/demo_avatar_woz.png and b/JSQMessagesDemo/Images.xcassets/DemoAvatars/demo_avatar_woz.imageset/demo_avatar_woz.png differ diff --git a/JSQMessagesDemo/Images.xcassets/DemoAvatars/demo_avatar_woz.imageset/demo_avatar_woz@3x.png b/JSQMessagesDemo/Images.xcassets/DemoAvatars/demo_avatar_woz.imageset/demo_avatar_woz@3x.png index a00582cf7..18ced9168 100644 Binary files a/JSQMessagesDemo/Images.xcassets/DemoAvatars/demo_avatar_woz.imageset/demo_avatar_woz@3x.png and b/JSQMessagesDemo/Images.xcassets/DemoAvatars/demo_avatar_woz.imageset/demo_avatar_woz@3x.png differ diff --git a/JSQMessagesDemo/Images.xcassets/LaunchImage.launchimage/jsq_messages_splash_47inch.png b/JSQMessagesDemo/Images.xcassets/LaunchImage.launchimage/jsq_messages_splash_47inch.png index dced2d78a..b4392bad8 100644 Binary files a/JSQMessagesDemo/Images.xcassets/LaunchImage.launchimage/jsq_messages_splash_47inch.png and b/JSQMessagesDemo/Images.xcassets/LaunchImage.launchimage/jsq_messages_splash_47inch.png differ diff --git a/JSQMessagesDemo/Images.xcassets/LaunchImage.launchimage/jsq_messages_splash_55inch.png b/JSQMessagesDemo/Images.xcassets/LaunchImage.launchimage/jsq_messages_splash_55inch.png index cf9b89b8d..a26d36a39 100644 Binary files a/JSQMessagesDemo/Images.xcassets/LaunchImage.launchimage/jsq_messages_splash_55inch.png and b/JSQMessagesDemo/Images.xcassets/LaunchImage.launchimage/jsq_messages_splash_55inch.png differ diff --git a/JSQMessagesDemo/Images.xcassets/LaunchImage.launchimage/jsq_messages_splash_55inch_landscape.png b/JSQMessagesDemo/Images.xcassets/LaunchImage.launchimage/jsq_messages_splash_55inch_landscape.png index b3c1ba9ad..0773e47ca 100644 Binary files a/JSQMessagesDemo/Images.xcassets/LaunchImage.launchimage/jsq_messages_splash_55inch_landscape.png and b/JSQMessagesDemo/Images.xcassets/LaunchImage.launchimage/jsq_messages_splash_55inch_landscape.png differ diff --git a/JSQMessagesDemo/Images.xcassets/LaunchImage.launchimage/jsq_messages_splash_ipad.png b/JSQMessagesDemo/Images.xcassets/LaunchImage.launchimage/jsq_messages_splash_ipad.png index bf94b786b..0d8af53dc 100644 Binary files a/JSQMessagesDemo/Images.xcassets/LaunchImage.launchimage/jsq_messages_splash_ipad.png and b/JSQMessagesDemo/Images.xcassets/LaunchImage.launchimage/jsq_messages_splash_ipad.png differ diff --git a/JSQMessagesDemo/Images.xcassets/LaunchImage.launchimage/jsq_messages_splash_ipad@2x.png b/JSQMessagesDemo/Images.xcassets/LaunchImage.launchimage/jsq_messages_splash_ipad@2x.png index dc0f7b3fc..6819bb9bb 100644 Binary files a/JSQMessagesDemo/Images.xcassets/LaunchImage.launchimage/jsq_messages_splash_ipad@2x.png and b/JSQMessagesDemo/Images.xcassets/LaunchImage.launchimage/jsq_messages_splash_ipad@2x.png differ diff --git a/JSQMessagesDemo/Images.xcassets/LaunchImage.launchimage/jsq_messages_splash_ipad@2x~landscape.png b/JSQMessagesDemo/Images.xcassets/LaunchImage.launchimage/jsq_messages_splash_ipad@2x~landscape.png index f80be19da..420a349ca 100644 Binary files a/JSQMessagesDemo/Images.xcassets/LaunchImage.launchimage/jsq_messages_splash_ipad@2x~landscape.png and b/JSQMessagesDemo/Images.xcassets/LaunchImage.launchimage/jsq_messages_splash_ipad@2x~landscape.png differ diff --git a/JSQMessagesDemo/Images.xcassets/LaunchImage.launchimage/jsq_messages_splash_ipad~landscape.png b/JSQMessagesDemo/Images.xcassets/LaunchImage.launchimage/jsq_messages_splash_ipad~landscape.png index 82e01bda1..de1cc30c9 100644 Binary files a/JSQMessagesDemo/Images.xcassets/LaunchImage.launchimage/jsq_messages_splash_ipad~landscape.png and b/JSQMessagesDemo/Images.xcassets/LaunchImage.launchimage/jsq_messages_splash_ipad~landscape.png differ diff --git a/JSQMessagesDemo/Images.xcassets/LaunchImage.launchimage/slpash_iphone4inch.png b/JSQMessagesDemo/Images.xcassets/LaunchImage.launchimage/slpash_iphone4inch.png index dbfdf535d..5b3ecb6f3 100644 Binary files a/JSQMessagesDemo/Images.xcassets/LaunchImage.launchimage/slpash_iphone4inch.png and b/JSQMessagesDemo/Images.xcassets/LaunchImage.launchimage/slpash_iphone4inch.png differ diff --git a/JSQMessagesDemo/Images.xcassets/LaunchImage.launchimage/splash_iphone35inch.png b/JSQMessagesDemo/Images.xcassets/LaunchImage.launchimage/splash_iphone35inch.png index d7030ca14..cbfae2507 100644 Binary files a/JSQMessagesDemo/Images.xcassets/LaunchImage.launchimage/splash_iphone35inch.png and b/JSQMessagesDemo/Images.xcassets/LaunchImage.launchimage/splash_iphone35inch.png differ diff --git a/JSQMessagesDemo/Images.xcassets/goldengate.imageset/goldengate.png b/JSQMessagesDemo/Images.xcassets/goldengate.imageset/goldengate.png index b9a720fd5..2cdc23e82 100644 Binary files a/JSQMessagesDemo/Images.xcassets/goldengate.imageset/goldengate.png and b/JSQMessagesDemo/Images.xcassets/goldengate.imageset/goldengate.png differ diff --git a/JSQMessagesDemo/Images.xcassets/goldengate.imageset/goldengate@2x.png b/JSQMessagesDemo/Images.xcassets/goldengate.imageset/goldengate@2x.png index 96f741f96..6150a7863 100644 Binary files a/JSQMessagesDemo/Images.xcassets/goldengate.imageset/goldengate@2x.png and b/JSQMessagesDemo/Images.xcassets/goldengate.imageset/goldengate@2x.png differ diff --git a/JSQMessagesDemo/Images.xcassets/goldengate.imageset/goldengate@3x.png b/JSQMessagesDemo/Images.xcassets/goldengate.imageset/goldengate@3x.png index 11b1691f9..f49e27aa1 100644 Binary files a/JSQMessagesDemo/Images.xcassets/goldengate.imageset/goldengate@3x.png and b/JSQMessagesDemo/Images.xcassets/goldengate.imageset/goldengate@3x.png differ diff --git a/JSQMessagesTests/ViewTests/JSQMessagesComposerTextViewTests.m b/JSQMessagesTests/ViewTests/JSQMessagesComposerTextViewTests.m index 66bdcb8e9..9ba0f0ecb 100644 --- a/JSQMessagesTests/ViewTests/JSQMessagesComposerTextViewTests.m +++ b/JSQMessagesTests/ViewTests/JSQMessagesComposerTextViewTests.m @@ -65,6 +65,20 @@ - (void)testComposerTextViewInit XCTAssertEqual(self.textView.keyboardAppearance, UIKeyboardAppearanceDefault, @"Property should be equal to default value"); XCTAssertEqual(self.textView.keyboardType, UIKeyboardTypeDefault, @"Property should be equal to default value"); XCTAssertEqual(self.textView.returnKeyType, UIReturnKeyDefault, @"Property should be equal to default value"); + + XCTAssertTrue(UIEdgeInsetsEqualToEdgeInsets(self.textView.placeHolderInsets, UIEdgeInsetsMake(5.0, 7.0, 5.0, 7.0)), @"Property should be equal to default value"); +} + +- (void)testComposerTextViewPlaceholderInsets +{ + // New insets to draw the placeholder + UIEdgeInsets placeholderInsets = UIEdgeInsetsMake(2.0, 4.0, 2.0, 0.0); + + // Set the new insets into the contentView + self.textView.placeHolderInsets = placeholderInsets; + + // Validate if placeholderInsets setter worked. We may validate the draw... + XCTAssertTrue(UIEdgeInsetsEqualToEdgeInsets(self.textView.placeHolderInsets, placeholderInsets), @"Property placeholderInsets should have changed to (2.0, 4.0, 2.0, 0.0)"); } @end diff --git a/JSQMessagesViewController.podspec b/JSQMessagesViewController.podspec index 5c5944f81..009cad392 100644 --- a/JSQMessagesViewController.podspec +++ b/JSQMessagesViewController.podspec @@ -1,18 +1,11 @@ Pod::Spec.new do |s| s.name = 'JSQMessagesViewController' - s.version = '7.3.4' + s.version = '7.3.5' s.summary = 'An elegant messages UI library for iOS.' - s.homepage = 'http://jessesquires.github.io/JSQMessagesViewController' s.license = 'MIT' s.platform = :ios, '7.0' s.author = 'Jesse Squires' - s.social_media_url = 'https://twitter.com/jesse_squires' - - s.screenshots = ['https://raw.githubusercontent.com/jessesquires/JSQMessagesViewController/develop/Screenshots/screenshot0.png', - 'https://raw.githubusercontent.com/jessesquires/JSQMessagesViewController/develop/Screenshots/screenshot1.png', - 'https://raw.githubusercontent.com/jessesquires/JSQMessagesViewController/develop/Screenshots/screenshot2.png', - 'https://raw.githubusercontent.com/jessesquires/JSQMessagesViewController/develop/Screenshots/screenshot3.png'] s.source = { :git => 'https://github.com/jessesquires/JSQMessagesViewController.git', :tag => s.version } s.source_files = 'JSQMessagesViewController/**/*.{h,m}' @@ -21,4 +14,6 @@ Pod::Spec.new do |s| s.frameworks = 'QuartzCore', 'CoreGraphics', 'CoreLocation', 'MapKit', 'MobileCoreServices', 'AVFoundation' s.requires_arc = true + + s.deprecated = true end diff --git a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_min.png b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_min.png index 5e6f44473..62a480ea2 100644 Binary files a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_min.png and b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_min.png differ diff --git a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_min@2x.png b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_min@2x.png index cdeb1f5b5..13cfba622 100644 Binary files a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_min@2x.png and b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_min@2x.png differ diff --git a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_min@3x.png b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_min@3x.png index 6fd3e90cb..615dcab19 100644 Binary files a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_min@3x.png and b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_min@3x.png differ diff --git a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_min_tailless.png b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_min_tailless.png index db260340f..9959084c7 100644 Binary files a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_min_tailless.png and b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_min_tailless.png differ diff --git a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_min_tailless@2x.png b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_min_tailless@2x.png index 2bfe4321a..4702fa0ec 100644 Binary files a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_min_tailless@2x.png and b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_min_tailless@2x.png differ diff --git a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_min_tailless@3x.png b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_min_tailless@3x.png index 1811c2200..09d77fcb2 100644 Binary files a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_min_tailless@3x.png and b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_min_tailless@3x.png differ diff --git a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_regular.png b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_regular.png index eea6cbe88..f4e7f93d1 100644 Binary files a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_regular.png and b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_regular.png differ diff --git a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_regular@2x.png b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_regular@2x.png index 88baedb75..2322a614b 100644 Binary files a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_regular@2x.png and b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_regular@2x.png differ diff --git a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_regular@3x.png b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_regular@3x.png index 7ab50cf44..4081d1070 100644 Binary files a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_regular@3x.png and b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_regular@3x.png differ diff --git a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_stroked.png b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_stroked.png index 6b0d77f9b..6752256bf 100755 Binary files a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_stroked.png and b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_stroked.png differ diff --git a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_stroked@2x.png b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_stroked@2x.png index fdaab0063..0cfaca58b 100755 Binary files a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_stroked@2x.png and b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_stroked@2x.png differ diff --git a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_stroked@3x.png b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_stroked@3x.png index 41ce17815..4c80a0cf2 100644 Binary files a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_stroked@3x.png and b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_stroked@3x.png differ diff --git a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_stroked_tailless.png b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_stroked_tailless.png index 67f03a947..73973294f 100755 Binary files a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_stroked_tailless.png and b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_stroked_tailless.png differ diff --git a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_stroked_tailless@2x.png b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_stroked_tailless@2x.png index 158c18314..27e8532dd 100755 Binary files a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_stroked_tailless@2x.png and b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_stroked_tailless@2x.png differ diff --git a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_stroked_tailless@3x.png b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_stroked_tailless@3x.png index 170c16445..1f0235cf0 100644 Binary files a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_stroked_tailless@3x.png and b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_stroked_tailless@3x.png differ diff --git a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_tailless.png b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_tailless.png index 9445eec00..637b93d99 100644 Binary files a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_tailless.png and b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_tailless.png differ diff --git a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_tailless@2x.png b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_tailless@2x.png index 297764dd5..3ed029e28 100644 Binary files a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_tailless@2x.png and b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_tailless@2x.png differ diff --git a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_tailless@3x.png b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_tailless@3x.png index c968c39ec..9a5b9fdef 100644 Binary files a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_tailless@3x.png and b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_tailless@3x.png differ diff --git a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/clip.png b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/clip.png index 8506bbe00..ea04a1bc4 100644 Binary files a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/clip.png and b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/clip.png differ diff --git a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/clip@2x.png b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/clip@2x.png index 58ba9f5f7..1ba72fb4c 100644 Binary files a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/clip@2x.png and b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/clip@2x.png differ diff --git a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/clip@3x.png b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/clip@3x.png index caba66250..44b0d2b04 100644 Binary files a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/clip@3x.png and b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/clip@3x.png differ diff --git a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/pause.png b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/pause.png index 487a308fb..04c7c8099 100644 Binary files a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/pause.png and b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/pause.png differ diff --git a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/pause@2x.png b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/pause@2x.png index 8f5a3c2f4..0dddb7b67 100644 Binary files a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/pause@2x.png and b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/pause@2x.png differ diff --git a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/pause@3x.png b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/pause@3x.png index a15cadda6..bcbbd8f71 100644 Binary files a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/pause@3x.png and b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/pause@3x.png differ diff --git a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/play.png b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/play.png index 3bd7045bf..6bf97fcf9 100644 Binary files a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/play.png and b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/play.png differ diff --git a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/play@2x.png b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/play@2x.png index c769e68f6..0907493c5 100644 Binary files a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/play@2x.png and b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/play@2x.png differ diff --git a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/play@3x.png b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/play@3x.png index 53fb82a0d..f731b8fcb 100644 Binary files a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/play@3x.png and b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/play@3x.png differ diff --git a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/typing@2x.png b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/typing@2x.png index 1c8788d2f..c451c15b5 100644 Binary files a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/typing@2x.png and b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/typing@2x.png differ diff --git a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/typing@3x.png b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/typing@3x.png index 3849eb128..a5162468f 100644 Binary files a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/typing@3x.png and b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/typing@3x.png differ diff --git a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/bs.lproj/JSQMessages.strings b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/bs.lproj/JSQMessages.strings new file mode 100644 index 000000000..7848b1413 --- /dev/null +++ b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/bs.lproj/JSQMessages.strings @@ -0,0 +1,37 @@ +// +// Created by Jesse Squires +// http://www.jessesquires.com +// +// +// Documentation +// http://cocoadocs.org/docsets/JSQMessagesViewController +// +// +// GitHub +// https://github.com/jessesquires/JSQMessagesViewController +// +// +// License +// Copyright (c) 2014 Jesse Squires +// Released under an MIT license: http://opensource.org/licenses/MIT +// + +// ******************************** +// Special thanks to the localization contributors! +// +// https://github.com/jessesquires/JSQMessagesViewController/issues/237 +// ******************************** + +"load_earlier_messages" = "Učitaj ranije poruke"; + +"send" = "Šalji"; + +"new_message" = "Nova poruka"; + +"text_message_accessibility_label" = "%@: %@"; + +"media_message_accessibility_label" = "%@: medijska poruka"; + +"accessory_button_accessibility_label" = "Podijeli medij"; + +"new_message_received_accessibility_announcement" = "Primljena nova poruka"; diff --git a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/cs.lproj/JSQMessages.strings b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/cs.lproj/JSQMessages.strings new file mode 100644 index 000000000..7ca3737e4 --- /dev/null +++ b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/cs.lproj/JSQMessages.strings @@ -0,0 +1,37 @@ +// +// Created by Jesse Squires +// http://www.jessesquires.com +// +// +// Documentation +// http://cocoadocs.org/docsets/JSQMessagesViewController +// +// +// GitHub +// https://github.com/jessesquires/JSQMessagesViewController +// +// +// License +// Copyright (c) 2014 Jesse Squires +// Released under an MIT license: http://opensource.org/licenses/MIT +// + +// ******************************** +// Special thanks to the localization contributors! +// +// https://github.com/jessesquires/JSQMessagesViewController/issues/237 +// ******************************** + +"load_earlier_messages" = "Načíst starší zprávy"; + +"send" = "Odeslat"; + +"new_message" = "Nová zpráva"; + +"text_message_accessibility_label" = "%@: %@"; + +"media_message_accessibility_label" = "%@: multimediální zpráva"; + +"accessory_button_accessibility_label" = "Sdílet"; + +"new_message_received_accessibility_announcement" = "Přijata nová zpráva"; diff --git a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/da.lproj/JSQMessages.strings b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/da.lproj/JSQMessages.strings new file mode 100644 index 000000000..a58416dd3 --- /dev/null +++ b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/da.lproj/JSQMessages.strings @@ -0,0 +1,37 @@ +// +// Created by Jesse Squires +// http://www.jessesquires.com +// +// +// Documentation +// http://cocoadocs.org/docsets/JSQMessagesViewController +// +// +// GitHub +// https://github.com/jessesquires/JSQMessagesViewController +// +// +// License +// Copyright (c) 2014 Jesse Squires +// Released under an MIT license: http://opensource.org/licenses/MIT +// + +// ******************************** +// Special thanks to the localization contributors! +// +// https://github.com/jessesquires/JSQMessagesViewController/issues/237 +// ******************************** + +"load_earlier_messages" = "Indlæs tidligere beskeder"; + +"send" = "Send"; + +"new_message" = "Ny besked"; + +"text_message_accessibility_label" = "%@: %@"; + +"media_message_accessibility_label" = "%@: mediebesked"; + +"accessory_button_accessibility_label" = "Del medie"; + +"new_message_received_accessibility_announcement" = "Ny besked modtaget"; diff --git a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/hr.lproj/JSQMessages.strings b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/hr.lproj/JSQMessages.strings new file mode 100644 index 000000000..7848b1413 --- /dev/null +++ b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/hr.lproj/JSQMessages.strings @@ -0,0 +1,37 @@ +// +// Created by Jesse Squires +// http://www.jessesquires.com +// +// +// Documentation +// http://cocoadocs.org/docsets/JSQMessagesViewController +// +// +// GitHub +// https://github.com/jessesquires/JSQMessagesViewController +// +// +// License +// Copyright (c) 2014 Jesse Squires +// Released under an MIT license: http://opensource.org/licenses/MIT +// + +// ******************************** +// Special thanks to the localization contributors! +// +// https://github.com/jessesquires/JSQMessagesViewController/issues/237 +// ******************************** + +"load_earlier_messages" = "Učitaj ranije poruke"; + +"send" = "Šalji"; + +"new_message" = "Nova poruka"; + +"text_message_accessibility_label" = "%@: %@"; + +"media_message_accessibility_label" = "%@: medijska poruka"; + +"accessory_button_accessibility_label" = "Podijeli medij"; + +"new_message_received_accessibility_announcement" = "Primljena nova poruka"; diff --git a/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/sv.lproj/JSQMessages.strings b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/sv.lproj/JSQMessages.strings new file mode 100644 index 000000000..a7948e111 --- /dev/null +++ b/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/sv.lproj/JSQMessages.strings @@ -0,0 +1,29 @@ +// +// Created by Jesse Squires +// http://www.jessesquires.com +// +// +// Documentation +// http://cocoadocs.org/docsets/JSQMessagesViewController +// +// +// GitHub +// https://github.com/jessesquires/JSQMessagesViewController +// +// +// License +// Copyright (c) 2014 Jesse Squires +// Released under an MIT license: http://opensource.org/licenses/MIT +// + +// ******************************** +// Special thanks to the localization contributors! +// +// https://github.com/jessesquires/JSQMessagesViewController/issues/237 +// ******************************** + +"load_earlier_messages" = "Visa tidigare meddelanden"; + +"send" = "Skicka"; + +"new_message" = "Nytt meddelande"; diff --git a/JSQMessagesViewController/Controllers/JSQMessagesViewController.m b/JSQMessagesViewController/Controllers/JSQMessagesViewController.m index 0b6942a0a..cdf40c5b0 100644 --- a/JSQMessagesViewController/Controllers/JSQMessagesViewController.m +++ b/JSQMessagesViewController/Controllers/JSQMessagesViewController.m @@ -238,7 +238,9 @@ - (void)viewDidLoad - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; - self.toolbarHeightConstraint.constant = self.inputToolbar.preferredDefaultHeight; + if (!self.inputToolbar.contentView.textView.hasText) { + self.toolbarHeightConstraint.constant = self.inputToolbar.preferredDefaultHeight; + } [self.view layoutIfNeeded]; [self.collectionView.collectionViewLayout invalidateLayout]; @@ -511,7 +513,7 @@ - (UICollectionViewCell *)collectionView:(JSQMessagesCollectionView *)collection } JSQMessagesCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath]; - cell.accessibilityIdentifier = [NSString stringWithFormat:@"(%ld, %ld)", indexPath.section, indexPath.row]; + cell.accessibilityIdentifier = [NSString stringWithFormat:@"(%ld, %ld)", (long)indexPath.section, (long)indexPath.row]; cell.delegate = collectionView; if (!isMediaMessage) { @@ -678,7 +680,7 @@ - (void)collectionView:(JSQMessagesCollectionView *)collectionView performAction if ([messageData isMediaMessage]) { id mediaData = [messageData media]; - if ([messageData respondsToSelector:@selector(mediaDataType)]) { + if ([messageData conformsToProtocol:@protocol(JSQMessageData)]) { [[UIPasteboard generalPasteboard] setValue:[mediaData mediaData] forPasteboardType:[mediaData mediaDataType]]; } diff --git a/JSQMessagesViewController/Factories/JSQMessagesToolbarButtonFactory.h b/JSQMessagesViewController/Factories/JSQMessagesToolbarButtonFactory.h index 60aadf055..3a19796a5 100644 --- a/JSQMessagesViewController/Factories/JSQMessagesToolbarButtonFactory.h +++ b/JSQMessagesViewController/Factories/JSQMessagesToolbarButtonFactory.h @@ -39,7 +39,7 @@ NS_ASSUME_NONNULL_BEGIN * Creates and returns a new instance of `JSQMessagesToolbarButtonFactory` that uses * the specified font for creating buttons. * - * @param A font that will be used for the buttons produced by the factory. + * @param font The font that will be used for the buttons produced by the factory. * * @return An initialized `JSQMessagesToolbarButtonFactory` object. */ diff --git a/JSQMessagesViewController/Factories/JSQMessagesVideoThumbnailFactory.h b/JSQMessagesViewController/Factories/JSQMessagesVideoThumbnailFactory.h new file mode 100644 index 000000000..f20f821bb --- /dev/null +++ b/JSQMessagesViewController/Factories/JSQMessagesVideoThumbnailFactory.h @@ -0,0 +1,75 @@ +// +// Created by Jesse Squires +// http://www.jessesquires.com +// +// +// Documentation +// http://cocoadocs.org/docsets/JSQMessagesViewController +// +// +// GitHub +// https://github.com/jessesquires/JSQMessagesViewController +// +// +// License +// Copyright (c) 2014 Jesse Squires +// Released under an MIT license: http://opensource.org/licenses/MIT +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * A completion block for a `JSQMessagesVideoThumbnailFactory`. + * + * @see `thumbnailWithVideoMediaAsset: completion:` + */ +typedef void (^JSQMessagesVideoThumbnailCompletionBlock)(UIImage * _Nullable, NSError * _Nullable); + +/** + * `JSQMessagesVideoThumbnailFactory` is a factory that provides a means for generating + * a thumbnail image with for a `JSQVideoMediaItem`. + */ +@interface JSQMessagesVideoThumbnailFactory : NSObject + +/** + * Generates and returns a thumbnail image for the specified video media asset + * with the default time of `CMTimeMakeWithSeconds(1, 2)`. + * + * The specified block is executed upon completion of generating the thumbnail image + * and is executed on the main thread. + * + * @param asset The `AVURLAsset` for the video media item. + * @param completion The block to call after the thumbnail has been generated. + */ +- (void)thumbnailWithVideoMediaAsset:(AVURLAsset *)asset + completion:(JSQMessagesVideoThumbnailCompletionBlock)completion; + +/** + * Generates and returns a thumbnail image for the specified video media asset with a given CMTime. + * + * The specified block is executed upon completion of generating the thumbnail image and is executed on the app’s main thread. + * + * @param videoMediaAsset The instance of AVURLAsset for the video media item. + * @param time The CMTime struct for capturing the thumbnail image from the video media item. + * @param completion The block to call after the thumbnail has been generated. + */ + +/** + * Generates and returns a thumbnail image for the specified video media asset with the given `CMTime`. + * + * The specified block is executed upon completion of generating the thumbnail image + * and is executed on the main thread. + * + * @param asset The `AVURLAsset` for the video media item. + * @param time The CMTime for capturing the thumbnail image from the video asset. + * @param completion The block to call after the thumbnail has been generated. + */ +- (void)thumbnailWithVideoMediaAsset:(AVURLAsset *)asset + time:(CMTime)time + completion:(JSQMessagesVideoThumbnailCompletionBlock)completion; + +@end + +NS_ASSUME_NONNULL_END diff --git a/JSQMessagesViewController/Factories/JSQMessagesVideoThumbnailFactory.m b/JSQMessagesViewController/Factories/JSQMessagesVideoThumbnailFactory.m new file mode 100644 index 000000000..bf6c8a660 --- /dev/null +++ b/JSQMessagesViewController/Factories/JSQMessagesVideoThumbnailFactory.m @@ -0,0 +1,66 @@ +// +// Created by Jesse Squires +// http://www.jessesquires.com +// +// +// Documentation +// http://cocoadocs.org/docsets/JSQMessagesViewController +// +// +// GitHub +// https://github.com/jessesquires/JSQMessagesViewController +// +// +// License +// Copyright (c) 2014 Jesse Squires +// Released under an MIT license: http://opensource.org/licenses/MIT +// + +#import "JSQVideoMediaItem.h" + +#import "JSQMessagesVideoThumbnailFactory.h" +#import "JSQMessagesBubbleImageFactory.h" + +#import "UIImage+JSQMessages.h" + +@implementation JSQMessagesVideoThumbnailFactory + +- (void)thumbnailWithVideoMediaAsset:(AVURLAsset *)asset + completion:(JSQMessagesVideoThumbnailCompletionBlock)completion +{ + NSParameterAssert(asset != nil); + NSParameterAssert(completion != nil); + [self thumbnailWithVideoMediaAsset:asset + time:CMTimeMakeWithSeconds(1, 2) + completion:completion]; +} + +- (void)thumbnailWithVideoMediaAsset:(AVURLAsset *)asset + time:(CMTime)time + completion:(JSQMessagesVideoThumbnailCompletionBlock)completion +{ + NSParameterAssert(asset != nil); + NSParameterAssert(completion != nil); + + AVAssetImageGenerator *generate = [[AVAssetImageGenerator alloc] initWithAsset:asset]; + generate.appliesPreferredTrackTransform = YES; + + if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) { + generate.maximumSize = CGSizeMake(315.0f, 225.0f); + } + else { + generate.maximumSize = CGSizeMake(210.0f, 150.0f); + } + + NSArray *times = [NSArray arrayWithObject:[NSValue valueWithCMTime:time]]; + [generate generateCGImagesAsynchronouslyForTimes:times + completionHandler:^(CMTime requestedTime, CGImageRef im, CMTime actualTime, AVAssetImageGeneratorResult result, NSError *error) { + + UIImage *image = (result == AVAssetImageGeneratorSucceeded) ? [UIImage imageWithCGImage:im] : nil; + if (completion) { + completion(image, error); + } + }]; +} + +@end diff --git a/JSQMessagesViewController/Layout/JSQMessagesCollectionViewFlowLayout.m b/JSQMessagesViewController/Layout/JSQMessagesCollectionViewFlowLayout.m index b430d628f..099fca385 100644 --- a/JSQMessagesViewController/Layout/JSQMessagesCollectionViewFlowLayout.m +++ b/JSQMessagesViewController/Layout/JSQMessagesCollectionViewFlowLayout.m @@ -270,7 +270,7 @@ - (void)prepareLayout CGFloat padding = -100.0f; CGRect visibleRect = CGRectInset(self.collectionView.bounds, padding, padding); - NSArray *visibleItems = [super layoutAttributesForElementsInRect:visibleRect]; + NSArray *visibleItems = [[NSArray alloc] initWithArray:[super layoutAttributesForElementsInRect:visibleRect] copyItems:YES]; NSSet *visibleItemsIndexPaths = [NSSet setWithArray:[visibleItems valueForKey:NSStringFromSelector(@selector(indexPath))]]; [self jsq_removeNoLongerVisibleBehaviorsFromVisibleItemsIndexPaths:visibleItemsIndexPaths]; @@ -281,7 +281,7 @@ - (void)prepareLayout - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect { - NSArray *attributesInRect = [[super layoutAttributesForElementsInRect:rect] copy]; + NSArray *attributesInRect = [[NSArray alloc] initWithArray:[super layoutAttributesForElementsInRect:rect] copyItems:YES]; if (self.springinessEnabled) { NSMutableArray *attributesInRectCopy = [attributesInRect mutableCopy]; diff --git a/JSQMessagesViewController/Model/JSQAudioMediaItem.h b/JSQMessagesViewController/Model/JSQAudioMediaItem.h index 3534ec70b..e40d7295f 100644 --- a/JSQMessagesViewController/Model/JSQAudioMediaItem.h +++ b/JSQMessagesViewController/Model/JSQAudioMediaItem.h @@ -65,7 +65,7 @@ didChangeAudioCategory:(NSString *)category * Initializes and returns a audio media item having the given audioData. * * @param audioData The data object that contains the audio resource. - * @param audioViewConfiguration The view attributes to configure the appearance of the audio media view. + * @param audioViewAttributes The view attributes to configure the appearance of the audio media view. * * @return An initialized `JSQAudioMediaItem`. * diff --git a/JSQMessagesViewController/Model/JSQMessagesViewAccessoryButtonDelegate.h b/JSQMessagesViewController/Model/JSQMessagesViewAccessoryButtonDelegate.h index 3c6e48db2..ca8948c5e 100644 --- a/JSQMessagesViewController/Model/JSQMessagesViewAccessoryButtonDelegate.h +++ b/JSQMessagesViewController/Model/JSQMessagesViewAccessoryButtonDelegate.h @@ -33,7 +33,7 @@ NS_ASSUME_NONNULL_BEGIN * Notifies the delegate that the accessory button at the specified indexPath did receive a tap event. * * @param messageView The collection view object that is notifying the delegate of the tap event. - * @param indexPath The index path of the item for which the accessory button was tapped. + * @param path The index path of the item for which the accessory button was tapped. */ - (void)messageView:(JSQMessagesCollectionView *)messageView didTapAccessoryButtonAtIndexPath:(NSIndexPath *)path; diff --git a/JSQMessagesViewController/Model/JSQVideoMediaItem.h b/JSQMessagesViewController/Model/JSQVideoMediaItem.h index 4046d2e48..b6738db92 100644 --- a/JSQMessagesViewController/Model/JSQVideoMediaItem.h +++ b/JSQMessagesViewController/Model/JSQVideoMediaItem.h @@ -33,9 +33,14 @@ NS_ASSUME_NONNULL_BEGIN */ @property (nonatomic, strong, nullable) NSURL *fileURL; +/** + * The thumbnail image to display for the video. + */ +@property (nonatomic, strong, nullable) UIImage *thumbnailImage; + /** * A boolean value that specifies whether or not the video is ready to be played. - * + * * @discussion When set to `YES`, the video is ready. When set to `NO` it is not ready. */ @property (nonatomic, assign) BOOL isReadyToPlay; @@ -55,6 +60,25 @@ NS_ASSUME_NONNULL_BEGIN */ - (instancetype)initWithFileURL:(nullable NSURL *)fileURL isReadyToPlay:(BOOL)isReadyToPlay; +/** + * Initializes and returns a video media item having the given fileURL. + * + * @param fileURL The URL that identifies the video resource. + * @param isReadyToPlay A boolean value that specifies if the video is ready to play. + * @param thumbnailImage The background thumbnail image for the video. + * + * @return An initialized `JSQVideoMediaItem` if successful, `nil` otherwise. + * + * @discussion If the video must be downloaded from the network, + * you may initialize a `JSQVideoMediaItem` with a `nil` fileURL or specify `NO` for + * isReadyToPlay. Once the video has been saved to disk, or is ready to stream, you can + * set the fileURL property or isReadyToPlay property, respectively. The background thumbnail + * is optional. + */ +- (instancetype)initWithFileURL:(NSURL *)fileURL + isReadyToPlay:(BOOL)isReadyToPlay + thumbnailImage:(nullable UIImage *)thumbnailImage; + @end NS_ASSUME_NONNULL_END diff --git a/JSQMessagesViewController/Model/JSQVideoMediaItem.m b/JSQMessagesViewController/Model/JSQVideoMediaItem.m index d499acbcd..885fb748c 100644 --- a/JSQMessagesViewController/Model/JSQVideoMediaItem.m +++ b/JSQMessagesViewController/Model/JSQVideoMediaItem.m @@ -20,6 +20,7 @@ #import "JSQMessagesMediaPlaceholderView.h" #import "JSQMessagesMediaViewBubbleImageMasker.h" +#import "JSQMessagesVideoThumbnailFactory.h" #import "UIImage+JSQMessages.h" @@ -36,12 +37,18 @@ @implementation JSQVideoMediaItem #pragma mark - Initialization - (instancetype)initWithFileURL:(NSURL *)fileURL isReadyToPlay:(BOOL)isReadyToPlay +{ + return [self initWithFileURL:fileURL isReadyToPlay:isReadyToPlay thumbnailImage:nil]; +} + +- (instancetype)initWithFileURL:(NSURL *)fileURL isReadyToPlay:(BOOL)isReadyToPlay thumbnailImage:(UIImage *)thumbnailImage { self = [super init]; if (self) { _fileURL = [fileURL copy]; _isReadyToPlay = isReadyToPlay; _cachedVideoImageView = nil; + _thumbnailImage = thumbnailImage; } return self; } @@ -79,20 +86,33 @@ - (UIView *)mediaView if (self.fileURL == nil || !self.isReadyToPlay) { return nil; } - + if (self.cachedVideoImageView == nil) { CGSize size = [self mediaViewDisplaySize]; UIImage *playIcon = [[UIImage jsq_defaultPlayImage] jsq_imageMaskedWithColor:[UIColor lightGrayColor]]; - + UIImageView *imageView = [[UIImageView alloc] initWithImage:playIcon]; - imageView.backgroundColor = [UIColor blackColor]; imageView.frame = CGRectMake(0.0f, 0.0f, size.width, size.height); imageView.contentMode = UIViewContentModeCenter; imageView.clipsToBounds = YES; [JSQMessagesMediaViewBubbleImageMasker applyBubbleImageMaskToMediaView:imageView isOutgoing:self.appliesMediaViewMaskAsOutgoing]; - self.cachedVideoImageView = imageView; + + if (self.thumbnailImage) { + UIImageView *thumbnailImageView = [[UIImageView alloc] initWithImage:self.thumbnailImage]; + thumbnailImageView.frame = CGRectMake(0.0f, 0.0f, size.width, size.height); + thumbnailImageView.contentMode = UIViewContentModeCenter; + thumbnailImageView.clipsToBounds = YES; + [JSQMessagesMediaViewBubbleImageMasker applyBubbleImageMaskToMediaView:thumbnailImageView isOutgoing:self.appliesMediaViewMaskAsOutgoing]; + imageView.backgroundColor = [UIColor clearColor]; + [thumbnailImageView addSubview:imageView]; + self.cachedVideoImageView = thumbnailImageView; + } + else { + imageView.backgroundColor = [UIColor blackColor]; + self.cachedVideoImageView = imageView; + } } - + return self.cachedVideoImageView; } @@ -108,11 +128,11 @@ - (BOOL)isEqual:(id)object if (![super isEqual:object]) { return NO; } - + JSQVideoMediaItem *videoItem = (JSQVideoMediaItem *)object; - + return [self.fileURL isEqual:videoItem.fileURL] - && self.isReadyToPlay == videoItem.isReadyToPlay; + && self.isReadyToPlay == videoItem.isReadyToPlay; } - (NSUInteger)hash @@ -122,8 +142,8 @@ - (NSUInteger)hash - (NSString *)description { - return [NSString stringWithFormat:@"<%@: fileURL=%@, isReadyToPlay=%@, appliesMediaViewMaskAsOutgoing=%@>", - [self class], self.fileURL, @(self.isReadyToPlay), @(self.appliesMediaViewMaskAsOutgoing)]; + return [NSString stringWithFormat:@"<%@: fileURL=%@, isReadyToPlay=%@, appliesMediaViewMaskAsOutgoing=%@>, thumbnailImage=%@", + [self class], self.fileURL, @(self.isReadyToPlay), @(self.appliesMediaViewMaskAsOutgoing), self.thumbnailImage]; } #pragma mark - NSCoding @@ -134,6 +154,7 @@ - (instancetype)initWithCoder:(NSCoder *)aDecoder if (self) { _fileURL = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(fileURL))]; _isReadyToPlay = [aDecoder decodeBoolForKey:NSStringFromSelector(@selector(isReadyToPlay))]; + _thumbnailImage = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(thumbnailImage))]; } return self; } @@ -143,6 +164,7 @@ - (void)encodeWithCoder:(NSCoder *)aCoder [super encodeWithCoder:aCoder]; [aCoder encodeObject:self.fileURL forKey:NSStringFromSelector(@selector(fileURL))]; [aCoder encodeBool:self.isReadyToPlay forKey:NSStringFromSelector(@selector(isReadyToPlay))]; + [aCoder encodeObject:self.thumbnailImage forKey:NSStringFromSelector(@selector(thumbnailImage))]; } #pragma mark - NSCopying @@ -150,7 +172,8 @@ - (void)encodeWithCoder:(NSCoder *)aCoder - (instancetype)copyWithZone:(NSZone *)zone { JSQVideoMediaItem *copy = [[[self class] allocWithZone:zone] initWithFileURL:self.fileURL - isReadyToPlay:self.isReadyToPlay]; + isReadyToPlay:self.isReadyToPlay + thumbnailImage:self.thumbnailImage]; copy.appliesMediaViewMaskAsOutgoing = self.appliesMediaViewMaskAsOutgoing; return copy; } diff --git a/JSQMessagesViewController/Views/JSQMessagesComposerTextView.h b/JSQMessagesViewController/Views/JSQMessagesComposerTextView.h index b81f5e766..496fcc1a7 100644 --- a/JSQMessagesViewController/Views/JSQMessagesComposerTextView.h +++ b/JSQMessagesViewController/Views/JSQMessagesComposerTextView.h @@ -54,6 +54,11 @@ NS_ASSUME_NONNULL_BEGIN */ @property (strong, nonatomic) UIColor *placeHolderTextColor; +/** + * The insets to be used when the placeholder is drawn. The default value is `UIEdgeInsets(5.0, 7.0, 5.0, 7.0)`. + */ +@property (assign, nonatomic) UIEdgeInsets placeHolderInsets; + /** * The object that acts as the paste delegate of the text view. */ diff --git a/JSQMessagesViewController/Views/JSQMessagesComposerTextView.m b/JSQMessagesViewController/Views/JSQMessagesComposerTextView.m index c21ecd271..94e5ff0e7 100644 --- a/JSQMessagesViewController/Views/JSQMessagesComposerTextView.m +++ b/JSQMessagesViewController/Views/JSQMessagesComposerTextView.m @@ -68,6 +68,7 @@ - (void)jsq_configureTextView _placeHolder = nil; _placeHolderTextColor = [UIColor lightGrayColor]; + _placeHolderInsets = UIEdgeInsetsMake(5.0, 7.0, 5.0, 7.0); [self associateConstraints]; @@ -169,6 +170,16 @@ - (void)setPlaceHolderTextColor:(UIColor *)placeHolderTextColor [self setNeedsDisplay]; } +- (void)setPlaceHolderInsets:(UIEdgeInsets)placeHolderInsets +{ + if (UIEdgeInsetsEqualToEdgeInsets(placeHolderInsets, _placeHolderInsets)) { + return; + } + + _placeHolderInsets = placeHolderInsets; + [self setNeedsDisplay]; +} + #pragma mark - UITextView overrides @@ -220,8 +231,8 @@ - (void)drawRect:(CGRect)rect if ([self.text length] == 0 && self.placeHolder) { [self.placeHolderTextColor set]; - - [self.placeHolder drawInRect:CGRectInset(rect, 7.0f, 5.0f) + + [self.placeHolder drawInRect:UIEdgeInsetsInsetRect(rect, self.placeHolderInsets) withAttributes:[self jsq_placeholderTextAttributes]]; } } diff --git a/README.md b/README.md index 16e166a19..db4e521c0 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,13 @@ -![JSQMessagesViewController banner](https://raw.githubusercontent.com/jessesquires/JSQMessagesViewController/develop/Assets/jsq_messages_banner.png) - -[![Build Status](https://secure.travis-ci.org/jessesquires/JSQMessagesViewController.svg)](https://travis-ci.org/jessesquires/JSQMessagesViewController) [![Version Status](https://img.shields.io/cocoapods/v/JSQMessagesViewController.svg)][podLink] [![license MIT](https://img.shields.io/cocoapods/l/JSQMessagesViewController.svg)][mitLink] [![codecov](https://codecov.io/gh/jessesquires/JSQMessagesViewController/branch/develop/graph/badge.svg)](https://codecov.io/gh/jessesquires/JSQMessagesViewController) [![Platform](https://img.shields.io/cocoapods/p/JSQMessagesViewController.svg)][docsLink] +[![No Maintenance Intended](http://unmaintained.tech/badge.svg)](http://unmaintained.tech/) ------------------------- +# :warning: Deprecated :warning: -## :warning: Announcement :warning: +This library is deprecated. Please read [my blog post](http://www.jessesquires.com/blog/officially-deprecating-jsqmessagesviewcontroller/) for details. -Development on version `8.0` of the library is underway. Learn more at [#1216](https://github.com/jessesquires/JSQMessagesViewController/issues/1216) and [#1336](https://github.com/jessesquires/JSQMessagesViewController/issues/1336). -Submit work for `v8.0` to the [`develop`](https://github.com/jessesquires/JSQMessagesViewController/tree/develop) branch. +![JSQMessagesViewController banner](https://raw.githubusercontent.com/jessesquires/JSQMessagesViewController/develop/Assets/jsq_messages_banner.png) -Submit fixes for `v7.3.x` to the [`release_7.3`](https://github.com/jessesquires/JSQMessagesViewController/tree/release_7.3) branch. +[![Build Status](https://secure.travis-ci.org/jessesquires/JSQMessagesViewController.svg)](https://travis-ci.org/jessesquires/JSQMessagesViewController) [![Version Status](https://img.shields.io/cocoapods/v/JSQMessagesViewController.svg)][podLink] [![license MIT](https://img.shields.io/cocoapods/l/JSQMessagesViewController.svg)][mitLink] [![codecov](https://codecov.io/gh/jessesquires/JSQMessagesViewController/branch/develop/graph/badge.svg)](https://codecov.io/gh/jessesquires/JSQMessagesViewController) [![Platform](https://img.shields.io/cocoapods/p/JSQMessagesViewController.svg)][docsLink] ------------------------ @@ -22,7 +19,7 @@ Submit fixes for `v7.3.x` to the [`release_7.3`](https://github.com/jessesquires ## Features -See the [website](http://www.jessesquires.com/JSQMessagesViewController/) for the list of features. +See the [website](http://jessesquires.github.io/JSQMessagesViewController) for the list of features. ## Design Goals @@ -74,6 +71,8 @@ Read the docs, [available here][docsLink] via [@CocoaDocs](https://twitter.com/C - Harlan Haskans ([**@harlanhaskins**](https://github.com/harlanhaskins)) - Eli Burke ([**@eliburke**](https://github.com/eliburke)) - Sebastian Ludwig ([**@sebastianludwig**](https://github.com/sebastianludwig)) +- Lucas Huang ([**@Lucashuang0802**](https://github.com/Lucashuang0802)) +- Dan Leonard ([**@macmedan**](https://github.com/macmedan)) ## Contributing @@ -89,7 +88,7 @@ Please follow these sweet [contribution guidelines](https://github.com/jessesqui ## Apps using this library -According to [CocoaPods stats](https://cocoapods.org/pods/JSQMessagesViewController), over **10,000 apps** are using `JSQMessagesViewController`. [Here are the ones](https://github.com/jessesquires/JSQMessagesViewController/blob/develop/Documentation/apps_using_this_library.md) that we know about. Please submit a [pull request](https://github.com/jessesquires/JSQMessagesViewController/compare) to add your app! :smile: +According to [CocoaPods stats](https://cocoapods.org/pods/JSQMessagesViewController), over **36,000 apps** are using `JSQMessagesViewController`. [Here are the ones](https://github.com/jessesquires/JSQMessagesViewController/blob/develop/Documentation/apps_using_this_library.md) that we know about. Please submit a [pull request](https://github.com/jessesquires/JSQMessagesViewController/compare) to add your app! :smile: ## License diff --git a/SwiftExample/SwiftExample.xcodeproj/project.pbxproj b/SwiftExample/SwiftExample.xcodeproj/project.pbxproj index 1e6f9aef6..0d40caf50 100644 --- a/SwiftExample/SwiftExample.xcodeproj/project.pbxproj +++ b/SwiftExample/SwiftExample.xcodeproj/project.pbxproj @@ -197,14 +197,16 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0730; - LastUpgradeCheck = 0730; + LastUpgradeCheck = 0800; ORGANIZATIONNAME = MacMeDan; TargetAttributes = { F82D09BE1CDFBB4900DD74CF = { CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 0800; }; F84895281CE0EE8800F5B654 = { CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 0800; TestTargetID = F82D09BE1CDFBB4900DD74CF; }; }; @@ -409,11 +411,12 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -455,11 +458,12 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; @@ -475,6 +479,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 9.3; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; @@ -485,10 +490,12 @@ baseConfigurationReference = 3D5DE46B5737B20C9B95257C /* Pods-SwiftExample.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = SwiftExample/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.MacMeDan.SwiftExample; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -497,10 +504,12 @@ baseConfigurationReference = 8F35C314AF75B616FAD01E7A /* Pods-SwiftExample.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = SwiftExample/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.MacMeDan.SwiftExample; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; }; name = Release; }; @@ -513,6 +522,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.MacMeDan.SwiftExampleTests; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SwiftExample.app/SwiftExample"; }; name = Debug; @@ -526,6 +536,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.MacMeDan.SwiftExampleTests; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SwiftExample.app/SwiftExample"; }; name = Release; diff --git a/SwiftExample/SwiftExample/AppDelegate.swift b/SwiftExample/SwiftExample/AppDelegate.swift index c23912800..b5f280a9e 100644 --- a/SwiftExample/SwiftExample/AppDelegate.swift +++ b/SwiftExample/SwiftExample/AppDelegate.swift @@ -14,30 +14,30 @@ class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? - func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. return true } - func applicationWillResignActive(application: UIApplication) { + func applicationWillResignActive(_ application: UIApplication) { // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. } - func applicationDidEnterBackground(application: UIApplication) { + func applicationDidEnterBackground(_ application: UIApplication) { // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. } - func applicationWillEnterForeground(application: UIApplication) { + func applicationWillEnterForeground(_ application: UIApplication) { // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. } - func applicationDidBecomeActive(application: UIApplication) { + func applicationDidBecomeActive(_ application: UIApplication) { // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. } - func applicationWillTerminate(application: UIApplication) { + func applicationWillTerminate(_ application: UIApplication) { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. } diff --git a/SwiftExample/SwiftExample/Assets.xcassets/AppIcon.appiconset/Icon-167.png b/SwiftExample/SwiftExample/Assets.xcassets/AppIcon.appiconset/Icon-167.png new file mode 100644 index 000000000..62482f415 Binary files /dev/null and b/SwiftExample/SwiftExample/Assets.xcassets/AppIcon.appiconset/Icon-167.png differ diff --git a/SwiftExample/SwiftExample/Assets.xcassets/AppIcon.appiconset/Icon-29.png b/SwiftExample/SwiftExample/Assets.xcassets/AppIcon.appiconset/Icon-29.png new file mode 100644 index 000000000..2ff6e7aa0 Binary files /dev/null and b/SwiftExample/SwiftExample/Assets.xcassets/AppIcon.appiconset/Icon-29.png differ diff --git a/SwiftExample/SwiftExample/Assets.xcassets/AppIcon.appiconset/Icon-29@2x-1.png b/SwiftExample/SwiftExample/Assets.xcassets/AppIcon.appiconset/Icon-29@2x-1.png new file mode 100644 index 000000000..ab8d5ba9f Binary files /dev/null and b/SwiftExample/SwiftExample/Assets.xcassets/AppIcon.appiconset/Icon-29@2x-1.png differ diff --git a/SwiftExample/SwiftExample/Assets.xcassets/AppIcon.appiconset/Icon-29@2x.png b/SwiftExample/SwiftExample/Assets.xcassets/AppIcon.appiconset/Icon-29@2x.png new file mode 100644 index 000000000..8bd09d719 Binary files /dev/null and b/SwiftExample/SwiftExample/Assets.xcassets/AppIcon.appiconset/Icon-29@2x.png differ diff --git a/SwiftExample/SwiftExample/Assets.xcassets/AppIcon.appiconset/Icon-29@3x.png b/SwiftExample/SwiftExample/Assets.xcassets/AppIcon.appiconset/Icon-29@3x.png new file mode 100644 index 000000000..c17579d54 Binary files /dev/null and b/SwiftExample/SwiftExample/Assets.xcassets/AppIcon.appiconset/Icon-29@3x.png differ diff --git a/SwiftExample/SwiftExample/Assets.xcassets/AppIcon.appiconset/Icon-40.png b/SwiftExample/SwiftExample/Assets.xcassets/AppIcon.appiconset/Icon-40.png new file mode 100644 index 000000000..fa39765c5 Binary files /dev/null and b/SwiftExample/SwiftExample/Assets.xcassets/AppIcon.appiconset/Icon-40.png differ diff --git a/SwiftExample/SwiftExample/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png b/SwiftExample/SwiftExample/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png new file mode 100644 index 000000000..8ced5f0a2 Binary files /dev/null and b/SwiftExample/SwiftExample/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png differ diff --git a/SwiftExample/SwiftExample/Assets.xcassets/AppIcon.appiconset/Icon-40@3x.png b/SwiftExample/SwiftExample/Assets.xcassets/AppIcon.appiconset/Icon-40@3x.png new file mode 100644 index 000000000..c425c198a Binary files /dev/null and b/SwiftExample/SwiftExample/Assets.xcassets/AppIcon.appiconset/Icon-40@3x.png differ diff --git a/SwiftExample/SwiftExample/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png b/SwiftExample/SwiftExample/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png new file mode 100644 index 000000000..c567b0387 Binary files /dev/null and b/SwiftExample/SwiftExample/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png differ diff --git a/SwiftExample/SwiftExample/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png b/SwiftExample/SwiftExample/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png new file mode 100644 index 000000000..1799534d6 Binary files /dev/null and b/SwiftExample/SwiftExample/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png differ diff --git a/SwiftExample/SwiftExample/Assets.xcassets/AppIcon.appiconset/Icon-76.png b/SwiftExample/SwiftExample/Assets.xcassets/AppIcon.appiconset/Icon-76.png new file mode 100644 index 000000000..5606a3d3b Binary files /dev/null and b/SwiftExample/SwiftExample/Assets.xcassets/AppIcon.appiconset/Icon-76.png differ diff --git a/SwiftExample/SwiftExample/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png b/SwiftExample/SwiftExample/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png new file mode 100644 index 000000000..728210b90 Binary files /dev/null and b/SwiftExample/SwiftExample/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png differ diff --git a/SwiftExample/SwiftExample/Assets.xcassets/AppIcon.appiconset/icon40@3x.png b/SwiftExample/SwiftExample/Assets.xcassets/AppIcon.appiconset/icon40@3x.png new file mode 100644 index 000000000..04e689a27 Binary files /dev/null and b/SwiftExample/SwiftExample/Assets.xcassets/AppIcon.appiconset/icon40@3x.png differ diff --git a/SwiftExample/SwiftExample/ChatViewController.swift b/SwiftExample/SwiftExample/ChatViewController.swift index 12f9c5017..fbf824f68 100644 --- a/SwiftExample/SwiftExample/ChatViewController.swift +++ b/SwiftExample/SwiftExample/ChatViewController.swift @@ -11,11 +11,11 @@ import JSQMessagesViewController class ChatViewController: JSQMessagesViewController { var messages = [JSQMessage]() - let defaults = NSUserDefaults.standardUserDefaults() + let defaults = UserDefaults.standard var conversation: Conversation? var incomingBubble: JSQMessagesBubbleImage! var outgoingBubble: JSQMessagesBubbleImage! - private var displayName: String! + fileprivate var displayName: String! override func viewDidLoad() { super.viewDidLoad() @@ -31,22 +31,22 @@ class ChatViewController: JSQMessagesViewController { * */ - if defaults.boolForKey(Setting.removeBubbleTails.rawValue) { + if defaults.bool(forKey: Setting.removeBubbleTails.rawValue) { // Make taillessBubbles - incomingBubble = JSQMessagesBubbleImageFactory(bubbleImage: UIImage.jsq_bubbleCompactTaillessImage(), capInsets: UIEdgeInsetsZero, layoutDirection: UIApplication.sharedApplication().userInterfaceLayoutDirection).incomingMessagesBubbleImageWithColor(UIColor.jsq_messageBubbleBlueColor()) - outgoingBubble = JSQMessagesBubbleImageFactory(bubbleImage: UIImage.jsq_bubbleCompactTaillessImage(), capInsets: UIEdgeInsetsZero, layoutDirection: UIApplication.sharedApplication().userInterfaceLayoutDirection).outgoingMessagesBubbleImageWithColor(UIColor.lightGrayColor()) + incomingBubble = JSQMessagesBubbleImageFactory(bubble: UIImage.jsq_bubbleCompactTailless(), capInsets: UIEdgeInsets.zero, layoutDirection: UIApplication.shared.userInterfaceLayoutDirection).incomingMessagesBubbleImage(with: UIColor.jsq_messageBubbleBlue()) + outgoingBubble = JSQMessagesBubbleImageFactory(bubble: UIImage.jsq_bubbleCompactTailless(), capInsets: UIEdgeInsets.zero, layoutDirection: UIApplication.shared.userInterfaceLayoutDirection).outgoingMessagesBubbleImage(with: UIColor.lightGray) } else { // Bubbles with tails - incomingBubble = JSQMessagesBubbleImageFactory().incomingMessagesBubbleImageWithColor(UIColor.jsq_messageBubbleBlueColor()) - outgoingBubble = JSQMessagesBubbleImageFactory().outgoingMessagesBubbleImageWithColor(UIColor.lightGrayColor()) + incomingBubble = JSQMessagesBubbleImageFactory().incomingMessagesBubbleImage(with: UIColor.jsq_messageBubbleBlue()) + outgoingBubble = JSQMessagesBubbleImageFactory().outgoingMessagesBubbleImage(with: UIColor.lightGray) } /** * Example on showing or removing Avatars based on user settings. */ - if defaults.boolForKey(Setting.removeAvatar.rawValue) { + if defaults.bool(forKey: Setting.removeAvatar.rawValue) { collectionView?.collectionViewLayout.incomingAvatarViewSize = .zero collectionView?.collectionViewLayout.outgoingAvatarViewSize = .zero } else { @@ -55,7 +55,7 @@ class ChatViewController: JSQMessagesViewController { } // Show Button to simulate incoming messages - self.navigationItem.rightBarButtonItem = UIBarButtonItem(image: UIImage.jsq_defaultTypingIndicatorImage(), style: .Plain, target: self, action: #selector(receiveMessagePressed)) + self.navigationItem.rightBarButtonItem = UIBarButtonItem(image: UIImage.jsq_defaultTypingIndicator(), style: .plain, target: self, action: #selector(receiveMessagePressed)) // This is a beta feature that mostly works but to make things more stable it is diabled. collectionView?.collectionViewLayout.springinessEnabled = false @@ -67,14 +67,14 @@ class ChatViewController: JSQMessagesViewController { } func setupBackButton() { - let backButton = UIBarButtonItem(title: "Back", style: UIBarButtonItemStyle.Plain, target: self, action: #selector(backButtonTapped)) + let backButton = UIBarButtonItem(title: "Back", style: UIBarButtonItemStyle.plain, target: self, action: #selector(backButtonTapped)) navigationItem.leftBarButtonItem = backButton } func backButtonTapped() { - dismissViewControllerAnimated(true, completion: nil) + dismiss(animated: true, completion: nil) } - func receiveMessagePressed(sender: UIBarButtonItem) { + func receiveMessagePressed(_ sender: UIBarButtonItem) { /** * DEMO ONLY * @@ -90,7 +90,7 @@ class ChatViewController: JSQMessagesViewController { /** * Scroll to actually view the indicator */ - self.scrollToBottomAnimated(true) + self.scrollToBottom(animated: true) /** * Copy last sent message, this will be the new "received" message @@ -105,18 +105,18 @@ class ChatViewController: JSQMessagesViewController { var newMediaData:JSQMessageMediaData! var newMediaAttachmentCopy:AnyObject? - if copyMessage!.isMediaMessage() { + if (copyMessage! as AnyObject).isMediaMessage() { /** * Last message was a media message */ - let copyMediaData = copyMessage!.media + let copyMediaData = (copyMessage! as AnyObject).media switch copyMediaData { case is JSQPhotoMediaItem: let photoItemCopy = (copyMediaData as! JSQPhotoMediaItem).copy() as! JSQPhotoMediaItem photoItemCopy.appliesMediaViewMaskAsOutgoing = false - newMediaAttachmentCopy = UIImage(CGImage: photoItemCopy.image!.CGImage!) + newMediaAttachmentCopy = UIImage(cgImage: photoItemCopy.image!.cgImage!) /** * Set image to nil to simulate "downloading" the image @@ -128,7 +128,7 @@ class ChatViewController: JSQMessagesViewController { case is JSQLocationMediaItem: let locationItemCopy = (copyMediaData as! JSQLocationMediaItem).copy() as! JSQLocationMediaItem locationItemCopy.appliesMediaViewMaskAsOutgoing = false - newMediaAttachmentCopy = locationItemCopy.location!.copy() + newMediaAttachmentCopy = locationItemCopy.location!.copy() as AnyObject? /** * Set location to nil to simulate "downloading" the location data @@ -139,7 +139,7 @@ class ChatViewController: JSQMessagesViewController { case is JSQVideoMediaItem: let videoItemCopy = (copyMediaData as! JSQVideoMediaItem).copy() as! JSQVideoMediaItem videoItemCopy.appliesMediaViewMaskAsOutgoing = false - newMediaAttachmentCopy = videoItemCopy.fileURL!.copy() + newMediaAttachmentCopy = (videoItemCopy.fileURL! as NSURL).copy() as AnyObject? /** * Reset video item to simulate "downloading" the video @@ -151,7 +151,7 @@ class ChatViewController: JSQMessagesViewController { case is JSQAudioMediaItem: let audioItemCopy = (copyMediaData as! JSQAudioMediaItem).copy() as! JSQAudioMediaItem audioItemCopy.appliesMediaViewMaskAsOutgoing = false - newMediaAttachmentCopy = audioItemCopy.audioData!.copy() + newMediaAttachmentCopy = (audioItemCopy.audioData! as NSData).copy() as AnyObject? /** * Reset audio item to simulate "downloading" the audio @@ -170,7 +170,7 @@ class ChatViewController: JSQMessagesViewController { * Last message was a text message */ - newMessage = JSQMessage(senderId: AvatarIdJobs, displayName: getName(User.Jobs), text: copyMessage!.text) + newMessage = JSQMessage(senderId: AvatarIdJobs, displayName: getName(User.Jobs), text: (copyMessage! as AnyObject).text) } /** @@ -182,13 +182,13 @@ class ChatViewController: JSQMessagesViewController { */ self.messages.append(newMessage) - self.finishReceivingMessageAnimated(true) + self.finishReceivingMessage(animated: true) if newMessage.isMediaMessage { /** * Simulate "downloading" media */ - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(1 * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) { + DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + Double(Int64(1 * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)) { /** * Media is "finished downloading", re-display visible cells * @@ -206,11 +206,11 @@ class ChatViewController: JSQMessagesViewController { self.collectionView!.reloadData() }) case is JSQVideoMediaItem: - (newMediaData as! JSQVideoMediaItem).fileURL = newMediaAttachmentCopy as? NSURL + (newMediaData as! JSQVideoMediaItem).fileURL = newMediaAttachmentCopy as? URL (newMediaData as! JSQVideoMediaItem).isReadyToPlay = true self.collectionView!.reloadData() case is JSQAudioMediaItem: - (newMediaData as! JSQAudioMediaItem).audioData = newMediaAttachmentCopy as? NSData + (newMediaData as! JSQAudioMediaItem).audioData = newMediaAttachmentCopy as? Data self.collectionView!.reloadData() default: assertionFailure("Error: This Media type was not recognised") @@ -220,7 +220,7 @@ class ChatViewController: JSQMessagesViewController { } // MARK: JSQMessagesViewController method overrides - override func didPressSendButton(button: UIButton, withMessageText text: String, senderId: String, senderDisplayName: String, date: NSDate) { + override func didPressSend(_ button: UIButton, withMessageText text: String, senderId: String, senderDisplayName: String, date: Date) { /** * Sending a message. Your implementation of this method should do *at least* the following: * @@ -231,15 +231,15 @@ class ChatViewController: JSQMessagesViewController { let message = JSQMessage(senderId: senderId, senderDisplayName: senderDisplayName, date: date, text: text) self.messages.append(message) - self.finishSendingMessageAnimated(true) + self.finishSendingMessage(animated: true) } - override func didPressAccessoryButton(sender: UIButton) { + override func didPressAccessoryButton(_ sender: UIButton) { self.inputToolbar.contentView!.textView!.resignFirstResponder() - let sheet = UIAlertController(title: "Media messages", message: nil, preferredStyle: .ActionSheet) + let sheet = UIAlertController(title: "Media messages", message: nil, preferredStyle: .actionSheet) - let photoAction = UIAlertAction(title: "Send photo", style: .Default) { (action) in + let photoAction = UIAlertAction(title: "Send photo", style: .default) { (action) in /** * Create fake photo */ @@ -247,7 +247,7 @@ class ChatViewController: JSQMessagesViewController { self.addMedia(photoItem) } - let locationAction = UIAlertAction(title: "Send location", style: .Default) { (action) in + let locationAction = UIAlertAction(title: "Send location", style: .default) { (action) in /** * Add fake location */ @@ -256,7 +256,7 @@ class ChatViewController: JSQMessagesViewController { self.addMedia(locationItem) } - let videoAction = UIAlertAction(title: "Send video", style: .Default) { (action) in + let videoAction = UIAlertAction(title: "Send video", style: .default) { (action) in /** * Add fake video */ @@ -265,7 +265,7 @@ class ChatViewController: JSQMessagesViewController { self.addMedia(videoItem) } - let audioAction = UIAlertAction(title: "Send audio", style: .Default) { (action) in + let audioAction = UIAlertAction(title: "Send audio", style: .default) { (action) in /** * Add fake audio */ @@ -274,7 +274,7 @@ class ChatViewController: JSQMessagesViewController { self.addMedia(audioItem) } - let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel, handler: nil) + let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil) sheet.addAction(photoAction) sheet.addAction(locationAction) @@ -282,11 +282,11 @@ class ChatViewController: JSQMessagesViewController { sheet.addAction(audioAction) sheet.addAction(cancelAction) - self.presentViewController(sheet, animated: true, completion: nil) + self.present(sheet, animated: true, completion: nil) } func buildVideoItem() -> JSQVideoMediaItem { - let videoURL = NSURL(fileURLWithPath: "file://") + let videoURL = URL(fileURLWithPath: "file://") let videoItem = JSQVideoMediaItem(fileURL: videoURL, isReadyToPlay: true) @@ -294,8 +294,8 @@ class ChatViewController: JSQMessagesViewController { } func buildAudioItem() -> JSQAudioMediaItem { - let sample = NSBundle.mainBundle().pathForResource("jsq_messages_sample", ofType: "m4a") - let audioData = NSData(contentsOfFile: sample!) + let sample = Bundle.main.path(forResource: "jsq_messages_sample", ofType: "m4a") + let audioData = try? Data(contentsOf: URL(fileURLWithPath: sample!)) let audioItem = JSQAudioMediaItem(data: audioData) @@ -313,45 +313,45 @@ class ChatViewController: JSQMessagesViewController { return locationItem } - func addMedia(media:JSQMediaItem) { + func addMedia(_ media:JSQMediaItem) { let message = JSQMessage(senderId: self.senderId(), displayName: self.senderDisplayName(), media: media) self.messages.append(message) //Optional: play sent sound - self.finishSendingMessageAnimated(true) + self.finishSendingMessage(animated: true) } //MARK: JSQMessages CollectionView DataSource override func senderId() -> String { - return User.Wazniak.rawValue + return User.Wozniak.rawValue } override func senderDisplayName() -> String { - return getName(User.Wazniak) + return getName(.Wozniak) } - override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return messages.count } - override func collectionView(collectionView: JSQMessagesCollectionView, messageDataForItemAtIndexPath indexPath: NSIndexPath) -> JSQMessageData { + override func collectionView(_ collectionView: JSQMessagesCollectionView, messageDataForItemAt indexPath: IndexPath) -> JSQMessageData { return messages[indexPath.item] } - override func collectionView(collectionView: JSQMessagesCollectionView, messageBubbleImageDataForItemAtIndexPath indexPath: NSIndexPath) -> JSQMessageBubbleImageDataSource { + override func collectionView(_ collectionView: JSQMessagesCollectionView, messageBubbleImageDataForItemAt indexPath: IndexPath) -> JSQMessageBubbleImageDataSource { return messages[indexPath.item].senderId == self.senderId() ? outgoingBubble : incomingBubble } - override func collectionView(collectionView: JSQMessagesCollectionView, avatarImageDataForItemAtIndexPath indexPath: NSIndexPath) -> JSQMessageAvatarImageDataSource? { + override func collectionView(_ collectionView: JSQMessagesCollectionView, avatarImageDataForItemAt indexPath: IndexPath) -> JSQMessageAvatarImageDataSource? { let message = messages[indexPath.item] return getAvatar(message.senderId) } - override func collectionView(collectionView: JSQMessagesCollectionView, attributedTextForCellTopLabelAtIndexPath indexPath: NSIndexPath) -> NSAttributedString? { + override func collectionView(_ collectionView: JSQMessagesCollectionView, attributedTextForCellTopLabelAt indexPath: IndexPath) -> NSAttributedString? { /** * This logic should be consistent with what you return from `heightForCellTopLabelAtIndexPath:` * The other label text delegate methods should follow a similar pattern. @@ -361,13 +361,13 @@ class ChatViewController: JSQMessagesViewController { if (indexPath.item % 3 == 0) { let message = self.messages[indexPath.item] - return JSQMessagesTimestampFormatter.sharedFormatter().attributedTimestampForDate(message.date) + return JSQMessagesTimestampFormatter.shared().attributedTimestamp(for: message.date) } return nil } - override func collectionView(collectionView: JSQMessagesCollectionView, attributedTextForMessageBubbleTopLabelAtIndexPath indexPath: NSIndexPath) -> NSAttributedString? { + override func collectionView(_ collectionView: JSQMessagesCollectionView, attributedTextForMessageBubbleTopLabelAt indexPath: IndexPath) -> NSAttributedString? { let message = messages[indexPath.item] // Displaying names above messages @@ -376,7 +376,7 @@ class ChatViewController: JSQMessagesViewController { * Example on showing or removing senderDisplayName based on user settings. * This logic should be consistent with what you return from `heightForCellTopLabelAtIndexPath:` */ - if defaults.boolForKey(Setting.removeSenderDisplayName.rawValue) { + if defaults.bool(forKey: Setting.removeSenderDisplayName.rawValue) { return nil } @@ -387,7 +387,7 @@ class ChatViewController: JSQMessagesViewController { return NSAttributedString(string: message.senderDisplayName) } - override func collectionView(collectionView: JSQMessagesCollectionView, layout collectionViewLayout: JSQMessagesCollectionViewFlowLayout, heightForCellTopLabelAtIndexPath indexPath: NSIndexPath) -> CGFloat { + override func collectionView(_ collectionView: JSQMessagesCollectionView, layout collectionViewLayout: JSQMessagesCollectionViewFlowLayout, heightForCellTopLabelAt indexPath: IndexPath) -> CGFloat { /** * Each label in a cell has a `height` delegate method that corresponds to its text dataSource method */ @@ -405,13 +405,13 @@ class ChatViewController: JSQMessagesViewController { return 0.0 } - override func collectionView(collectionView: JSQMessagesCollectionView, layout collectionViewLayout: JSQMessagesCollectionViewFlowLayout, heightForMessageBubbleTopLabelAtIndexPath indexPath: NSIndexPath) -> CGFloat { + override func collectionView(_ collectionView: JSQMessagesCollectionView, layout collectionViewLayout: JSQMessagesCollectionViewFlowLayout, heightForMessageBubbleTopLabelAt indexPath: IndexPath) -> CGFloat { /** * Example on showing or removing senderDisplayName based on user settings. * This logic should be consistent with what you return from `attributedTextForCellTopLabelAtIndexPath:` */ - if defaults.boolForKey(Setting.removeSenderDisplayName.rawValue) { + if defaults.bool(forKey: Setting.removeSenderDisplayName.rawValue) { return 0.0 } diff --git a/SwiftExample/SwiftExample/DemoConversation.swift b/SwiftExample/SwiftExample/DemoConversation.swift index db023ce9c..7dbde4456 100644 --- a/SwiftExample/SwiftExample/DemoConversation.swift +++ b/SwiftExample/SwiftExample/DemoConversation.swift @@ -14,18 +14,18 @@ enum User: String { case Squires = "053496-4509-289" case Jobs = "707-8956784-57" case Cook = "468-768355-23123" - case Wazniak = "309-41802-93823" + case Wozniak = "309-41802-93823" } // Helper Function to get usernames for a secific User. -func getName(user: User) -> String{ +func getName(_ user: User) -> String{ switch user { case .Squires: return "Jesse Squires" case .Cook: return "Tim Cook" - case .Wazniak: - return "Steve Wazniak" + case .Wozniak: + return "Steve Wozniak" case .Leonard: return "Dan Leonard" case .Jobs: @@ -52,19 +52,19 @@ let AvatarIdWoz = "309-41802-93823" // // Create an avatar with Image -let AvatarLeonard = JSQMessagesAvatarImageFactory().avatarImageWithUserInitials("DL", backgroundColor: UIColor.jsq_messageBubbleGreenColor(), textColor: UIColor.whiteColor(), font: UIFont.systemFontOfSize(12)) +let AvatarLeonard = JSQMessagesAvatarImageFactory().avatarImage(withUserInitials: "DL", backgroundColor: UIColor.jsq_messageBubbleGreen(), textColor: UIColor.white, font: UIFont.systemFont(ofSize: 12)) -let AvatarCook = JSQMessagesAvatarImageFactory().avatarImageWithUserInitials("TC", backgroundColor: UIColor.grayColor(), textColor: UIColor.whiteColor(), font: UIFont.systemFontOfSize(12)) +let AvatarCook = JSQMessagesAvatarImageFactory().avatarImage(withUserInitials: "TC", backgroundColor: UIColor.gray, textColor: UIColor.white, font: UIFont.systemFont(ofSize: 12)) // Create avatar with Placeholder Image -let AvatarJobs = JSQMessagesAvatarImageFactory().avatarImageWithPlaceholder(UIImage(named:"demo_avatar_jobs")!) +let AvatarJobs = JSQMessagesAvatarImageFactory().avatarImage(withPlaceholder: UIImage(named:"demo_avatar_jobs")!) -let AvatarWaz = JSQMessagesAvatarImageFactory().avatarImageWithUserInitials("SW", backgroundColor: UIColor.jsq_messageBubbleGreenColor(), textColor: UIColor.whiteColor(), font: UIFont.systemFontOfSize(12)) +let AvatarWoz = JSQMessagesAvatarImageFactory().avatarImage(withUserInitials: "SW", backgroundColor: UIColor.jsq_messageBubbleGreen(), textColor: UIColor.white, font: UIFont.systemFont(ofSize: 12)) -let AvatarSquires = JSQMessagesAvatarImageFactory().avatarImageWithUserInitials("JSQ", backgroundColor: UIColor.grayColor(), textColor: UIColor.whiteColor(), font: UIFont.systemFontOfSize(12)) +let AvatarSquires = JSQMessagesAvatarImageFactory().avatarImage(withUserInitials: "JSQ", backgroundColor: UIColor.gray, textColor: UIColor.white, font: UIFont.systemFont(ofSize: 12)) // Helper Method for getting an avatar for a specific User. -func getAvatar(id: String) -> JSQMessagesAvatarImage{ +func getAvatar(_ id: String) -> JSQMessagesAvatarImage{ let user = User(rawValue: id)! switch user { @@ -74,8 +74,8 @@ func getAvatar(id: String) -> JSQMessagesAvatarImage{ return AvatarSquires case .Cook: return AvatarCook - case .Wazniak: - return AvatarWaz + case .Wozniak: + return AvatarWoz case .Jobs: return AvatarJobs } @@ -92,25 +92,25 @@ var conversation = [JSQMessage]() let message = JSQMessage(senderId: AvatarIdCook, displayName: getName(User.Cook), text: "What is this Black Majic?") let message2 = JSQMessage(senderId: AvatarIDSquires, displayName: getName(User.Squires), text: "It is simple, elegant, and easy to use. There are super sweet default settings, but you can customize like crazy") -let message3 = JSQMessage(senderId: AvatarIdWoz, displayName: getName(User.Wazniak), text: "It even has data detectors. You can call me tonight. My cell number is 123-456-7890. My website is www.hexedbits.com.") +let message3 = JSQMessage(senderId: AvatarIdWoz, displayName: getName(User.Wozniak), text: "It even has data detectors. You can call me tonight. My cell number is 123-456-7890. My website is www.hexedbits.com.") let message4 = JSQMessage(senderId: AvatarIdJobs, displayName: getName(User.Jobs), text: "JSQMessagesViewController is nearly an exact replica of the iOS Messages App. And perhaps, better.") let message5 = JSQMessage(senderId: AvatarIDLeonard, displayName: getName(User.Leonard), text: "It is unit-tested, free, open-source, and documented.") let message6 = JSQMessage(senderId: AvatarIDLeonard, displayName: getName(User.Leonard), text: "This is incredible") -let message7 = JSQMessage(senderId: AvatarIdWoz, displayName: getName(User.Wazniak), text: "I would have to agree") +let message7 = JSQMessage(senderId: AvatarIdWoz, displayName: getName(User.Wozniak), text: "I would have to agree") let message8 = JSQMessage(senderId: AvatarIDLeonard, displayName: getName(User.Leonard), text: "It is unit-tested, free, open-source, and documented like a boss.") -let message9 = JSQMessage(senderId: AvatarIdWoz, displayName: getName(User.Wazniak), text: "You guys need an award for this, I'll talk to my people at Apple. 💯 💯 💯") +let message9 = JSQMessage(senderId: AvatarIdWoz, displayName: getName(User.Wozniak), text: "You guys need an award for this, I'll talk to my people at Apple. 💯 💯 💯") // photo message let photoItem = JSQPhotoMediaItem(image: UIImage(named: "goldengate")) -let photoMessage = JSQMessage(senderId: AvatarIdWoz, displayName: getName(User.Wazniak), media: photoItem) +let photoMessage = JSQMessage(senderId: AvatarIdWoz, displayName: getName(User.Wozniak), media: photoItem) // audio mesage -let sample = NSBundle.mainBundle().pathForResource("jsq_messages_sample", ofType: "m4a") -let audioData = NSData(contentsOfFile: sample!) +let sample = Bundle.main.path(forResource: "jsq_messages_sample", ofType: "m4a") +let audioData = try? Data(contentsOf: URL(fileURLWithPath: sample!)) let audioItem = JSQAudioMediaItem(data: audioData) -let audioMessage = JSQMessage(senderId: AvatarIdWoz, displayName: getName(User.Wazniak), media: audioItem) +let audioMessage = JSQMessage(senderId: AvatarIdWoz, displayName: getName(User.Wozniak), media: audioItem) func makeGroupConversation()->[JSQMessage] { conversation = [message, message2,message3, message4, message5, photoMessage, audioMessage] diff --git a/SwiftExample/SwiftExample/InitalTableViewController.swift b/SwiftExample/SwiftExample/InitalTableViewController.swift index bbe4b6871..b0fa2a62f 100644 --- a/SwiftExample/SwiftExample/InitalTableViewController.swift +++ b/SwiftExample/SwiftExample/InitalTableViewController.swift @@ -17,17 +17,17 @@ class InitalTableViewController: UITableViewController { override func viewDidLoad() { super.viewDidLoad() self.title = "JSQMessagesViewControler in Swift" - tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: cellIdentifier) + tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellIdentifier) } // MARK: - Table view data source - override func numberOfSectionsInTableView(tableView: UITableView) -> Int { + override func numberOfSections(in tableView: UITableView) -> Int { return 2 } - override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { switch (section) { case 0: @@ -39,9 +39,9 @@ class InitalTableViewController: UITableViewController { } } - override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - guard let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier) else { + guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier) else { return UITableViewCell() } @@ -71,7 +71,7 @@ class InitalTableViewController: UITableViewController { return cell } - override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? { + override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { switch section { case 0: @@ -83,11 +83,11 @@ class InitalTableViewController: UITableViewController { } } - override func tableView(tableView: UITableView, titleForFooterInSection section: Int) -> String? { + override func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? { switch section { - case 2: + case 0: return "Copyright © 2015\nJesse Squires\nMIT License" - case 3: + case 1: return "Thanks to all the contributers and MacMeDan for this swift example." default: return nil @@ -96,7 +96,7 @@ class InitalTableViewController: UITableViewController { //Mark: - Table view delegate - override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { switch indexPath.section { case 0: switch indexPath.row { @@ -104,19 +104,19 @@ class InitalTableViewController: UITableViewController { let chatView = ChatViewController() chatView.messages = makeNormalConversation() let chatNavigationController = UINavigationController(rootViewController: chatView) - presentViewController(chatNavigationController, animated: true, completion: nil) + present(chatNavigationController, animated: true, completion: nil) case 1: let chatView = ChatViewController() chatView.messages = makeGroupConversation() let chatNavigationController = UINavigationController(rootViewController: chatView) - presentViewController(chatNavigationController, animated: true, completion: nil) + present(chatNavigationController, animated: true, completion: nil) default: return } case 1: switch indexPath.row { case 0: - self.presentViewController(UINavigationController(rootViewController: SettingsTableViewController()), animated: true, completion: nil) + self.present(UINavigationController(rootViewController: SettingsTableViewController()), animated: true, completion: nil) default: return } @@ -125,6 +125,6 @@ class InitalTableViewController: UITableViewController { } } - + } diff --git a/SwiftExample/SwiftExample/SettingsTableViewController.swift b/SwiftExample/SwiftExample/SettingsTableViewController.swift index f5f080eeb..b85aed21e 100644 --- a/SwiftExample/SwiftExample/SettingsTableViewController.swift +++ b/SwiftExample/SwiftExample/SettingsTableViewController.swift @@ -16,7 +16,7 @@ public enum Setting: String{ case removeAvatar = "Remove Avatars" } -let defaults = NSUserDefaults.standardUserDefaults() +let defaults = UserDefaults.standard var rows = [Setting]() class SettingsTableViewController: UITableViewController { @@ -28,46 +28,46 @@ class SettingsTableViewController: UITableViewController { rows = [.removeAvatar, .removeBubbleTails, .removeSenderDisplayName] // Set the Switch to the currents settings self.title = "Settings" - tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: cellReuseIdentifier) + tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellReuseIdentifier) } // MARK: - Table view data source - override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - guard let cell = tableView.dequeueReusableCellWithIdentifier(cellReuseIdentifier) else { + guard let cell = tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier) else { return UITableViewCell() } let row = rows[indexPath.row] let settingSwitch = UISwitch() settingSwitch.tag = indexPath.row - settingSwitch.on = defaults.boolForKey(row.rawValue) ?? false - settingSwitch.addTarget(self, action: #selector(switchValueChanged), forControlEvents: .ValueChanged) + settingSwitch.isOn = defaults.bool(forKey: row.rawValue) + settingSwitch.addTarget(self, action: #selector(switchValueChanged), for: .valueChanged) cell.accessoryView = settingSwitch cell.textLabel?.text = row.rawValue return cell } - func switchValueChanged(sender: UISwitch) { - defaults.setBool(sender.on, forKey: rows[sender.tag].rawValue) + func switchValueChanged(_ sender: UISwitch) { + defaults.set(sender.isOn, forKey: rows[sender.tag].rawValue) } func setupBackButton() { - let backButton = UIBarButtonItem(title: "Back", style: UIBarButtonItemStyle.Plain, target: self, action: #selector(backButtonTapped)) + let backButton = UIBarButtonItem(title: "Back", style: UIBarButtonItemStyle.plain, target: self, action: #selector(backButtonTapped)) navigationItem.leftBarButtonItem = backButton } func backButtonTapped() { - dismissViewControllerAnimated(true, completion: nil) + dismiss(animated: true, completion: nil) } //Mark: - Table view delegate - override func numberOfSectionsInTableView(tableView: UITableView) -> Int { + override func numberOfSections(in tableView: UITableView) -> Int { return 1 } - override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return 3 } } diff --git a/SwiftExample/SwiftExampleTests/ChatViewControllerTests.swift b/SwiftExample/SwiftExampleTests/ChatViewControllerTests.swift index db4190744..c89115b5a 100644 --- a/SwiftExample/SwiftExampleTests/ChatViewControllerTests.swift +++ b/SwiftExample/SwiftExampleTests/ChatViewControllerTests.swift @@ -12,8 +12,7 @@ import JSQMessagesViewController @testable import SwiftExample class ChatViewControllerTests: XCTestCase { - - let changeSetting = NSUserDefaults.standardUserDefaults().setBool + let defaults = UserDefaults.standard let chatViewController = ChatViewController() override func setUp() { @@ -27,22 +26,22 @@ class ChatViewControllerTests: XCTestCase { } override func tearDown() { super.tearDown() - changeSetting(false, forKey: Setting.removeAvatar.rawValue) - changeSetting(false, forKey: Setting.removeSenderDisplayName.rawValue) - changeSetting(false, forKey: Setting.removeBubbleTails.rawValue) + defaults.set(false, forKey: Setting.removeAvatar.rawValue) + defaults.set(false, forKey: Setting.removeSenderDisplayName.rawValue) + defaults.set(false, forKey: Setting.removeBubbleTails.rawValue) } func testSendButtonAction() { let _ = chatViewController.view - let button = self.chatViewController.inputToolbar.sendButtonOnRight ? self.chatViewController.inputToolbar.contentView!.rightBarButtonItem! : self.chatViewController.inputToolbar.contentView!.leftBarButtonItem! + let button = self.chatViewController.inputToolbar.sendButtonLocation == .right ? self.chatViewController.inputToolbar.contentView!.rightBarButtonItem! : self.chatViewController.inputToolbar.contentView!.leftBarButtonItem! let text = "Testing text" let senderId = self.chatViewController.senderId() let senderDisplayName = self.chatViewController.senderDisplayName() - let date = NSDate() + let date = Date() let originalCount = self.chatViewController.messages.count - self.chatViewController.didPressSendButton(button, withMessageText: text, senderId: senderId, senderDisplayName: senderDisplayName, date: date) + self.chatViewController.didPressSend(button, withMessageText: text, senderId: senderId, senderDisplayName: senderDisplayName, date: date) let newCount = self.chatViewController.messages.count @@ -129,7 +128,7 @@ class ChatViewControllerTests: XCTestCase { // trigger action let rightBarButton = self.chatViewController.navigationItem.rightBarButtonItem! - rightBarButton.target!.performSelector(rightBarButton.action, withObject: rightBarButton) + rightBarButton.target!.perform(rightBarButton.action, with: rightBarButton) let lastMessage = self.chatViewController.messages.last! @@ -138,7 +137,7 @@ class ChatViewControllerTests: XCTestCase { XCTAssert(lastMessage.senderDisplayName != self.chatViewController.senderDisplayName()) // triger action - rightBarButton.target!.performSelector(rightBarButton.action, withObject: rightBarButton) + rightBarButton.target!.perform(rightBarButton.action, with: rightBarButton) let newMessage = self.chatViewController.messages.last! @@ -161,7 +160,7 @@ class ChatViewControllerTests: XCTestCase { // trigger action let rightBarButton = self.chatViewController.navigationItem.rightBarButtonItem! - rightBarButton.target!.performSelector(rightBarButton.action, withObject: rightBarButton) + rightBarButton.target!.perform(rightBarButton.action, with: rightBarButton) let newMessage = self.chatViewController.messages.last! @@ -184,7 +183,7 @@ class ChatViewControllerTests: XCTestCase { // trigger action let rightBarButton = self.chatViewController.navigationItem.rightBarButtonItem! - rightBarButton.target!.performSelector(rightBarButton.action, withObject: rightBarButton) + rightBarButton.target!.perform(rightBarButton.action, with: rightBarButton) let newMessage = self.chatViewController.messages.last! @@ -195,7 +194,7 @@ class ChatViewControllerTests: XCTestCase { } func testRemoveAvatarSetting() { - changeSetting(true, forKey: Setting.removeAvatar.rawValue) + defaults.set(true, forKey: Setting.removeAvatar.rawValue) let _ = chatViewController.view XCTAssertEqual(chatViewController.collectionView?.collectionViewLayout.incomingAvatarViewSize, .zero, "Incoming Avatar should be hidden") @@ -203,26 +202,26 @@ class ChatViewControllerTests: XCTestCase { } func testSenderDisplayNameDefaultSetting() { - changeSetting(false, forKey: Setting.removeSenderDisplayName.rawValue) + defaults.set(false, forKey: Setting.removeSenderDisplayName.rawValue) let _ = chatViewController.view + let button = self.chatViewController.inputToolbar.sendButtonLocation == .right ? self.chatViewController.inputToolbar.contentView!.rightBarButtonItem! : self.chatViewController.inputToolbar.contentView!.leftBarButtonItem! + let sender = User.Cook + self.chatViewController.didPressSend(button, withMessageText: "Testing Text", senderId: sender.rawValue, senderDisplayName: getName(sender), date: Date()) - let button = self.chatViewController.inputToolbar.sendButtonOnRight ? self.chatViewController.inputToolbar.contentView!.rightBarButtonItem! : self.chatViewController.inputToolbar.contentView!.leftBarButtonItem! - self.chatViewController.didPressSendButton(button, withMessageText: "Testing Text", senderId: chatViewController.senderId(), senderDisplayName: chatViewController.senderDisplayName(), date: NSDate()) - - let senderDisplayName = chatViewController.collectionView(self.chatViewController.collectionView!, attributedTextForMessageBubbleTopLabelAtIndexPath: NSIndexPath(forItem: self.chatViewController.messages.count - 1, inSection: 0)) + let senderDisplayName = chatViewController.collectionView(self.chatViewController.collectionView!, attributedTextForMessageBubbleTopLabelAt: IndexPath(item: self.chatViewController.messages.count - 1, section: 0)) XCTAssertNotNil(senderDisplayName, "Sender Display should not be nil") } func testRemoveSenderDisplayNameSetting() { - changeSetting(true, forKey: Setting.removeSenderDisplayName.rawValue) + defaults.set(true, forKey: Setting.removeSenderDisplayName.rawValue) let _ = chatViewController.view - let button = self.chatViewController.inputToolbar.sendButtonOnRight ? self.chatViewController.inputToolbar.contentView!.rightBarButtonItem! : self.chatViewController.inputToolbar.contentView!.leftBarButtonItem! - self.chatViewController.didPressSendButton(button, withMessageText: "Testing Text", senderId: chatViewController.senderId(), senderDisplayName: chatViewController.senderDisplayName(), date: NSDate()) + let button = self.chatViewController.inputToolbar.sendButtonLocation == .right ? self.chatViewController.inputToolbar.contentView!.rightBarButtonItem! : self.chatViewController.inputToolbar.contentView!.leftBarButtonItem! + self.chatViewController.didPressSend(button, withMessageText: "Testing Text", senderId: chatViewController.senderId(), senderDisplayName: chatViewController.senderDisplayName(), date: Date()) - XCTAssertNil(chatViewController.collectionView(self.chatViewController.collectionView!, attributedTextForMessageBubbleTopLabelAtIndexPath: NSIndexPath(forItem: self.chatViewController.messages.count - 1, inSection: 0)), "Sender Display should be nil") + XCTAssertNil(chatViewController.collectionView(self.chatViewController.collectionView!, attributedTextForMessageBubbleTopLabelAt: IndexPath(item: self.chatViewController.messages.count - 1, section: 0)), "Sender Display should be nil") } -} \ No newline at end of file +} diff --git a/SwiftExample/SwiftExampleTests/SettingsTests.swift b/SwiftExample/SwiftExampleTests/SettingsTests.swift index 7967046d5..2a2c61600 100644 --- a/SwiftExample/SwiftExampleTests/SettingsTests.swift +++ b/SwiftExample/SwiftExampleTests/SettingsTests.swift @@ -19,6 +19,6 @@ class SettingsTests: XCTestCase { func testSettingsView() { let _ = settingsView.view - XCTAssertEqual(settingsView.tableView.numberOfRowsInSection(0), 3) + XCTAssertEqual(settingsView.tableView.numberOfRows(inSection: 0), 3) } }