├── .gitignore
├── Assets
├── CollectionMulti-Message.png
├── CollectionSingle-Message.png
├── ContentNode.png
├── Custom-Message.png
├── DefaultBubble.png
├── Image-Message.png
├── ImageBubble.png
├── MessageGroup.png
├── Mg-Add.gif
├── Mg-Delete.gif
├── Mg-Replace.gif
├── NMessenger-Overview.png
├── SimpleBubble.png
├── StackedBubble.png
├── Text-Message.png
├── TypingIndicator.png
└── nmessenger.png
├── Cartfile
├── LICENSE
├── NMessenger.podspec
├── Podfile
├── README.md
├── examples
└── MessageGroups
│ ├── MessageGroups.xcodeproj
│ ├── project.pbxproj
│ └── project.xcworkspace
│ │ └── contents.xcworkspacedata
│ ├── MessageGroups
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── Base.lproj
│ │ └── Main.storyboard
│ ├── EntryViewController.swift
│ ├── ExampleMessengerViewController.swift
│ └── Info.plist
│ ├── MessageGroupsTests
│ ├── Info.plist
│ └── MessageGroupsTests.swift
│ ├── MessageGroupsUITests
│ ├── Info.plist
│ └── MessageGroupsUITests.swift
│ └── Podfile
├── nMessenger-iOS
├── Info.plist
└── nMessenger-iOS.h
├── nMessenger.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ └── contents.xcworkspacedata
└── xcshareddata
│ └── xcschemes
│ └── nMessenger-iOS.xcscheme
├── nMessenger
├── AppDelegate.swift
├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ └── Contents.json
├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
├── Info.plist
├── Source
│ ├── Animated
│ │ └── loadBubble-iOS
│ │ │ ├── loadBubble@1x.gif
│ │ │ ├── loadBubble@2x.gif
│ │ │ ├── loadBubble@3x.gif
│ │ │ ├── loadBubble_1x
│ │ │ ├── loadBubble_0000_Layer-39@1x.png
│ │ │ ├── loadBubble_0001_Layer-38@1x.png
│ │ │ ├── loadBubble_0002_Layer-37@1x.png
│ │ │ ├── loadBubble_0003_Layer-36@1x.png
│ │ │ ├── loadBubble_0004_Layer-35@1x.png
│ │ │ ├── loadBubble_0005_Layer-34@1x.png
│ │ │ ├── loadBubble_0006_Layer-33@1x.png
│ │ │ ├── loadBubble_0007_Layer-32@1x.png
│ │ │ ├── loadBubble_0008_Layer-31@1x.png
│ │ │ ├── loadBubble_0009_Layer-30@1x.png
│ │ │ ├── loadBubble_0010_Layer-29@1x.png
│ │ │ ├── loadBubble_0011_Layer-28@1x.png
│ │ │ ├── loadBubble_0012_Layer-27@1x.png
│ │ │ ├── loadBubble_0013_Layer-26@1x.png
│ │ │ ├── loadBubble_0014_Layer-25@1x.png
│ │ │ ├── loadBubble_0015_Layer-24@1x.png
│ │ │ ├── loadBubble_0016_Layer-23@1x.png
│ │ │ ├── loadBubble_0017_Layer-22@1x.png
│ │ │ ├── loadBubble_0018_Layer-21@1x.png
│ │ │ ├── loadBubble_0019_Layer-20@1x.png
│ │ │ ├── loadBubble_0020_Layer-19@1x.png
│ │ │ ├── loadBubble_0021_Layer-18@1x.png
│ │ │ ├── loadBubble_0022_Layer-17@1x.png
│ │ │ ├── loadBubble_0023_Layer-16@1x.png
│ │ │ ├── loadBubble_0024_Layer-15@1x.png
│ │ │ ├── loadBubble_0025_Layer-14@1x.png
│ │ │ ├── loadBubble_0026_Layer-13@1x.png
│ │ │ ├── loadBubble_0027_Layer-12@1x.png
│ │ │ ├── loadBubble_0028_Layer-11@1x.png
│ │ │ ├── loadBubble_0029_Layer-10@1x.png
│ │ │ ├── loadBubble_0030_Layer-9@1x.png
│ │ │ ├── loadBubble_0031_Layer-8@1x.png
│ │ │ ├── loadBubble_0032_Layer-7@1x.png
│ │ │ ├── loadBubble_0033_Layer-6@1x.png
│ │ │ ├── loadBubble_0034_Layer-5@1x.png
│ │ │ ├── loadBubble_0035_Layer-4@1x.png
│ │ │ ├── loadBubble_0036_Layer-3@1x.png
│ │ │ ├── loadBubble_0037_Layer-2@1x.png
│ │ │ └── loadBubble_0038_Layer-1@1x.png
│ │ │ ├── loadBubble_2x
│ │ │ ├── loadBubble_0000_Layer-39@2x.png
│ │ │ ├── loadBubble_0001_Layer-38@2x.png
│ │ │ ├── loadBubble_0002_Layer-37@2x.png
│ │ │ ├── loadBubble_0003_Layer-36@2x.png
│ │ │ ├── loadBubble_0004_Layer-35@2x.png
│ │ │ ├── loadBubble_0005_Layer-34@2x.png
│ │ │ ├── loadBubble_0006_Layer-33@2x.png
│ │ │ ├── loadBubble_0007_Layer-32@2x.png
│ │ │ ├── loadBubble_0008_Layer-31@2x.png
│ │ │ ├── loadBubble_0009_Layer-30@2x.png
│ │ │ ├── loadBubble_0010_Layer-29@2x.png
│ │ │ ├── loadBubble_0011_Layer-28@2x.png
│ │ │ ├── loadBubble_0012_Layer-27@2x.png
│ │ │ ├── loadBubble_0013_Layer-26@2x.png
│ │ │ ├── loadBubble_0014_Layer-25@2x.png
│ │ │ ├── loadBubble_0015_Layer-24@2x.png
│ │ │ ├── loadBubble_0016_Layer-23@2x.png
│ │ │ ├── loadBubble_0017_Layer-22@2x.png
│ │ │ ├── loadBubble_0018_Layer-21@2x.png
│ │ │ ├── loadBubble_0019_Layer-20@2x.png
│ │ │ ├── loadBubble_0020_Layer-19@2x.png
│ │ │ ├── loadBubble_0021_Layer-18@2x.png
│ │ │ ├── loadBubble_0022_Layer-17@2x.png
│ │ │ ├── loadBubble_0023_Layer-16@2x.png
│ │ │ ├── loadBubble_0024_Layer-15@2x.png
│ │ │ ├── loadBubble_0025_Layer-14@2x.png
│ │ │ ├── loadBubble_0026_Layer-13@2x.png
│ │ │ ├── loadBubble_0027_Layer-12@2x.png
│ │ │ ├── loadBubble_0028_Layer-11@2x.png
│ │ │ ├── loadBubble_0029_Layer-10@2x.png
│ │ │ ├── loadBubble_0030_Layer-9@2x.png
│ │ │ ├── loadBubble_0031_Layer-8@2x.png
│ │ │ ├── loadBubble_0032_Layer-7@2x.png
│ │ │ ├── loadBubble_0033_Layer-6@2x.png
│ │ │ ├── loadBubble_0034_Layer-5@2x.png
│ │ │ ├── loadBubble_0035_Layer-4@2x.png
│ │ │ ├── loadBubble_0036_Layer-3@2x.png
│ │ │ ├── loadBubble_0037_Layer-2@2x.png
│ │ │ └── loadBubble_0038_Layer-1@2x.png
│ │ │ └── loadBubble_3x
│ │ │ ├── loadBubble_0000_Layer-39@3x.png
│ │ │ ├── loadBubble_0001_Layer-38@3x.png
│ │ │ ├── loadBubble_0002_Layer-37@3x.png
│ │ │ ├── loadBubble_0003_Layer-36@3x.png
│ │ │ ├── loadBubble_0004_Layer-35@3x.png
│ │ │ ├── loadBubble_0005_Layer-34@3x.png
│ │ │ ├── loadBubble_0006_Layer-33@3x.png
│ │ │ ├── loadBubble_0007_Layer-32@3x.png
│ │ │ ├── loadBubble_0008_Layer-31@3x.png
│ │ │ ├── loadBubble_0009_Layer-30@3x.png
│ │ │ ├── loadBubble_0010_Layer-29@3x.png
│ │ │ ├── loadBubble_0011_Layer-28@3x.png
│ │ │ ├── loadBubble_0012_Layer-27@3x.png
│ │ │ ├── loadBubble_0013_Layer-26@3x.png
│ │ │ ├── loadBubble_0014_Layer-25@3x.png
│ │ │ ├── loadBubble_0015_Layer-24@3x.png
│ │ │ ├── loadBubble_0016_Layer-23@3x.png
│ │ │ ├── loadBubble_0017_Layer-22@3x.png
│ │ │ ├── loadBubble_0018_Layer-21@3x.png
│ │ │ ├── loadBubble_0019_Layer-20@3x.png
│ │ │ ├── loadBubble_0020_Layer-19@3x.png
│ │ │ ├── loadBubble_0021_Layer-18@3x.png
│ │ │ ├── loadBubble_0022_Layer-17@3x.png
│ │ │ ├── loadBubble_0023_Layer-16@3x.png
│ │ │ ├── loadBubble_0024_Layer-15@3x.png
│ │ │ ├── loadBubble_0025_Layer-14@3x.png
│ │ │ ├── loadBubble_0026_Layer-13@3x.png
│ │ │ ├── loadBubble_0027_Layer-12@3x.png
│ │ │ ├── loadBubble_0028_Layer-11@3x.png
│ │ │ ├── loadBubble_0029_Layer-10@3x.png
│ │ │ ├── loadBubble_0030_Layer-9@3x.png
│ │ │ ├── loadBubble_0031_Layer-8@3x.png
│ │ │ ├── loadBubble_0032_Layer-7@3x.png
│ │ │ ├── loadBubble_0033_Layer-6@3x.png
│ │ │ ├── loadBubble_0034_Layer-5@3x.png
│ │ │ ├── loadBubble_0035_Layer-4@3x.png
│ │ │ ├── loadBubble_0036_Layer-3@3x.png
│ │ │ ├── loadBubble_0037_Layer-2@3x.png
│ │ │ └── loadBubble_0038_Layer-1@3x.png
│ ├── Images
│ │ ├── MessageBubble.png
│ │ ├── cameraRollIcon.png
│ │ ├── cameraRollIcon@2x.png
│ │ ├── cameraRollIcon@3x.png
│ │ ├── exitIcon.png
│ │ ├── flashIcon.png
│ │ ├── flashIcon@2x.png
│ │ ├── flashIcon@3x.png
│ │ ├── flipCameraIcon.png
│ │ ├── shutterBtn.png
│ │ ├── shutterBtn@2x.png
│ │ └── shutterBtn@3x.png
│ ├── MessageNodes
│ │ ├── BubbleConfiguration
│ │ │ ├── BubbleConfigurationProtocol.swift
│ │ │ ├── ImageBubbleConfiguration.swift
│ │ │ ├── SimpleBubbleConfiguration.swift
│ │ │ └── StandardBubbleConfiguration.swift
│ │ ├── Bubbles
│ │ │ ├── Bubble.swift
│ │ │ ├── DefaultBubble.swift
│ │ │ ├── ImageBubble.swift
│ │ │ ├── SimpleBubble.swift
│ │ │ └── StackedBubble.swift
│ │ ├── ContentNodes
│ │ │ ├── CollectionViewContent
│ │ │ │ ├── CollectionViewContentNode.swift
│ │ │ │ └── CustomContentCellNode.swift
│ │ │ ├── ContentNode.swift
│ │ │ ├── CustomContentContent
│ │ │ │ └── CustomContentNode.swift
│ │ │ ├── ImageContent
│ │ │ │ └── ImageContentNode.swift
│ │ │ ├── NetworkImageContent
│ │ │ │ └── NetworkImageContentNode.swift
│ │ │ ├── TextContent
│ │ │ │ └── TextContentNode.swift
│ │ │ └── TypingIndicatorContent
│ │ │ │ └── TypingIndicatorContent.swift
│ │ ├── GeneralMessageCell
│ │ │ └── GeneralMessengerCell.swift
│ │ ├── Indicators
│ │ │ ├── HeadLoadingIndicator.swift
│ │ │ └── MessageSentIndicator.swift
│ │ └── MessageCell
│ │ │ ├── MessageCellProtocol.swift
│ │ │ ├── MessageGroup.swift
│ │ │ └── MessageNode.swift
│ ├── Messenger
│ │ ├── Components
│ │ │ ├── CameraViewController.swift
│ │ │ ├── InputBarView
│ │ │ │ ├── InputBarView.swift
│ │ │ │ ├── InputBarViewProtocol.swift
│ │ │ │ ├── NMessengerBarView.swift
│ │ │ │ └── NMessengerBarView.xib
│ │ │ └── NMessenger.swift
│ │ └── NMessengerViewController.swift
│ └── Utilities
│ │ ├── ModalAlertUtilities.swift
│ │ ├── UIColor+N1Colors.swift
│ │ └── UIFont+N1Fonts.swift
└── ViewController.swift
├── nMessengerTests
├── Extensions
│ ├── UIColorTests.swift
│ └── UIFontTests.swift
├── Info.plist
├── Messenger
│ └── NMessengerTests.swift
├── UI Components
│ ├── Chat
│ │ ├── BubbleConfigurationTests.swift
│ │ ├── BubbleTests.swift
│ │ ├── CollectionViewContentNodeTests.swift
│ │ ├── HeadLoadingIndicatorTests.swift
│ │ ├── MessageGroupTests.swift
│ │ ├── MessageNodeTests.swift
│ │ └── NetworkImageContentNodeTests.swift
│ └── NMessengerVCTests.swift
└── nMessengerTests.swift
└── nMessengerUITests
├── Info.plist
├── OrientationUITest.swift
└── nMessengerUITests.swift
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
3 | ## Build generated
4 | build/
5 | DerivedData/
6 | Pods/
7 | Podfile.lock
8 | Carthage/
9 | Cartfile.resolved
10 | *.xcworkspace
11 |
12 | ## Various settings
13 | *.pbxuser
14 | !default.pbxuser
15 | *.mode1v3
16 | !default.mode1v3
17 | *.mode2v3
18 | !default.mode2v3
19 | *.perspectivev3
20 | !default.perspectivev3
21 | xcuserdata/
22 |
23 | ## Other
24 | *.moved-aside
25 | *.xccheckout
26 | *.xcscmblueprint
27 |
28 | # Swift Package Manager
29 | #
30 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
31 | Packages/
32 | .build/
33 |
34 | ## Obj-C/Swift specific
35 | *.hmap
36 | *.ipa
37 |
38 | ## Playgrounds
39 | timeline.xctimeline
40 | playground.xcworkspace
41 |
--------------------------------------------------------------------------------
/Assets/CollectionMulti-Message.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/Assets/CollectionMulti-Message.png
--------------------------------------------------------------------------------
/Assets/CollectionSingle-Message.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/Assets/CollectionSingle-Message.png
--------------------------------------------------------------------------------
/Assets/ContentNode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/Assets/ContentNode.png
--------------------------------------------------------------------------------
/Assets/Custom-Message.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/Assets/Custom-Message.png
--------------------------------------------------------------------------------
/Assets/DefaultBubble.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/Assets/DefaultBubble.png
--------------------------------------------------------------------------------
/Assets/Image-Message.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/Assets/Image-Message.png
--------------------------------------------------------------------------------
/Assets/ImageBubble.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/Assets/ImageBubble.png
--------------------------------------------------------------------------------
/Assets/MessageGroup.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/Assets/MessageGroup.png
--------------------------------------------------------------------------------
/Assets/Mg-Add.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/Assets/Mg-Add.gif
--------------------------------------------------------------------------------
/Assets/Mg-Delete.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/Assets/Mg-Delete.gif
--------------------------------------------------------------------------------
/Assets/Mg-Replace.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/Assets/Mg-Replace.gif
--------------------------------------------------------------------------------
/Assets/NMessenger-Overview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/Assets/NMessenger-Overview.png
--------------------------------------------------------------------------------
/Assets/SimpleBubble.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/Assets/SimpleBubble.png
--------------------------------------------------------------------------------
/Assets/StackedBubble.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/Assets/StackedBubble.png
--------------------------------------------------------------------------------
/Assets/Text-Message.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/Assets/Text-Message.png
--------------------------------------------------------------------------------
/Assets/TypingIndicator.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/Assets/TypingIndicator.png
--------------------------------------------------------------------------------
/Assets/nmessenger.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/Assets/nmessenger.png
--------------------------------------------------------------------------------
/Cartfile:
--------------------------------------------------------------------------------
1 | github "facebook/AsyncDisplayKit" "1.9.92"
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 eBay Software Foundation
4 | Initially written by Aaron Tainter and David Schecter
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 |
--------------------------------------------------------------------------------
/NMessenger.podspec:
--------------------------------------------------------------------------------
1 | #
2 | # Be sure to run `pod spec lint NMessenger.podspec' to ensure this is a
3 | # valid spec and to remove all comments including this before submitting the spec.
4 | #
5 | # To learn more about Podspec attributes see http://docs.cocoapods.org/specification.html
6 | # To see working Podspecs in the CocoaPods repo see https://github.com/CocoaPods/Specs/
7 | #
8 |
9 | Pod::Spec.new do |s|
10 |
11 | # ――― Spec Metadata ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
12 | #
13 | # These will help people to find your library, and whilst it
14 | # can feel like a chore to fill in it's definitely to your advantage. The
15 | # summary should be tweet-length, and the description more in depth.
16 | #
17 |
18 | s.name = "NMessenger"
19 | s.version = "1.0.80"
20 | s.summary = "A fast, lightweight messenger component built on AsyncDisplaykit and written in Swift"
21 |
22 | # This description is used to generate tags and improve search results.
23 | # * Think: What does it do? Why did you write it? What is the focus?
24 | # * Try to keep it short, snappy and to the point.
25 | # * Write the description between the DESC delimiters below.
26 | # * Finally, don't worry about the indent, CocoaPods strips it!
27 | s.description = <<-DESC
28 | NMessenger is a fast, lightweight messenger component built on AsyncDisplaykit and written in Swift. Developers can inherently achieve 60FPS scrolling and smooth transitions with rich content components.
29 | DESC
30 |
31 | s.homepage = "https://github.com/eBay/NMessenger"
32 | # s.screenshots = "www.example.com/screenshots_1.gif", "www.example.com/screenshots_2.gif"
33 |
34 |
35 | # ――― Spec License ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
36 | #
37 | # Licensing your code is important. See http://choosealicense.com for more info.
38 | # CocoaPods will detect a license file if there is a named LICENSE*
39 | # Popular ones are 'MIT', 'BSD' and 'Apache License, Version 2.0'.
40 | #
41 |
42 | s.license = "MIT"
43 | # s.license = { :type => "MIT", :file => "FILE_LICENSE" }
44 |
45 |
46 | # ――― Author Metadata ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
47 | #
48 | # Specify the authors of the library, with email addresses. Email addresses
49 | # of the authors are extracted from the SCM log. E.g. $ git log. CocoaPods also
50 | # accepts just a name if you'd rather not provide an email address.
51 | #
52 | # Specify a social_media_url where others can refer to, for example a twitter
53 | # profile URL.
54 | #
55 |
56 | # s.author = { "eBay" => "email@address.com" }
57 | # Or just: s.author = "eBay"
58 | s.authors = { "Schechter, David" => "david.schechter.mail@gmail.com", "Tainter, Aaron" => "amtainter@gmail.com" }
59 | # s.social_media_url = "http://twitter.com/eBay"
60 |
61 | # ――― Platform Specifics ――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
62 | #
63 | # If this Pod runs only on iOS or OS X, then specify the platform and
64 | # the deployment target. You can optionally include the target after the platform.
65 | #
66 |
67 | # s.platform = :ios
68 | s.platform = :ios, "8.2"
69 |
70 | # When using multiple platforms
71 | # s.ios.deployment_target = "5.0"
72 | # s.osx.deployment_target = "10.7"
73 | # s.watchos.deployment_target = "2.0"
74 | # s.tvos.deployment_target = "9.0"
75 |
76 |
77 | # ――― Source Location ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
78 | #
79 | # Specify the location from where the source should be retrieved.
80 | # Supports git, hg, bzr, svn and HTTP.
81 | #
82 |
83 | s.source = { :git => "https://github.com/eBay/NMessenger.git", :tag => s.version }
84 |
85 |
86 | # ――― Source Code ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
87 | #
88 | # CocoaPods is smart about how it includes source code. For source files
89 | # giving a folder will include any swift, h, m, mm, c & cpp files.
90 | # For header files it will include any header in the folder.
91 | # Not including the public_header_files will make all headers public.
92 | #
93 |
94 | s.source_files = "nMessenger/Source/**/*.swift"
95 | # s.exclude_files = "Classes/Exclude"
96 |
97 | # s.public_header_files = "Classes/**/*.h"
98 |
99 |
100 | # ――― Resources ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
101 | #
102 | # A list of resources included with the Pod. These are copied into the
103 | # target bundle with a build phase script. Anything else will be cleaned.
104 | # You can preserve files from being cleaned, please don't preserve
105 | # non-essential files like tests, examples and documentation.
106 | #
107 |
108 | # s.resource = "icon.png"
109 | s.resources = ['nMessenger/Source/**/*.{png,jpeg,jpg,xib}']
110 |
111 | # s.preserve_paths = "FilesToSave", "MoreFilesToSave"
112 |
113 |
114 | # ――― Project Linking ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
115 | #
116 | # Link your library with frameworks, or libraries. Libraries do not include
117 | # the lib prefix of their name.
118 | #
119 |
120 | # s.framework = "SomeFramework"
121 | # s.frameworks = "SomeFramework", "AnotherFramework"
122 |
123 | # s.library = "iconv"
124 | # s.libraries = "iconv", "xml2"
125 |
126 |
127 | # ――― Project Settings ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
128 | #
129 | # If your library depends on compiler flags you can set them in the xcconfig hash
130 | # where they will only apply to your library. If you depend on other Podspecs
131 | # you can include multiple dependencies to ensure it works.
132 |
133 | s.requires_arc = true
134 |
135 | # s.xcconfig = { "HEADER_SEARCH_PATHS" => "$(SDKROOT)/usr/include/libxml2" }
136 | s.dependency "Texture", "2.3.2"
137 | end
138 |
--------------------------------------------------------------------------------
/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment this line to define a global platform for your project
2 | # platform :ios, '9.0'
3 |
4 | target 'nMessenger' do
5 | # Comment this line if you're not using Swift and don't want to use dynamic frameworks
6 | use_frameworks!
7 |
8 | # Pods for nMessenger
9 | pod 'Texture', '2.3.2'
10 |
11 | target 'nMessengerTests' do
12 | inherit! :search_paths
13 | # Pods for testing
14 | end
15 |
16 | target 'nMessengerUITests' do
17 | inherit! :search_paths
18 | # Pods for testing
19 | end
20 |
21 | target 'nMessenger-iOS' do
22 | inherit! :search_paths
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/examples/MessageGroups/MessageGroups.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/examples/MessageGroups/MessageGroups/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // MessageGroups
4 | //
5 | // Created by Tainter, Aaron on 8/17/16.
6 | // Copyright © 2016 Ebay Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 |
17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
18 | // Override point for customization after application launch.
19 | window = UIWindow(frame: UIScreen.main.bounds)
20 | window?.makeKeyAndVisible()
21 | window?.rootViewController = UINavigationController(rootViewController: EntryViewController())
22 | return true
23 | }
24 |
25 | func applicationWillResignActive(_ application: UIApplication) {
26 | // 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.
27 | // 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.
28 | }
29 |
30 | func applicationDidEnterBackground(_ application: UIApplication) {
31 | // 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.
32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
33 | }
34 |
35 | func applicationWillEnterForeground(_ application: UIApplication) {
36 | // 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.
37 | }
38 |
39 | func applicationDidBecomeActive(_ application: UIApplication) {
40 | // 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.
41 | }
42 |
43 | func applicationWillTerminate(_ application: UIApplication) {
44 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
45 | }
46 |
47 |
48 | }
49 |
50 |
--------------------------------------------------------------------------------
/examples/MessageGroups/MessageGroups/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "29x29",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "29x29",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "40x40",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "40x40",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "60x60",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "60x60",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "ipad",
35 | "size" : "29x29",
36 | "scale" : "1x"
37 | },
38 | {
39 | "idiom" : "ipad",
40 | "size" : "29x29",
41 | "scale" : "2x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "40x40",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "40x40",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "76x76",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "76x76",
61 | "scale" : "2x"
62 | }
63 | ],
64 | "info" : {
65 | "version" : 1,
66 | "author" : "xcode"
67 | }
68 | }
--------------------------------------------------------------------------------
/examples/MessageGroups/MessageGroups/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/examples/MessageGroups/MessageGroups/EntryViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EntryViewController.swift
3 | // MessageGroups
4 | //
5 | // Created by Max Alexander on 11/21/16.
6 | // Copyright © 2016 Ebay Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import LoremIpsum
11 |
12 | class EntryViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
13 |
14 | lazy var tableView : UITableView = {
15 | let tableView = UITableView()
16 | tableView.dataSource = self
17 | tableView.delegate = self
18 | return tableView
19 | }()
20 |
21 | lazy var items : [String] = [
22 | "Empty",
23 | "50 Preloaded Messages",
24 | "200 Preloaded Messages"
25 | ]
26 |
27 | override func viewDidLoad() {
28 | super.viewDidLoad()
29 | view.addSubview(tableView)
30 | tableView.frame = view.bounds
31 | title = "Welcome to NMessenger"
32 | }
33 |
34 | override func didReceiveMemoryWarning() {
35 | super.didReceiveMemoryWarning()
36 | // Dispose of any resources that can be recreated.
37 | }
38 |
39 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
40 | return items.count
41 | }
42 |
43 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
44 | let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") ?? UITableViewCell()
45 | let item = items[indexPath.row]
46 | cell.textLabel?.text = item
47 | return cell
48 | }
49 |
50 | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
51 | tableView.deselectRow(at: indexPath, animated: true)
52 | let exampleViewController = ExampleMessengerViewController()
53 | if indexPath.row == 1 {
54 | exampleViewController.bootstrapWithRandomMessages = 50
55 | }
56 | if indexPath.row == 2 {
57 | exampleViewController.bootstrapWithRandomMessages = 200
58 | }
59 | navigationController?.pushViewController(exampleViewController, animated: true)
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/examples/MessageGroups/MessageGroups/ExampleMessengerViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2016 eBay Software Foundation
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 | //
6 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 | //
8 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 | //
10 |
11 | import UIKit
12 | import NMessenger
13 | import AsyncDisplayKit
14 |
15 | // not needed in your implementation
16 | import LoremIpsum
17 |
18 | class ExampleMessengerViewController: NMessengerViewController {
19 |
20 | let segmentedControlPadding:CGFloat = 10
21 | let segmentedControlHeight: CGFloat = 30
22 |
23 | lazy var senderSegmentedControl : UISegmentedControl = {
24 | let control = UISegmentedControl(items: ["incoming", "outgoing"])
25 | control.selectedSegmentIndex = 0
26 | return control
27 | }()
28 |
29 | private(set) var lastMessageGroup:MessageGroup? = nil
30 |
31 | //This is not needed in your implementation. This just for a demo purpose.
32 | var bootstrapWithRandomMessages : Int = 0
33 |
34 | override func viewDidLoad() {
35 | super.viewDidLoad()
36 | navigationItem.titleView = senderSegmentedControl
37 |
38 | //BEGIN BOOTSTRAPPING MESSAGES
39 | var messageGroups = [MessageGroup]()
40 | for _ in 0.. GeneralMessengerCell {
72 |
73 | //create a new text message
74 | let textContent = TextContentNode(textMessageString: text, currentViewController: self, bubbleConfiguration: self.sharedBubbleConfiguration)
75 | let newMessage = MessageNode(content: textContent)
76 | newMessage.cellPadding = messagePadding
77 | newMessage.currentViewController = self
78 |
79 | //add message to correct group
80 | if (self.senderSegmentedControl.selectedSegmentIndex == 0) { //incoming
81 | self.postText(newMessage, isIncomingMessage: true)
82 | } else { //outgoing
83 | self.postText(newMessage, isIncomingMessage: false)
84 | }
85 |
86 | return newMessage
87 | }
88 |
89 | //MARK: Helper Functions
90 | /**
91 | Posts a text to the correct message group. Creates a new message group *isIncomingMessage* is different than the last message group.
92 | - parameter message: The message to add
93 | - parameter isIncomingMessage: If the message is incoming or outgoing.
94 | */
95 | private func postText(_ message: MessageNode, isIncomingMessage: Bool) {
96 | if self.lastMessageGroup == nil || self.lastMessageGroup?.isIncomingMessage == !isIncomingMessage {
97 | self.lastMessageGroup = self.createMessageGroup()
98 |
99 | //add avatar if incoming message
100 | if isIncomingMessage {
101 | self.lastMessageGroup?.avatarNode = self.createAvatar()
102 | }
103 |
104 | self.lastMessageGroup!.isIncomingMessage = isIncomingMessage
105 | self.messengerView.addMessageToMessageGroup(message, messageGroup: self.lastMessageGroup!, scrollsToLastMessage: false)
106 | self.messengerView.addMessage(self.lastMessageGroup!, scrollsToMessage: true, withAnimation: isIncomingMessage ? .left : .right)
107 |
108 | } else {
109 | self.messengerView.addMessageToMessageGroup(message, messageGroup: self.lastMessageGroup!, scrollsToLastMessage: true)
110 | }
111 | }
112 |
113 | /**
114 | Creates a new message group for *lastMessageGroup*
115 | -returns: MessageGroup
116 | */
117 | private func createMessageGroup()->MessageGroup {
118 | let newMessageGroup = MessageGroup()
119 | newMessageGroup.currentViewController = self
120 | newMessageGroup.cellPadding = self.messagePadding
121 | return newMessageGroup
122 | }
123 |
124 | /**
125 | Creates mock avatar with an AsyncDisplaykit *ASImageNode*.
126 | - returns: ASImageNode
127 | */
128 | private func createAvatar()->ASImageNode {
129 | let avatar = ASImageNode()
130 | avatar.backgroundColor = UIColor.lightGray
131 | avatar.style.preferredSize = CGSize(width: 20, height: 20)
132 | avatar.layer.cornerRadius = 10
133 | return avatar
134 | }
135 |
136 | /**
137 | Just a helper to give a random isIncomingValue
138 | */
139 | func randomBool() -> Bool {
140 | return arc4random_uniform(2) == 0
141 | }
142 |
143 | deinit {
144 | print("Deinitialized")
145 | }
146 | }
147 |
148 |
--------------------------------------------------------------------------------
/examples/MessageGroups/MessageGroups/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | NSCameraUsageDescription
26 | $(PRODUCT_NAME) wants acceess to Camera
27 | NSPhotoLibraryUsageDescription
28 | $(PRODUCT_NAME) wants acceess to Photos
29 | UILaunchStoryboardName
30 | LaunchScreen
31 | UIRequiredDeviceCapabilities
32 |
33 | armv7
34 |
35 | UISupportedInterfaceOrientations
36 |
37 | UIInterfaceOrientationPortrait
38 | UIInterfaceOrientationLandscapeLeft
39 | UIInterfaceOrientationLandscapeRight
40 |
41 | UISupportedInterfaceOrientations~ipad
42 |
43 | UIInterfaceOrientationPortrait
44 | UIInterfaceOrientationPortraitUpsideDown
45 | UIInterfaceOrientationLandscapeLeft
46 | UIInterfaceOrientationLandscapeRight
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/examples/MessageGroups/MessageGroupsTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/examples/MessageGroups/MessageGroupsTests/MessageGroupsTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MessageGroupsTests.swift
3 | // MessageGroupsTests
4 | //
5 | // Created by Tainter, Aaron on 8/17/16.
6 | // Copyright © 2016 Ebay Inc. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import MessageGroups
11 |
12 | class MessageGroupsTests: XCTestCase {
13 |
14 | override func setUp() {
15 | super.setUp()
16 | // Put setup code here. This method is called before the invocation of each test method in the class.
17 | }
18 |
19 | override func tearDown() {
20 | // Put teardown code here. This method is called after the invocation of each test method in the class.
21 | super.tearDown()
22 | }
23 |
24 | func testExample() {
25 | // This is an example of a functional test case.
26 | // Use XCTAssert and related functions to verify your tests produce the correct results.
27 | }
28 |
29 | func testPerformanceExample() {
30 | // This is an example of a performance test case.
31 | self.measure {
32 | // Put the code you want to measure the time of here.
33 | }
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/examples/MessageGroups/MessageGroupsUITests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/examples/MessageGroups/MessageGroupsUITests/MessageGroupsUITests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MessageGroupsUITests.swift
3 | // MessageGroupsUITests
4 | //
5 | // Created by Tainter, Aaron on 8/17/16.
6 | // Copyright © 2016 Ebay Inc. All rights reserved.
7 | //
8 |
9 | import XCTest
10 |
11 | class MessageGroupsUITests: XCTestCase {
12 |
13 | override func setUp() {
14 | super.setUp()
15 |
16 | // Put setup code here. This method is called before the invocation of each test method in the class.
17 |
18 | // In UI tests it is usually best to stop immediately when a failure occurs.
19 | continueAfterFailure = false
20 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method.
21 | XCUIApplication().launch()
22 |
23 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
24 | }
25 |
26 | override func tearDown() {
27 | // Put teardown code here. This method is called after the invocation of each test method in the class.
28 | super.tearDown()
29 | }
30 |
31 | func testExample() {
32 | // Use recording to get started writing UI tests.
33 | // Use XCTAssert and related functions to verify your tests produce the correct results.
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/examples/MessageGroups/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment this line to define a global platform for your project
2 | # platform :ios, '9.0'
3 |
4 | target 'MessageGroups' do
5 | # Comment this line if you're not using Swift and don't want to use dynamic frameworks
6 | use_frameworks!
7 |
8 | swift_version = '3.0'
9 |
10 | # Pods for MessageGroups
11 | pod 'NMessenger', :path => '../..'
12 | pod 'LoremIpsum', '= 1.0.0'
13 |
14 | target 'MessageGroupsTests' do
15 | inherit! :search_paths
16 | # Pods for testing
17 | end
18 |
19 | target 'MessageGroupsUITests' do
20 | inherit! :search_paths
21 | # Pods for testing
22 | end
23 |
24 | end
25 |
26 | post_install do |installer|
27 | installer.pods_project.targets.each do |target|
28 | target.build_configurations.each do |config|
29 | config.build_settings['SWIFT_VERSION'] = '3.0'
30 | end
31 | end
32 | end
33 |
--------------------------------------------------------------------------------
/nMessenger-iOS/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(CURRENT_PROJECT_VERSION)
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/nMessenger-iOS/nMessenger-iOS.h:
--------------------------------------------------------------------------------
1 | #import
2 |
3 | //! Project version number for nMessenger-iOS.
4 | FOUNDATION_EXPORT double nMessenger_iOSVersionNumber;
5 |
6 | //! Project version string for nMessenger-iOS.
7 | FOUNDATION_EXPORT const unsigned char nMessenger_iOSVersionString[];
8 |
9 | // In this header, you should import all the public headers of your framework using statements like #import
10 |
11 |
12 |
--------------------------------------------------------------------------------
/nMessenger.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/nMessenger.xcodeproj/xcshareddata/xcschemes/nMessenger-iOS.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
34 |
35 |
45 |
46 |
52 |
53 |
54 |
55 |
56 |
57 |
63 |
64 |
70 |
71 |
72 |
73 |
75 |
76 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/nMessenger/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2016 eBay Software Foundation
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 | //
6 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 | //
8 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 | //
10 |
11 | import UIKit
12 |
13 | @UIApplicationMain
14 | class AppDelegate: UIResponder, UIApplicationDelegate {
15 |
16 | var window: UIWindow?
17 |
18 |
19 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
20 | // Override point for customization after application launch.
21 | return true
22 | }
23 |
24 | func applicationWillResignActive(_ application: UIApplication) {
25 | // 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.
26 | // 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.
27 | }
28 |
29 | func applicationDidEnterBackground(_ application: UIApplication) {
30 | // 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.
31 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
32 | }
33 |
34 | func applicationWillEnterForeground(_ application: UIApplication) {
35 | // 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.
36 | }
37 |
38 | func applicationDidBecomeActive(_ application: UIApplication) {
39 | // 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.
40 | }
41 |
42 | func applicationWillTerminate(_ application: UIApplication) {
43 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
44 | }
45 |
46 |
47 | }
48 |
49 |
--------------------------------------------------------------------------------
/nMessenger/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | }
88 | ],
89 | "info" : {
90 | "version" : 1,
91 | "author" : "xcode"
92 | }
93 | }
--------------------------------------------------------------------------------
/nMessenger/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/nMessenger/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/nMessenger/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/nMessenger/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UIRequiredDeviceCapabilities
30 |
31 | armv7
32 |
33 | UISupportedInterfaceOrientations
34 |
35 | UIInterfaceOrientationPortrait
36 | UIInterfaceOrientationLandscapeLeft
37 | UIInterfaceOrientationLandscapeRight
38 |
39 | UISupportedInterfaceOrientations~ipad
40 |
41 | UIInterfaceOrientationPortrait
42 | UIInterfaceOrientationPortraitUpsideDown
43 | UIInterfaceOrientationLandscapeLeft
44 | UIInterfaceOrientationLandscapeRight
45 |
46 | NSPhotoLibraryUsageDescription
47 | $(PRODUCT_NAME) wants acceess to Photos
48 | NSCameraUsageDescription
49 | $(PRODUCT_NAME) wants acceess to Camera
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble@1x.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble@1x.gif
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble@2x.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble@2x.gif
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble@3x.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble@3x.gif
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0000_Layer-39@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0000_Layer-39@1x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0001_Layer-38@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0001_Layer-38@1x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0002_Layer-37@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0002_Layer-37@1x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0003_Layer-36@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0003_Layer-36@1x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0004_Layer-35@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0004_Layer-35@1x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0005_Layer-34@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0005_Layer-34@1x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0006_Layer-33@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0006_Layer-33@1x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0007_Layer-32@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0007_Layer-32@1x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0008_Layer-31@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0008_Layer-31@1x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0009_Layer-30@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0009_Layer-30@1x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0010_Layer-29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0010_Layer-29@1x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0011_Layer-28@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0011_Layer-28@1x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0012_Layer-27@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0012_Layer-27@1x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0013_Layer-26@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0013_Layer-26@1x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0014_Layer-25@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0014_Layer-25@1x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0015_Layer-24@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0015_Layer-24@1x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0016_Layer-23@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0016_Layer-23@1x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0017_Layer-22@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0017_Layer-22@1x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0018_Layer-21@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0018_Layer-21@1x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0019_Layer-20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0019_Layer-20@1x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0020_Layer-19@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0020_Layer-19@1x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0021_Layer-18@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0021_Layer-18@1x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0022_Layer-17@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0022_Layer-17@1x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0023_Layer-16@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0023_Layer-16@1x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0024_Layer-15@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0024_Layer-15@1x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0025_Layer-14@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0025_Layer-14@1x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0026_Layer-13@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0026_Layer-13@1x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0027_Layer-12@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0027_Layer-12@1x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0028_Layer-11@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0028_Layer-11@1x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0029_Layer-10@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0029_Layer-10@1x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0030_Layer-9@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0030_Layer-9@1x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0031_Layer-8@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0031_Layer-8@1x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0032_Layer-7@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0032_Layer-7@1x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0033_Layer-6@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0033_Layer-6@1x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0034_Layer-5@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0034_Layer-5@1x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0035_Layer-4@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0035_Layer-4@1x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0036_Layer-3@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0036_Layer-3@1x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0037_Layer-2@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0037_Layer-2@1x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0038_Layer-1@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_1x/loadBubble_0038_Layer-1@1x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0000_Layer-39@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0000_Layer-39@2x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0001_Layer-38@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0001_Layer-38@2x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0002_Layer-37@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0002_Layer-37@2x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0003_Layer-36@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0003_Layer-36@2x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0004_Layer-35@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0004_Layer-35@2x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0005_Layer-34@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0005_Layer-34@2x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0006_Layer-33@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0006_Layer-33@2x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0007_Layer-32@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0007_Layer-32@2x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0008_Layer-31@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0008_Layer-31@2x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0009_Layer-30@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0009_Layer-30@2x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0010_Layer-29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0010_Layer-29@2x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0011_Layer-28@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0011_Layer-28@2x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0012_Layer-27@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0012_Layer-27@2x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0013_Layer-26@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0013_Layer-26@2x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0014_Layer-25@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0014_Layer-25@2x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0015_Layer-24@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0015_Layer-24@2x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0016_Layer-23@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0016_Layer-23@2x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0017_Layer-22@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0017_Layer-22@2x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0018_Layer-21@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0018_Layer-21@2x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0019_Layer-20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0019_Layer-20@2x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0020_Layer-19@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0020_Layer-19@2x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0021_Layer-18@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0021_Layer-18@2x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0022_Layer-17@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0022_Layer-17@2x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0023_Layer-16@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0023_Layer-16@2x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0024_Layer-15@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0024_Layer-15@2x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0025_Layer-14@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0025_Layer-14@2x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0026_Layer-13@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0026_Layer-13@2x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0027_Layer-12@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0027_Layer-12@2x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0028_Layer-11@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0028_Layer-11@2x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0029_Layer-10@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0029_Layer-10@2x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0030_Layer-9@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0030_Layer-9@2x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0031_Layer-8@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0031_Layer-8@2x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0032_Layer-7@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0032_Layer-7@2x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0033_Layer-6@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0033_Layer-6@2x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0034_Layer-5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0034_Layer-5@2x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0035_Layer-4@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0035_Layer-4@2x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0036_Layer-3@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0036_Layer-3@2x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0037_Layer-2@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0037_Layer-2@2x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0038_Layer-1@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_2x/loadBubble_0038_Layer-1@2x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0000_Layer-39@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0000_Layer-39@3x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0001_Layer-38@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0001_Layer-38@3x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0002_Layer-37@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0002_Layer-37@3x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0003_Layer-36@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0003_Layer-36@3x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0004_Layer-35@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0004_Layer-35@3x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0005_Layer-34@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0005_Layer-34@3x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0006_Layer-33@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0006_Layer-33@3x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0007_Layer-32@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0007_Layer-32@3x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0008_Layer-31@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0008_Layer-31@3x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0009_Layer-30@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0009_Layer-30@3x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0010_Layer-29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0010_Layer-29@3x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0011_Layer-28@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0011_Layer-28@3x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0012_Layer-27@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0012_Layer-27@3x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0013_Layer-26@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0013_Layer-26@3x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0014_Layer-25@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0014_Layer-25@3x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0015_Layer-24@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0015_Layer-24@3x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0016_Layer-23@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0016_Layer-23@3x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0017_Layer-22@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0017_Layer-22@3x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0018_Layer-21@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0018_Layer-21@3x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0019_Layer-20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0019_Layer-20@3x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0020_Layer-19@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0020_Layer-19@3x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0021_Layer-18@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0021_Layer-18@3x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0022_Layer-17@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0022_Layer-17@3x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0023_Layer-16@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0023_Layer-16@3x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0024_Layer-15@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0024_Layer-15@3x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0025_Layer-14@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0025_Layer-14@3x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0026_Layer-13@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0026_Layer-13@3x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0027_Layer-12@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0027_Layer-12@3x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0028_Layer-11@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0028_Layer-11@3x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0029_Layer-10@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0029_Layer-10@3x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0030_Layer-9@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0030_Layer-9@3x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0031_Layer-8@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0031_Layer-8@3x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0032_Layer-7@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0032_Layer-7@3x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0033_Layer-6@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0033_Layer-6@3x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0034_Layer-5@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0034_Layer-5@3x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0035_Layer-4@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0035_Layer-4@3x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0036_Layer-3@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0036_Layer-3@3x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0037_Layer-2@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0037_Layer-2@3x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0038_Layer-1@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Animated/loadBubble-iOS/loadBubble_3x/loadBubble_0038_Layer-1@3x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Images/MessageBubble.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Images/MessageBubble.png
--------------------------------------------------------------------------------
/nMessenger/Source/Images/cameraRollIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Images/cameraRollIcon.png
--------------------------------------------------------------------------------
/nMessenger/Source/Images/cameraRollIcon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Images/cameraRollIcon@2x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Images/cameraRollIcon@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Images/cameraRollIcon@3x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Images/exitIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Images/exitIcon.png
--------------------------------------------------------------------------------
/nMessenger/Source/Images/flashIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Images/flashIcon.png
--------------------------------------------------------------------------------
/nMessenger/Source/Images/flashIcon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Images/flashIcon@2x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Images/flashIcon@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Images/flashIcon@3x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Images/flipCameraIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Images/flipCameraIcon.png
--------------------------------------------------------------------------------
/nMessenger/Source/Images/shutterBtn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Images/shutterBtn.png
--------------------------------------------------------------------------------
/nMessenger/Source/Images/shutterBtn@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Images/shutterBtn@2x.png
--------------------------------------------------------------------------------
/nMessenger/Source/Images/shutterBtn@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBay/NMessenger/a6e9547554fbf9b66c3f67eff6c550bee0529ea1/nMessenger/Source/Images/shutterBtn@3x.png
--------------------------------------------------------------------------------
/nMessenger/Source/MessageNodes/BubbleConfiguration/BubbleConfigurationProtocol.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2016 eBay Software Foundation
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 | //
6 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 | //
8 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 | //
10 |
11 | import Foundation
12 | import UIKit
13 |
14 | /** Configures a bubble for a ContentNode. Implement this to create your own bubble configuration */
15 | public protocol BubbleConfigurationProtocol {
16 | var isMasked: Bool {get set}
17 |
18 | /** Create and return a UI color representing an incoming message */
19 | func getIncomingColor() -> UIColor
20 |
21 | /** Create and return a UI color representing an outgoing message */
22 | func getOutgoingColor() -> UIColor
23 |
24 | /** Create and return a bubble for the ContentNode */
25 | func getBubble() -> Bubble
26 |
27 | /** Create and return a bubble that is used by the Message group for Message nodes after the first. This is typically used to "stack" messages */
28 | func getSecondaryBubble() -> Bubble
29 | }
30 |
--------------------------------------------------------------------------------
/nMessenger/Source/MessageNodes/BubbleConfiguration/ImageBubbleConfiguration.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2016 eBay Software Foundation
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 | //
6 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 | //
8 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 | //
10 |
11 | import Foundation
12 | import UIKit
13 |
14 | /** Uses a simple bubble as primary and a simple bubble as secondary. Incoming color is pale grey and outgoing is mid grey */
15 | open class ImageBubbleConfiguration: BubbleConfigurationProtocol {
16 |
17 | open var isMasked = false
18 |
19 | public init() {}
20 |
21 | open func getIncomingColor() -> UIColor
22 | {
23 | return UIColor.n1PaleGreyColor()
24 | }
25 |
26 | open func getOutgoingColor() -> UIColor
27 | {
28 | return UIColor.n1ActionBlueColor()
29 | }
30 |
31 | open func getBubble() -> Bubble
32 | {
33 | let newBubble = ImageBubble()
34 | newBubble.bubbleImage = UIImage(named: "MessageBubble", in: Bundle(for: NMessengerViewController.self), compatibleWith: nil)
35 | newBubble.cutInsets = UIEdgeInsetsMake(29, 32, 25, 43)
36 | newBubble.hasLayerMask = isMasked
37 | return newBubble
38 | }
39 |
40 | open func getSecondaryBubble() -> Bubble
41 | {
42 | let newBubble = ImageBubble()
43 | newBubble.bubbleImage = UIImage(named: "MessageBubble", in: Bundle(for: NMessengerViewController.self), compatibleWith: nil)
44 | newBubble.cutInsets = UIEdgeInsetsMake(29, 32, 25, 43)
45 | newBubble.hasLayerMask = isMasked
46 | return newBubble
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/nMessenger/Source/MessageNodes/BubbleConfiguration/SimpleBubbleConfiguration.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2016 eBay Software Foundation
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 | //
6 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 | //
8 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 | //
10 |
11 | import Foundation
12 | import UIKit
13 |
14 | /** Uses a simple bubble as primary and a simple bubble as secondary. Incoming color is pale grey and outgoing is mid grey */
15 | open class SimpleBubbleConfiguration: BubbleConfigurationProtocol {
16 |
17 | open var isMasked = false
18 |
19 | public init() {}
20 |
21 | open func getIncomingColor() -> UIColor
22 | {
23 | return UIColor.n1PaleGreyColor()
24 | }
25 |
26 | open func getOutgoingColor() -> UIColor
27 | {
28 | return UIColor.n1MidGreyColor()
29 | }
30 |
31 | open func getBubble() -> Bubble
32 | {
33 | let newBubble = SimpleBubble()
34 | newBubble.hasLayerMask = isMasked
35 | return newBubble
36 | }
37 |
38 | open func getSecondaryBubble() -> Bubble
39 | {
40 | let newBubble = SimpleBubble()
41 | newBubble.hasLayerMask = isMasked
42 | return newBubble
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/nMessenger/Source/MessageNodes/BubbleConfiguration/StandardBubbleConfiguration.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2016 eBay Software Foundation
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 | //
6 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 | //
8 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 | //
10 |
11 | import Foundation
12 | import UIKit
13 |
14 | /** Uses a default bubble as primary and a stacked bubble as secondary. Incoming color is pale grey and outgoing is blue */
15 | open class StandardBubbleConfiguration: BubbleConfigurationProtocol {
16 |
17 | open var isMasked = false
18 |
19 | public init() {}
20 |
21 | open func getIncomingColor() -> UIColor
22 | {
23 | return UIColor.n1PaleGreyColor()
24 | }
25 |
26 | open func getOutgoingColor() -> UIColor
27 | {
28 | return UIColor.n1ActionBlueColor()
29 | }
30 |
31 | open func getBubble() -> Bubble
32 | {
33 | let newBubble = DefaultBubble()
34 | newBubble.hasLayerMask = isMasked
35 | return newBubble
36 | }
37 |
38 | open func getSecondaryBubble() -> Bubble
39 | {
40 | let newBubble = StackedBubble()
41 | newBubble.hasLayerMask = isMasked
42 | return newBubble
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/nMessenger/Source/MessageNodes/Bubbles/Bubble.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2016 eBay Software Foundation
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 | //
6 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 | //
8 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 | //
10 |
11 | import Foundation
12 | import UIKit
13 | import AsyncDisplayKit
14 |
15 | //MARK: Bubble class
16 | /**
17 | 'Abstract' Bubble class. Subclass for creating a custom bubble
18 | */
19 | open class Bubble {
20 |
21 | // MARK: Public Parameters
22 | open var bubbleColor : UIColor = UIColor.n1PaleGreyColor()
23 |
24 | /** When this is set, the layer mask will mask the ContentNode.*/
25 | open var hasLayerMask = false
26 |
27 | /**
28 | A layer for the bubble. Make sure this property is first accessed on the main thread.
29 | */
30 | open lazy var layer: CAShapeLayer = CAShapeLayer()
31 | /**
32 | A layer that holds a mask which is the same shape as the bubble. This can be used to mask anything in the ContentNode to the same shape as the bubble.
33 | */
34 | open lazy var maskLayer: CAShapeLayer = CAShapeLayer()
35 |
36 | /** Bounds of the bubble*/
37 | open var calculatedBounds = CGRect.zero
38 |
39 | // MARK: Initialisers
40 | public init() {}
41 |
42 | // MARK: Class methods
43 | /**
44 | Sizes the layer accordingly. This function should **always** be thread safe.
45 | -parameter bounds: The bounds of the content
46 | */
47 | open func sizeToBounds(_ bounds: CGRect) {
48 | self.calculatedBounds = bounds
49 | }
50 |
51 |
52 | /**
53 | This function should be called on the main thread. It makes creates the layer with the calculated values from *sizeToBounds*
54 | */
55 | open func createLayer() {
56 | self.layer.shouldRasterize = true
57 | self.layer.rasterizationScale = UIScreen.main.scale
58 |
59 | self.maskLayer.shouldRasterize = true
60 | self.maskLayer.rasterizationScale = UIScreen.main.scale
61 | }
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/nMessenger/Source/MessageNodes/Bubbles/DefaultBubble.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2016 eBay Software Foundation
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 | //
6 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 | //
8 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 | //
10 |
11 | import Foundation
12 | import UIKit
13 |
14 | //MARK: DefaultBubble class
15 | /**
16 | Default bubble class is standard with our message configuration. It has three rounded corners and one square corner closest to the avatar.
17 | */
18 | open class DefaultBubble: Bubble {
19 |
20 | //MARK: Public Variables
21 |
22 | /** Radius of the corners for the bubble. When this is set, you will need to call setNeedsLayout on your message for changes to take effect if the bubble has already been drawn*/
23 | open var radius : CGFloat = 16
24 | /** Should be less or equal to the *radius* property. When this is set, you will need to call setNeedsLayout on your message for changes to take effect if the bubble has already been drawn*/
25 | open var borderWidth : CGFloat = 0 //TODO:
26 | /** The color of the border around the bubble. When this is set, you will need to call setNeedsLayout on your message for changes to take effect if the bubble has already been drawn*/
27 | open var bubbleBorderColor : UIColor = UIColor.clear
28 | /** Path used to cutout the bubble*/
29 | open fileprivate(set) var path: CGMutablePath = CGMutablePath()
30 |
31 | // MARK: Initialisers
32 |
33 | /**
34 | Initialiser class.
35 | */
36 | public override init() {
37 | super.init()
38 | }
39 |
40 | // MARK: Class methods
41 |
42 | /**
43 | Overriding sizeToBounds from super class
44 | -parameter bounds: The bounds of the content
45 | */
46 | open override func sizeToBounds(_ bounds: CGRect) {
47 | super.sizeToBounds(bounds)
48 |
49 | var rect = CGRect.zero
50 | var radius2: CGFloat = 0
51 |
52 | if bounds.width < 2*radius || bounds.height < 2*radius { //if the rect calculation yeilds a negative result
53 | let newRadiusW = bounds.width/2
54 | let newRadiusH = bounds.height/2
55 |
56 | let newRadius = newRadiusW>newRadiusH ? newRadiusH : newRadiusW
57 |
58 | rect = CGRect(x: newRadius, y: newRadius, width: bounds.width - 2*newRadius, height: bounds.height - 2*newRadius)
59 | radius2 = newRadius - borderWidth / 2
60 | } else {
61 | rect = CGRect(x: radius, y: radius, width: bounds.width - 2*radius, height: bounds.height - 2*radius)
62 | radius2 = radius - borderWidth / 2
63 | }
64 |
65 | path = CGMutablePath()
66 |
67 | path.addArc(center: CGPoint(x: rect.maxX, y: rect.minY), radius: radius2, startAngle: CGFloat(-Double.pi/2), endAngle: 0, clockwise: false)
68 | path.addLine(to: CGPoint(x: rect.maxX + radius2, y: rect.maxY + radius2))
69 | path.addArc(center: CGPoint(x: rect.minX, y: rect.maxY), radius: radius2, startAngle: CGFloat(Double.pi/2), endAngle: CGFloat(Double.pi), clockwise: false)
70 | path.addArc(center: CGPoint(x: rect.minX, y: rect.minY), radius: radius2, startAngle: CGFloat(Double.pi), endAngle: CGFloat(-Double.pi/2), clockwise: false)
71 |
72 | //CGPathAddArc(path, nil, rect.maxX, rect.minY, radius2, CGFloat(-M_PI_2), 0, false)
73 | //CGPathAddLineToPoint(path, nil, rect.maxX + radius2, rect.maxY + radius2)
74 | //CGPathAddArc(path, nil, rect.minX, rect.maxY, radius2, CGFloat(M_PI_2), CGFloat(M_PI), false)
75 | //CGPathAddArc(path, nil, rect.minX, rect.minY, radius2, CGFloat(M_PI), CGFloat(-M_PI_2), false)
76 | path.closeSubpath()
77 | }
78 |
79 | /**
80 | Overriding createLayer from super class
81 | */
82 | open override func createLayer() {
83 | super.createLayer()
84 |
85 | CATransaction.begin()
86 | CATransaction.setDisableActions(true)
87 | self.layer.path = path
88 | self.layer.fillColor = self.bubbleColor.cgColor
89 | self.layer.strokeColor = self.bubbleBorderColor.cgColor
90 | self.layer.lineWidth = self.borderWidth
91 | self.layer.position = CGPoint.zero
92 |
93 | self.maskLayer.fillColor = UIColor.black.cgColor
94 | self.maskLayer.path = path
95 | self.maskLayer.position = CGPoint.zero
96 | CATransaction.commit()
97 |
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/nMessenger/Source/MessageNodes/Bubbles/ImageBubble.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2016 eBay Software Foundation
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 | //
6 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 | //
8 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 | //
10 |
11 | import Foundation
12 | import UIKit
13 |
14 | //MARK: ImageBubble class
15 | /**
16 | Image as background for messages in NMessenger
17 | Uses 9-Patch logic to resize image to appropriate size.
18 | */
19 | open class ImageBubble : Bubble {
20 |
21 | // MARK: Public variables
22 | /** Image 9-Patch used for bubble. When this is set, you will need to call setNeedsLayout on your message for changes to take effect if the bubble has already been drawn*/
23 | open var bubbleImage: UIImage?
24 | /** Image 9-Patch cut insets. When this is set, you will need to call setNeedsLayout on your message for changes to take effect if the bubble has already been drawn*/
25 | open var cutInsets: UIEdgeInsets = UIEdgeInsetsMake(0, 0, 0, 0)
26 |
27 | // MARK: Initialisers
28 |
29 | /**
30 | Initialiser class.
31 | Sets hasLayerMask to true
32 | */
33 | public override init() {
34 | super.init()
35 | self.hasLayerMask = true
36 | }
37 |
38 | // MARK: Class methods
39 |
40 | /**
41 | Overriding sizeToBounds from super class
42 | -parameter bounds: The bounds of the content
43 | */
44 | open override func sizeToBounds(_ bounds: CGRect) {
45 | super.sizeToBounds(bounds)
46 |
47 | }
48 |
49 | /**
50 | Overriding createLayer from super class
51 | */
52 | open override func createLayer() {
53 | super.createLayer()
54 |
55 | if let image = bubbleImage {
56 | UIGraphicsBeginImageContextWithOptions(image.size, false, image.scale);
57 | let context = UIGraphicsGetCurrentContext();
58 | self.bubbleColor.setFill()
59 | context?.translateBy(x: 0, y: image.size.height);
60 | context?.scaleBy(x: 1.0, y: -1.0);
61 | context?.clip(to: CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height), mask: image.cgImage!);
62 | context?.fill(CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height));
63 |
64 | var coloredImg = UIGraphicsGetImageFromCurrentImageContext();
65 |
66 | UIGraphicsEndImageContext();
67 |
68 |
69 | let insets = self.cutInsets
70 | coloredImg = coloredImg?.resizableImage(withCapInsets: insets, resizingMode: .stretch)
71 |
72 | self.layer.contents = coloredImg?.cgImage
73 | self.layer.position = CGPoint.zero
74 | self.layer.frame = CGRect(x: 0, y: 0, width: self.calculatedBounds.width, height: self.calculatedBounds.height)
75 | self.layer.contentsCenter = CGRect(x: insets.left/(coloredImg?.size.width)!,
76 | y: insets.top/(coloredImg?.size.height)!,
77 | width: 1.0/(coloredImg?.size.width)!,
78 | height: 1.0/(coloredImg?.size.height)!);
79 |
80 | self.maskLayer.contents = coloredImg?.cgImage
81 | self.maskLayer.position = CGPoint.zero
82 | self.maskLayer.frame = CGRect(x: 0, y: 0, width: self.calculatedBounds.width, height: self.calculatedBounds.height)
83 | self.maskLayer.contentsCenter = CGRect(x: insets.left/(coloredImg?.size.width)!,
84 | y: insets.top/(coloredImg?.size.height)!,
85 | width: 1.0/(coloredImg?.size.width)!,
86 | height: 1.0/(coloredImg?.size.height)!);
87 | }
88 | }
89 |
90 |
91 | }
92 |
--------------------------------------------------------------------------------
/nMessenger/Source/MessageNodes/Bubbles/SimpleBubble.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2016 eBay Software Foundation
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 | //
6 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 | //
8 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 | //
10 |
11 | import Foundation
12 | import UIKit
13 |
14 | //MARK: SimpleBubble class
15 | /**
16 | Simple bubble with no layer effects which is the bounds of the content it holds
17 | */
18 | open class SimpleBubble: Bubble {
19 |
20 | //MARK: Public Variables
21 | /** The color of the border around the bubble. When this is set, you will need to call setNeedsLayout on your message for changes to take effect if the bubble has already been drawn*/
22 | open var bubbleBorderColor : UIColor = UIColor.clear
23 | /** Path used to cutout the bubble*/
24 | open fileprivate(set) var path: CGMutablePath = CGMutablePath()
25 |
26 | public override init() {
27 | super.init()
28 | }
29 |
30 | // MARK: Class methods
31 |
32 | /**
33 | Overriding sizeToBounds from super class
34 | -parameter bounds: The bounds of the content
35 | */
36 | open override func sizeToBounds(_ bounds: CGRect) {
37 | super.sizeToBounds(bounds)
38 |
39 | let rect = CGRect(x: 0, y: 0, width: bounds.width, height: bounds.height)
40 |
41 | path = CGMutablePath()
42 |
43 | path.move(to: CGPoint(x: rect.minX, y: rect.minY))
44 | path.addLine(to: CGPoint(x: rect.maxX, y: rect.minY))
45 | path.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY))
46 | path.addLine(to: CGPoint(x: rect.minX, y: rect.maxY))
47 |
48 | // CGPathMoveToPoint(path, nil, rect.minX, rect.minY)
49 | // CGPathAddLineToPoint(path, nil, rect.maxX, rect.minY)
50 | // CGPathAddLineToPoint(path, nil, rect.maxX, rect.maxY)
51 | // CGPathAddLineToPoint(path, nil, rect.minX, rect.maxY)
52 |
53 | path.closeSubpath()
54 | }
55 |
56 | /**
57 | Overriding createLayer from super class
58 | */
59 | open override func createLayer() {
60 | super.createLayer()
61 |
62 | CATransaction.begin()
63 | CATransaction.setDisableActions(true)
64 | self.layer.path = path
65 | self.layer.fillColor = self.bubbleColor.cgColor
66 | self.layer.strokeColor = self.bubbleBorderColor.cgColor
67 | self.layer.position = CGPoint.zero
68 |
69 | self.maskLayer.fillColor = UIColor.black.cgColor
70 | self.maskLayer.path = path
71 | self.maskLayer.position = CGPoint.zero
72 | CATransaction.commit()
73 |
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/nMessenger/Source/MessageNodes/Bubbles/StackedBubble.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2016 eBay Software Foundation
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 | //
6 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 | //
8 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 | //
10 |
11 | import Foundation
12 | import UIKit
13 |
14 | //MARK: StackedBubble class
15 | /**
16 | Bubble when stacked for succeeding messages. The two outmost corners are rounded.
17 | */
18 | open class StackedBubble: Bubble {
19 |
20 | //MARK: Public Variables
21 |
22 | /** Radius of the corners for the bubble. When this is set, you will need to call setNeedsLayout on your message for changes to take effect if the bubble has already been drawn*/
23 | open var radius : CGFloat = 16
24 | /** Should be less or equal to the *radius* property. When this is set, you will need to call setNeedsLayout on your message for changes to take effect if the bubble has already been drawn*/
25 | open var borderWidth : CGFloat = 0
26 | /** The color of the border around the bubble. When this is set, you will need to call setNeedsLayout on your message for changes to take effect if the bubble has already been drawn*/
27 | open var bubbleBorderColor : UIColor = UIColor.clear
28 | /** Path used to cutout the bubble*/
29 | open fileprivate(set) var path: CGMutablePath = CGMutablePath()
30 |
31 | public override init() {
32 | super.init()
33 | }
34 |
35 | // MARK: Class methods
36 |
37 | /**
38 | Overriding sizeToBounds from super class
39 | -parameter bounds: The bounds of the content
40 | */
41 | open override func sizeToBounds(_ bounds: CGRect) {
42 | super.sizeToBounds(bounds)
43 | var rect = CGRect.zero
44 | var radius2: CGFloat = 0
45 |
46 | if bounds.width < 2*radius || bounds.height < 2*radius { //if the rect calculation yeilds a negative result
47 | let newRadiusW = bounds.width/2
48 | let newRadiusH = bounds.height/2
49 |
50 | let newRadius = newRadiusW>newRadiusH ? newRadiusH : newRadiusW
51 |
52 | rect = CGRect(x: newRadius, y: newRadius, width: bounds.width - 2*newRadius, height: bounds.height - 2*newRadius)
53 | radius2 = newRadius - borderWidth / 2
54 | } else {
55 | rect = CGRect(x: radius, y: radius, width: bounds.width - 2*radius, height: bounds.height - 2*radius)
56 | radius2 = radius - borderWidth / 2
57 | }
58 |
59 |
60 | self.path = CGMutablePath();
61 |
62 |
63 | path.move(to: CGPoint(x: rect.minX, y: rect.minY - radius2))
64 | path.addLine(to: CGPoint(x: rect.maxX + radius2, y: rect.minY - radius2))
65 | path.addLine(to: CGPoint(x: rect.maxX + radius2, y: rect.maxY + radius2))
66 | path.addArc(center: CGPoint(x: rect.minX, y: rect.maxY), radius: radius2, startAngle: CGFloat(Double.pi/2), endAngle: CGFloat(Double.pi), clockwise: false)
67 | path.addArc(center: CGPoint(x: rect.minX, y: rect.minY), radius: radius2, startAngle: CGFloat(Double.pi), endAngle: CGFloat(-(Double.pi/2)), clockwise: false)
68 |
69 | //CGPathMoveToPoint(path, nil, rect.minX, rect.minY - radius2)
70 | //CGPathAddLineToPoint(path, nil, rect.maxX + radius2, rect.minY - radius2)
71 | //CGPathAddLineToPoint(path, nil, rect.maxX + radius2, rect.maxY + radius2)
72 | //CGPathAddArc(path, nil, rect.minX, rect.maxY, radius2, CGFloat(M_PI_2), CGFloat(M_PI), false)
73 | //CGPathAddArc(path, nil, rect.minX, rect.minY, radius2, CGFloat(M_PI), CGFloat(-M_PI_2), false)
74 | path.closeSubpath()
75 |
76 | }
77 |
78 | /**
79 | Overriding createLayer from super class
80 | */
81 | open override func createLayer() {
82 | super.createLayer()
83 |
84 | CATransaction.begin()
85 | CATransaction.setDisableActions(true)
86 | self.layer.path = path
87 | self.layer.fillColor = self.bubbleColor.cgColor
88 | self.layer.strokeColor = self.bubbleBorderColor.cgColor
89 | self.layer.lineWidth = self.borderWidth
90 | self.layer.position = CGPoint.zero
91 |
92 | self.maskLayer.fillColor = UIColor.black.cgColor
93 | self.maskLayer.path = path
94 | self.maskLayer.position = CGPoint.zero
95 | CATransaction.commit()
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/nMessenger/Source/MessageNodes/ContentNodes/CollectionViewContent/CustomContentCellNode.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2016 eBay Software Foundation
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 | //
6 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 | //
8 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 | //
10 |
11 | import UIKit
12 | import AsyncDisplayKit
13 |
14 | //MARK: CustomContentCellNode
15 | /**
16 | CustomContentCellNode class for N Messenger.
17 | Define the cell for CollectionViewContentNode
18 | */
19 | open class CustomContentCellNode: ASCellNode {
20 |
21 | // MARK: Public Variables
22 | /** ASDisplayNode as the content of the cell*/
23 | open var customContent:ASDisplayNode = ASDisplayNode()
24 |
25 | // MARK: Initialisers
26 |
27 | /**
28 | Initialiser for the cell.
29 | - parameter withCustomNode: Must be ASDisplayNode. Sets content for the cell.
30 | */
31 | public init(withCustomNode node:ASDisplayNode)
32 | {
33 | super.init()
34 | self.customContent = node
35 | self.addSubnode(self.customContent)
36 | }
37 |
38 | // MARK: Override AsycDisaplyKit Methods
39 |
40 | /**
41 | Overriding layoutSpecThatFits to specifiy relatiohsips between elements in the cell
42 | */
43 | override open func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec {
44 | let customContentSpec = ASAbsoluteLayoutSpec()
45 | customContentSpec.sizing = .sizeToFit
46 | customContentSpec.children = [customContent]
47 | return customContentSpec
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/nMessenger/Source/MessageNodes/ContentNodes/ContentNode.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2016 eBay Software Foundation
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 | //
6 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 | //
8 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 | //
10 |
11 | import Foundation
12 | import AsyncDisplayKit
13 |
14 | //MARK: ContentNode
15 | /**
16 | Content node class for NMessenger.
17 | Define the content a a MessageNode or a MessageGroup
18 | */
19 | open class ContentNode: ASDisplayNode {
20 |
21 | // MARK: Public Parameters
22 | /** Bubble that defines the background for the message*/
23 | open var backgroundBubble: Bubble?
24 | /** UIViewController that holds the cell. Allows the cell the present View Controllers. Generally used for UIMenu or UIAlert Options*/
25 | open weak var currentViewController: UIViewController?
26 | /** MessageConfigurationProtocol hold common definition for all messages. Defaults to **StandardMessageConfiguration***/
27 | open var bubbleConfiguration : BubbleConfigurationProtocol = StandardBubbleConfiguration() {
28 | didSet {
29 | self.updateBubbleConfig(self.bubbleConfiguration)
30 | }
31 | }
32 | /** Bool if the cell is an incoming or out going message.
33 | Set backgroundBubble.bubbleColor when value is changed
34 | */
35 | open var isIncomingMessage = true {
36 | didSet {
37 | self.backgroundBubble?.bubbleColor = isIncomingMessage ? bubbleConfiguration.getIncomingColor() : bubbleConfiguration.getOutgoingColor()
38 |
39 | self.setNeedsLayout()
40 | }
41 | }
42 |
43 | // MARK: Initialisers
44 | /**
45 | Overriding init to initialise the node
46 | */
47 | public init(bubbleConfiguration: BubbleConfigurationProtocol? = nil) {
48 | if let bubbleConfiguration = bubbleConfiguration {
49 | self.bubbleConfiguration = bubbleConfiguration
50 | }
51 | super.init()
52 | //make sure the bubble is set correctly
53 | self.updateBubbleConfig(self.bubbleConfiguration)
54 | }
55 |
56 | //MARK: Node Lifecycle
57 | /**
58 | Overriding didLoad and calling helper method addSublayers
59 | */
60 | override open func didLoad() {
61 | super.didLoad()
62 | self.addSublayers()
63 | }
64 |
65 | //MARK: Node Lifecycle helper methods
66 |
67 | /** Updates the bubble config by setting all necessary properties (background bubble, bubble color, layout)
68 | - parameter newValue: the new BubbleConfigurationProtocol
69 | */
70 | open func updateBubbleConfig(_ newValue: BubbleConfigurationProtocol) {
71 | self.backgroundBubble = self.bubbleConfiguration.getBubble()
72 |
73 | self.backgroundBubble?.bubbleColor = isIncomingMessage ? bubbleConfiguration.getIncomingColor() : bubbleConfiguration.getOutgoingColor()
74 |
75 | self.setNeedsLayout()
76 | }
77 |
78 | /**
79 | Called during the initializer and makes sure layers are added on the main thread
80 | */
81 | open func addSublayers() {
82 | if let backgroundBubble = self.backgroundBubble {
83 | //make sure the layer is at the bottom of the node
84 | backgroundBubble.layer.removeFromSuperlayer()
85 | backgroundBubble.maskLayer.removeFromSuperlayer()
86 |
87 | self.layer.insertSublayer(backgroundBubble.layer, at: 0)
88 |
89 | //If there is a layer mask, add it
90 | if backgroundBubble.hasLayerMask {
91 | self.layer.insertSublayer(backgroundBubble.maskLayer, below: backgroundBubble.layer)
92 | self.layer.mask = backgroundBubble.maskLayer
93 | }
94 | }
95 | }
96 |
97 |
98 | //MARK: Override AsycDisaplyKit Methods
99 |
100 | /**
101 | Draws the content in the bubble. This is called on a background thread.
102 | */
103 | open func drawRect(_ bounds: CGRect, withParameters parameters: NSObjectProtocol!,
104 | isCancelled isCancelledBlock: asdisplaynode_iscancelled_block_t, isRasterizing: Bool) {
105 | self.isOpaque = false
106 | if !isRasterizing {
107 | self.calculateLayerPropertiesThatFit(bounds)
108 |
109 | //call the main queue
110 | DispatchQueue.main.async {
111 | self.layoutLayers()
112 | }
113 | }
114 | }
115 |
116 |
117 | //MARK: Override AsycDisaplyKit helper methods
118 |
119 | /**
120 | Called through the draw rect function. This should be used to create a background layer off the main thread. This layer should be added in layout.
121 | - parameter bounds: Must be CGRect
122 | */
123 | open func calculateLayerPropertiesThatFit(_ bounds: CGRect) {
124 | if let backgroundBubble = self.backgroundBubble {
125 | backgroundBubble.sizeToBounds(bounds)
126 | }
127 | }
128 |
129 | /**
130 | Called on the main thread
131 | */
132 | open func layoutLayers() {
133 | if let backgroundBubble = self.backgroundBubble {
134 | backgroundBubble.createLayer()
135 |
136 | //TODO: this is slightly hacky, will need to rethink
137 | if isIncomingMessage {
138 | CATransaction.begin()
139 | CATransaction.setDisableActions(true)
140 | backgroundBubble.layer.transform = CATransform3DTranslate(CATransform3DMakeScale(-1, 1, 1), -backgroundBubble.calculatedBounds.width, 0, 0)
141 | backgroundBubble.maskLayer.transform = CATransform3DTranslate(CATransform3DMakeScale(-1, 1, 1), -backgroundBubble.calculatedBounds.width, 0, 0)
142 | CATransaction.commit()
143 | }
144 | }
145 | }
146 |
147 | /**
148 | Calls closer after a time delay
149 | - parameter delay: Must be Double.
150 | - parameter closure: Must be an ()->()
151 | */
152 | open func delay(_ delay: Double, closure: @escaping ()->()) {
153 | DispatchQueue.main.asyncAfter(
154 | deadline: DispatchTime.now() + Double(Int64(delay * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC),
155 | execute: closure
156 | )
157 | }
158 |
159 |
160 | //MARK: UITapGestureRecognizer Selector
161 |
162 | /**
163 | Selector to handle long press on message and show custom menu
164 | - parameter recognizer: Must be UITapGestureRecognizer
165 | */
166 | open func messageNodeLongPressSelector(_ recognizer: UITapGestureRecognizer) {
167 | }
168 |
169 | }
170 |
--------------------------------------------------------------------------------
/nMessenger/Source/MessageNodes/ContentNodes/CustomContentContent/CustomContentNode.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2016 eBay Software Foundation
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 | //
6 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 | //
8 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 | //
10 |
11 | import UIKit
12 | import AsyncDisplayKit
13 |
14 | //MARK: CustomContentMessageNode
15 | /**
16 | Custom View Message class for NMessenger. Extends ContentNode.
17 | Defines content that is a custom. Content can be a view or a node.
18 | */
19 | open class CustomContentNode: ContentNode {
20 |
21 | // MARK: Public Variables
22 | /** Insets for the node */
23 | open var insets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0) {
24 | didSet {
25 | setNeedsLayout()
26 | }
27 | }
28 | /**Should the bubble be masked or not*/
29 | open var maskedBubble = true {
30 | didSet {
31 | self.updateBubbleConfig(self.bubbleConfiguration)
32 | self.setNeedsLayout()
33 | }
34 | }
35 |
36 | // MARK: Private Variables
37 | /** ASCollectionNode as the content of the cell*/
38 | open fileprivate(set) var customContentMessageNode:ASDisplayNode = ASDisplayNode()
39 | /** UIView as the posiible view of the cell*/
40 | fileprivate var customView:UIView?
41 | /** ASDisplayNode as the posiible view of the cell*/
42 | fileprivate var customNode:ASDisplayNode?
43 |
44 |
45 | // MARK: Initialisers
46 |
47 | /**
48 | Initialiser for the cell.
49 | - parameter customView: Must be UIView. Sets view for the cell.
50 | Calls helper method to setup cell
51 | */
52 | public init(withCustomView customView: UIView, bubbleConfiguration: BubbleConfigurationProtocol? = nil) {
53 | super.init(bubbleConfiguration: bubbleConfiguration)
54 | self.setupCustomView(customView)
55 | }
56 |
57 | /**
58 | Initialiser for the cell.
59 | - parameter customNode: Must be ASDisplayNode. Sets view for the cell.
60 | Calls helper method to setup cell
61 | */
62 | public init(withCustomNode customNode: ASDisplayNode, bubbleConfiguration: BubbleConfigurationProtocol? = nil) {
63 | super.init(bubbleConfiguration: bubbleConfiguration)
64 | self.setupCustomNode(customNode)
65 | }
66 |
67 | // MARK: Initialiser helper methods
68 | /** Override updateBubbleConfig to set bubble mask */
69 | open override func updateBubbleConfig(_ newValue: BubbleConfigurationProtocol) {
70 | var maskedBubbleConfig = newValue
71 | maskedBubbleConfig.isMasked = self.maskedBubble
72 | super.updateBubbleConfig(maskedBubbleConfig)
73 | }
74 |
75 | /**
76 | Adds subview to the content
77 | - parameter customView: Must be UIView. Sets view for the cell.
78 | */
79 | fileprivate func setupCustomView(_ customView: UIView)
80 | {
81 | self.customView = customView
82 | DispatchQueue.main.async {
83 | self.customContentMessageNode.view.addSubview(customView)
84 | self.customContentMessageNode.style.preferredSize = customView.frame.size
85 | }
86 | self.addSubnode(customContentMessageNode)
87 | }
88 |
89 | /**
90 | Adds subnode to the content
91 | - parameter customNode: Must be ASDisplayNode. Sets view for the cell.
92 | */
93 | fileprivate func setupCustomNode(_ customNode: ASDisplayNode)
94 | {
95 | self.isUserInteractionEnabled = true
96 | self.customNode = customNode
97 | self.customNode?.isUserInteractionEnabled = true
98 | customContentMessageNode = customNode
99 | self.addSubnode(customContentMessageNode)
100 | }
101 |
102 | // MARK: Override AsycDisaplyKit Methods
103 |
104 | /**
105 | Overriding layoutSpecThatFits to specifiy relatiohsips between elements in the cell
106 | */
107 | override open func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec {
108 |
109 | let width = constrainedSize.max.width
110 |
111 | let max = ASLayoutSize(width: ASDimension(unit: .points, value: width), height: ASDimension(unit: .fraction, value: 1))
112 |
113 | customContentMessageNode.style.maxWidth = max.width
114 | customContentMessageNode.style.maxHeight = max.height
115 |
116 | let customContentSpec = ASAbsoluteLayoutSpec()
117 | customContentSpec.sizing = .sizeToFit
118 | customContentSpec.children = [customContentMessageNode]
119 | return ASInsetLayoutSpec(insets: insets, child: customContentSpec)
120 | }
121 |
122 | }
123 |
--------------------------------------------------------------------------------
/nMessenger/Source/MessageNodes/ContentNodes/ImageContent/ImageContentNode.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2016 eBay Software Foundation
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 | //
6 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 | //
8 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 | //
10 |
11 | import UIKit
12 | import AsyncDisplayKit
13 |
14 | //MARK: ImageContentNode
15 | /**
16 | ImageContentNode for NMessenger. Extends ContentNode.
17 | Defines content that is an image.
18 | */
19 | open class ImageContentNode: ContentNode {
20 |
21 | // MARK: Public Variables
22 | /** UIImage as the image of the cell*/
23 | open var image: UIImage? {
24 | get {
25 | return imageMessageNode.image
26 | } set {
27 | imageMessageNode.image = newValue
28 | }
29 | }
30 |
31 | // MARK: Private Variables
32 | /** ASImageNode as the content of the cell*/
33 | open fileprivate(set) var imageMessageNode:ASImageNode = ASImageNode()
34 |
35 | // MARK: Initialisers
36 |
37 | /**
38 | Initialiser for the cell.
39 | - parameter image: Must be UIImage. Sets image for cell.
40 | Calls helper method to setup cell
41 | */
42 | public init(image: UIImage, bubbleConfiguration: BubbleConfigurationProtocol? = nil) {
43 |
44 | super.init(bubbleConfiguration: bubbleConfiguration)
45 | self.setupImageNode(image)
46 | }
47 |
48 | // MARK: Initialiser helper method
49 | /** Override updateBubbleConfig to set bubble mask */
50 | open override func updateBubbleConfig(_ newValue: BubbleConfigurationProtocol) {
51 | var maskedBubbleConfig = newValue
52 | maskedBubbleConfig.isMasked = true
53 | super.updateBubbleConfig(maskedBubbleConfig)
54 | }
55 |
56 | /**
57 | Sets the image to be display in the cell. Clips and rounds the corners.
58 | - parameter image: Must be UIImage. Sets image for cell.
59 | */
60 | fileprivate func setupImageNode(_ image: UIImage)
61 | {
62 | imageMessageNode.image = image
63 | imageMessageNode.clipsToBounds = true
64 | imageMessageNode.contentMode = UIViewContentMode.scaleAspectFill
65 | self.imageMessageNode.accessibilityIdentifier = "imageNode"
66 | self.imageMessageNode.isAccessibilityElement = true
67 | self.addSubnode(imageMessageNode)
68 | }
69 |
70 |
71 | // MARK: Override AsycDisaplyKit Methods
72 |
73 | /**
74 | Overriding layoutSpecThatFits to specifiy relatiohsips between elements in the cell
75 | */
76 | override open func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec {
77 |
78 | let width = constrainedSize.max.width
79 | self.imageMessageNode.style.width = ASDimension(unit: .points, value: width)
80 | self.imageMessageNode.style.height = ASDimension(unit: .points, value: width/4*3)
81 | let absLayout = ASAbsoluteLayoutSpec()
82 | absLayout.sizing = .sizeToFit
83 | absLayout.children = [self.imageMessageNode]
84 | return absLayout
85 | }
86 |
87 | // MARK: UILongPressGestureRecognizer Selector Methods
88 |
89 | /**
90 | Overriding canBecomeFirstResponder to make cell first responder
91 | */
92 | override open func canBecomeFirstResponder() -> Bool {
93 | return true
94 | }
95 |
96 | /**
97 | Override method from superclass
98 | */
99 | open override func messageNodeLongPressSelector(_ recognizer: UITapGestureRecognizer) {
100 | if recognizer.state == UIGestureRecognizerState.began {
101 |
102 | let touchLocation = recognizer.location(in: view)
103 | if self.imageMessageNode.frame.contains(touchLocation) {
104 |
105 | view.becomeFirstResponder()
106 |
107 | delay(0.1, closure: {
108 | let menuController = UIMenuController.shared
109 | menuController.menuItems = [UIMenuItem(title: "Copy", action: #selector(ImageContentNode.copySelector))]
110 | menuController.setTargetRect(self.imageMessageNode.frame, in: self.view)
111 | menuController.setMenuVisible(true, animated:true)
112 | })
113 | }
114 | }
115 | }
116 |
117 | /**
118 | Copy Selector for UIMenuController
119 | Puts the node's image on UIPasteboard
120 | */
121 | open func copySelector() {
122 | if let image = self.image {
123 | UIPasteboard.general.image = image
124 | }
125 | }
126 |
127 | }
128 |
129 |
--------------------------------------------------------------------------------
/nMessenger/Source/MessageNodes/ContentNodes/NetworkImageContent/NetworkImageContentNode.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2016 eBay Software Foundation
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 | //
6 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 | //
8 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 | //
10 |
11 | import UIKit
12 | import AsyncDisplayKit
13 |
14 | //MARK: NetworkImageContentNode
15 | /**
16 | NetworkImageContentNode class for N Messenger. Extends MessageNode.
17 | Defines content that is a network image (An image that is provided via url).
18 | */
19 | open class NetworkImageContentNode: ContentNode,ASNetworkImageNodeDelegate {
20 |
21 | // MARK: Public Variables
22 | /** NSURL for the image*/
23 | open var url: URL? {
24 | get {
25 | return networkImageMessageNode.url
26 | } set {
27 | networkImageMessageNode.url = newValue
28 | }
29 | }
30 |
31 | // MARK: Private Variables
32 | /** ASNetworkImageNode as the content of the cell*/
33 | open fileprivate(set) var networkImageMessageNode:ASNetworkImageNode = ASNetworkImageNode()
34 |
35 |
36 | // MARK: Initialisers
37 | /**
38 | Initialiser for the cell.
39 | - parameter imageURL: Must be String. Sets url for the image in the cell.
40 | Calls helper method to setup cell
41 | */
42 | public init(imageURL: String, bubbleConfiguration: BubbleConfigurationProtocol? = nil) {
43 | super.init(bubbleConfiguration: bubbleConfiguration)
44 | self.setupNetworkImageNode(imageURL)
45 | }
46 |
47 | // MARK: Initialiser helper method
48 | /** Override updateBubbleConfig to set bubble mask */
49 | open override func updateBubbleConfig(_ newValue: BubbleConfigurationProtocol) {
50 | var maskedBubbleConfig = newValue
51 | maskedBubbleConfig.isMasked = true
52 | super.updateBubbleConfig(maskedBubbleConfig)
53 | }
54 |
55 | /**
56 | Sets the URL to be display in the image. Clips and rounds the corners.
57 | - parameter imageURL: Must be String. Sets url for the image in the cell.
58 | */
59 | fileprivate func setupNetworkImageNode(_ imageURL: String)
60 | {
61 | networkImageMessageNode.url = URL(string: imageURL)
62 | networkImageMessageNode.shouldCacheImage = true
63 | networkImageMessageNode.delegate = self
64 | self.addSubnode(networkImageMessageNode)
65 | }
66 |
67 |
68 | // MARK: Override AsycDisaplyKit Methods
69 |
70 | /**
71 | Overriding layoutSpecThatFits to specifiy relatiohsips between elements in the cell
72 | */
73 | override open func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec {
74 |
75 | let width = constrainedSize.max.width
76 | self.networkImageMessageNode.style.width = ASDimension(unit: .points, value: width)
77 | self.networkImageMessageNode.style.height = ASDimension(unit: .points, value: width/4*3)
78 | let absLayoutSpec = ASAbsoluteLayoutSpec()
79 | absLayoutSpec.sizing = .sizeToFit
80 | absLayoutSpec.children = [self.networkImageMessageNode]
81 | return absLayoutSpec
82 | }
83 |
84 | // MARK: ASNetworkImageNodeDelegate
85 | /**
86 | Overriding didLoadImage to layout the node once the image is loaded
87 | */
88 | open func imageNode(_ imageNode: ASNetworkImageNode, didLoad image: UIImage) {
89 | self.setNeedsLayout()
90 | }
91 |
92 | // MARK: UILongPressGestureRecognizer Selector Methods
93 |
94 | /**
95 | Overriding canBecomeFirstResponder to make cell first responder
96 | */
97 | override open func canBecomeFirstResponder() -> Bool {
98 | return true
99 | }
100 |
101 | /**
102 | Override method from superclass
103 | */
104 | open override func messageNodeLongPressSelector(_ recognizer: UITapGestureRecognizer) {
105 | if recognizer.state == UIGestureRecognizerState.began {
106 |
107 | let touchLocation = recognizer.location(in: view)
108 | if self.networkImageMessageNode.frame.contains(touchLocation) {
109 |
110 | view.becomeFirstResponder()
111 |
112 | delay(0.1, closure: {
113 | let menuController = UIMenuController.shared
114 | menuController.menuItems = [UIMenuItem(title: "Copy", action: #selector(NetworkImageContentNode.copySelector))]
115 | menuController.setTargetRect(self.networkImageMessageNode.frame, in: self.view)
116 | menuController.setMenuVisible(true, animated:true)
117 | })
118 | }
119 | }
120 | }
121 |
122 | /**
123 | Copy Selector for UIMenuController
124 | Puts the node's image on UIPasteboard
125 | */
126 | open func copySelector() {
127 | if let image = self.networkImageMessageNode.image {
128 | UIPasteboard.general.image = image
129 | }
130 | }
131 |
132 | }
133 |
134 |
--------------------------------------------------------------------------------
/nMessenger/Source/MessageNodes/ContentNodes/TypingIndicatorContent/TypingIndicatorContent.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2016 eBay Software Foundation
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 | //
6 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 | //
8 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 | //
10 |
11 |
12 | import UIKit
13 | import AsyncDisplayKit
14 |
15 | //MARK: TypingIndicatorContent
16 | /**
17 | TypingIndicatorContent class for NMessenger. Extends MessageNode.
18 | Defines content that is a loading indicator.
19 | */
20 | open class TypingIndicatorContent: ContentNode {
21 |
22 | // MARK: Private Variables
23 | /** gifNode holds the animated typing indicator*/
24 | open fileprivate(set) var gifNode = ASDisplayNode()
25 |
26 | override open func didLoad() {
27 | super.didLoad()
28 | addIndicators()
29 |
30 | }
31 |
32 | open override func visibilityDidChange(_ isVisible: Bool) {
33 | if(isVisible){
34 | self.gifNode.removeFromSupernode();
35 | addIndicators()
36 | }else{
37 | self.gifNode.removeFromSupernode();
38 | }
39 | }
40 |
41 | func addIndicators(){
42 |
43 | let imageNames = ["loadBubble_0038_Layer-1", "loadBubble_0037_Layer-2", "loadBubble_0036_Layer-3", "loadBubble_0035_Layer-4", "loadBubble_0034_Layer-5", "loadBubble_0033_Layer-6", "loadBubble_0032_Layer-7", "loadBubble_0031_Layer-8", "loadBubble_0030_Layer-9", "loadBubble_0029_Layer-10", "loadBubble_0028_Layer-11", "loadBubble_0027_Layer-12", "loadBubble_0026_Layer-13", "loadBubble_0025_Layer-14", "loadBubble_0024_Layer-15", "loadBubble_0023_Layer-16", "loadBubble_0022_Layer-17", "loadBubble_0021_Layer-18", "loadBubble_0020_Layer-19", "loadBubble_0019_Layer-20", "loadBubble_0018_Layer-21", "loadBubble_0017_Layer-22", "loadBubble_0016_Layer-23", "loadBubble_0015_Layer-24", "loadBubble_0014_Layer-25", "loadBubble_0013_Layer-26", "loadBubble_0012_Layer-27", "loadBubble_0011_Layer-28", "loadBubble_0010_Layer-29", "loadBubble_0009_Layer-30", "loadBubble_0008_Layer-31", "loadBubble_0007_Layer-32", "loadBubble_0006_Layer-33", "loadBubble_0005_Layer-34", "loadBubble_0004_Layer-35", "loadBubble_0003_Layer-36", "loadBubble_0002_Layer-37", "loadBubble_0001_Layer-38", "loadBubble_0000_Layer-39"];
44 |
45 | var images = [UIImage]()
46 |
47 | for imageName in imageNames {
48 | if let image = UIImage(named: imageName, in: Bundle(for: NMessengerViewController.self), compatibleWith: nil){
49 | images.append(image)
50 | }
51 | }
52 |
53 | let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: images[0].size.width - 1, height: images[0].size.height - 1))
54 | imageView.backgroundColor = UIColor.orange
55 | imageView.contentMode = UIViewContentMode.center
56 | imageView.clipsToBounds = true
57 | imageView.animationImages = images
58 | imageView.animationDuration = 1
59 | imageView.startAnimating()
60 |
61 | self.gifNode.view.addSubview(imageView)
62 | self.gifNode.style.preferredSize = imageView.frame.size
63 | self.addSubnode(self.gifNode)
64 | self.setNeedsLayout()
65 | }
66 |
67 | // MARK: Override AsycDisaplyKit Methods
68 |
69 | /**
70 | Overriding layoutSpecThatFits to specifiy relatiohsips between elements in the cell
71 | */
72 | override open func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec {
73 | let absLayoutSpec = ASAbsoluteLayoutSpec()
74 | absLayoutSpec.sizing = .sizeToFit
75 | absLayoutSpec.children = [self.gifNode]
76 | return absLayoutSpec
77 | }
78 |
79 | }
80 |
81 |
--------------------------------------------------------------------------------
/nMessenger/Source/MessageNodes/GeneralMessageCell/GeneralMessengerCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2016 eBay Software Foundation
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 | //
6 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 | //
8 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 | //
10 |
11 | import UIKit
12 | import AsyncDisplayKit
13 |
14 | //MARK: GeneralMessengerCell
15 | /**
16 | GeneralMessengerCell class for NMessenger. Extends ASCellNode.
17 | Defines the base class for all messages in NMessenger.
18 | */
19 | open class GeneralMessengerCell: ASCellNode {
20 |
21 | // MARK: Public Variables
22 | /** UIEdgeInsets for cell*/
23 | open var cellPadding: UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, 0.0, 0.0)
24 | /** UIViewController that holds the cell. Allows the cell the present View Controllers*/
25 | open weak var currentViewController: UIViewController?
26 | /** The current table in which this node resides*/
27 | open weak var currentTableNode: ASTableNode?
28 | /** message incoming/outgoing */
29 | open var isIncomingMessage:Bool = true
30 |
31 | // MARK: Initialisers
32 | /**
33 | Default Init
34 | Sets cellPadding to 0 and selectionStyle to None
35 | */
36 | public override init() {
37 | super.init()
38 | selectionStyle = .none
39 | cellPadding = UIEdgeInsetsMake(0.0, 0.0, 0.0, 0.0)
40 | }
41 | /**
42 | Initialiser for the cell
43 | - parameter cellPadding: Can be UIEdgeInsets. Sets padding for cell.
44 | - parameter currentViewController: Can be an UIViewController. Set current view controller holding the cell.
45 | */
46 | public convenience init(cellPadding: UIEdgeInsets?, currentViewController: UIViewController?) {
47 | self.init()
48 |
49 | //set cell padding
50 | if let cellPadding = cellPadding {
51 | self.cellPadding = cellPadding
52 | }
53 |
54 | //set current view controller
55 | self.currentViewController = currentViewController
56 | }
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/nMessenger/Source/MessageNodes/Indicators/HeadLoadingIndicator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2016 eBay Software Foundation
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 | //
6 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 | //
8 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 | //
10 |
11 | import AsyncDisplayKit
12 | import UIKit
13 |
14 | //MARK: HeadLoadingIndicator class
15 | /**
16 | Spinning loading indicator class. Used by the NMessenger prefetch.
17 | */
18 | open class HeadLoadingIndicator: GeneralMessengerCell {
19 | /** Horizontal spacing between text and spinner. Defaults to 20.*/
20 | open var contentPadding:CGFloat = 20 {
21 | didSet {
22 | self.setNeedsLayout()
23 | }
24 | }
25 | /** Animated spinner node*/
26 | open let spinner = SpinnerNode()
27 | /** Loading text node*/
28 | open let text = ASTextNode()
29 | /** Sets the loading attributed text for the spinner. Defaults to *"Loading..."* */
30 | open var loadingAttributedText:NSAttributedString? {
31 | set {
32 | text.attributedText = newValue
33 | self.setNeedsLayout()
34 | } get {
35 | return text.attributedText
36 | }
37 | }
38 |
39 | public override init() {
40 | super.init()
41 | addSubnode(text)
42 | text.attributedText = NSAttributedString(
43 | string: "Loading…",
44 | attributes: [
45 | NSFontAttributeName: UIFont.systemFont(ofSize: 12),
46 | NSForegroundColorAttributeName: UIColor.lightGray,
47 | NSKernAttributeName: -0.3
48 | ])
49 | addSubnode(spinner)
50 | }
51 |
52 | override open func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec {
53 | let stackLayout = ASStackLayoutSpec(
54 | direction: .horizontal,
55 | spacing: contentPadding,
56 | justifyContent: .center,
57 | alignItems: .center,
58 | children: [ text, spinner ])
59 | let paddingLayout = ASInsetLayoutSpec(insets: cellPadding, child: stackLayout)
60 | return paddingLayout
61 | }
62 | }
63 |
64 | //MARK: SpinnerNode class
65 | /**
66 | Animated spinner. Used by HeadLoadingIndicator. Defaults to *preferredFrameSize.height=32*
67 | */
68 | open class SpinnerNode: ASDisplayNode {
69 | open var activityIndicatorView: UIActivityIndicatorView {
70 | return view as! UIActivityIndicatorView
71 | }
72 |
73 | public override init() {
74 | super.init()
75 | self.setViewBlock({ UIActivityIndicatorView(activityIndicatorStyle: .gray) })
76 | self.style.preferredSize.height = 32
77 | }
78 |
79 | override open func didLoad() {
80 | super.didLoad()
81 | activityIndicatorView.startAnimating()
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/nMessenger/Source/MessageNodes/Indicators/MessageSentIndicator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2016 eBay Software Foundation
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 | //
6 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 | //
8 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 | //
10 |
11 | import AsyncDisplayKit
12 | import UIKit
13 |
14 | //MARK: HeadLoadingIndicator class
15 | /**
16 | Spinning loading indicator class. Used by the NMessenger prefetch.
17 | */
18 | open class MessageSentIndicator: GeneralMessengerCell {
19 | /** Horizontal spacing between text and spinner. Defaults to 20.*/
20 | open var contentPadding:CGFloat = 20 {
21 | didSet {
22 | self.setNeedsLayout()
23 | }
24 | }
25 | /** Loading text node*/
26 | open let text = ASTextNode()
27 | /** Sets the loading attributed text for the spinner. Defaults to *"Loading..."* */
28 | open var messageSentAttributedText:NSAttributedString? {
29 | set {
30 | text.attributedText = newValue
31 | self.setNeedsLayout()
32 | } get {
33 | return text.attributedText
34 | }
35 | }
36 | open var messageSentText: String? {
37 | set {
38 | text.attributedText = NSAttributedString(
39 | string: newValue != nil ? newValue! : "",
40 | attributes: [
41 | NSFontAttributeName: UIFont.systemFont(ofSize: 14),
42 | NSForegroundColorAttributeName: UIColor.lightGray,
43 | NSKernAttributeName: -0.3
44 | ])
45 | self.setNeedsLayout()
46 | } get {
47 | return text.attributedText?.string
48 | }
49 | }
50 |
51 | public override init() {
52 | super.init()
53 | addSubnode(text)
54 | }
55 |
56 | override open func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec {
57 | let stackLayout = ASStackLayoutSpec(
58 | direction: .horizontal,
59 | spacing: contentPadding,
60 | justifyContent: .center,
61 | alignItems: .center,
62 | children: [ text ])
63 | let paddingLayout = ASInsetLayoutSpec(insets: cellPadding, child: stackLayout)
64 | return paddingLayout
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/nMessenger/Source/MessageNodes/MessageCell/MessageCellProtocol.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MessageCellProtocol.swift
3 | // nMessenger
4 | //
5 | // Created by Tainter, Aaron on 7/15/16.
6 | // Copyright © 2016 Ebay Inc. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | /** Protocol used by a message cell to handle various message related actions */
12 | @objc public protocol MessageCellProtocol {
13 | /**
14 | Called when the avatar is clicked. Notifies the delegate of the message cell whose avatar is clicked
15 | */
16 | @objc optional func avatarClicked(_ messageCell: GeneralMessengerCell)
17 | }
18 |
--------------------------------------------------------------------------------
/nMessenger/Source/Messenger/Components/InputBarView/InputBarView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2016 eBay Software Foundation
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 | //
6 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 | //
8 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 | //
10 |
11 | import UIKit
12 |
13 | //MARK: InputBarView
14 | /**
15 | InputBarView class for NMessenger.
16 | Define the input bar for NMessenger. This is where the user would type text and open the camera or photo library.
17 | */
18 | open class InputBarView: UIView, InputBarViewProtocol {
19 |
20 | //MARK: IBOutlets
21 | //@IBOutlets for input area view
22 | @IBOutlet open weak var textInputAreaView: UIView!
23 | //@IBOutlets for input view
24 | @IBOutlet open weak var textInputView: UITextView!
25 |
26 | //MARK: Public Parameters
27 |
28 | //MARK: Private Parameters
29 | //NMessengerViewController where to input is sent to
30 | open weak var controller:NMessengerViewController!
31 |
32 | // MARK: Initialisers
33 | /**
34 | Initialiser the view.
35 | - parameter controller: Must be NMessengerViewController. Sets controller for the view.
36 | Calls helper method to setup the view
37 | */
38 | public required init()
39 | {
40 | super.init(frame: CGRect(x: 0, y: 0, width: 0, height: 0))
41 | }
42 |
43 | public required init(controller:NMessengerViewController) {
44 | super.init(frame: CGRect.zero)
45 | self.controller = controller
46 | }
47 | /**
48 | Initialiser the view.
49 | - parameter controller: Must be NMessengerViewController. Sets controller for the view.
50 | - parameter controller: Must be CGRect. Sets frame for the view.
51 | Calls helper method to setup the view
52 | */
53 | public required init(controller:NMessengerViewController,frame: CGRect) {
54 | super.init(frame: frame)
55 | self.controller = controller
56 | }
57 | /**
58 | - parameter aDecoder: Must be NSCoder
59 | Calls helper method to setup the view
60 | */
61 | public required init?(coder aDecoder: NSCoder) {
62 | super.init(coder: aDecoder)
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/nMessenger/Source/Messenger/Components/InputBarView/InputBarViewProtocol.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2016 eBay Software Foundation
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 | //
6 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 | //
8 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 | //
10 |
11 | import Foundation
12 | import UIKit
13 |
14 | @objc public protocol InputBarViewProtocol
15 | {
16 | /* Superview of textInputView - can hold send button and/or attachment button*/
17 | var textInputAreaView: UIView! {get set}
18 | /* UITextView where the user will input the text*/
19 | var textInputView: UITextView! {get set}
20 | //NMessengerViewController where to input is sent to
21 | var controller:NMessengerViewController! {get set}
22 | }
--------------------------------------------------------------------------------
/nMessenger/Source/Utilities/ModalAlertUtilities.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2016 eBay Software Foundation
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 | //
6 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 | //
8 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 | //
10 |
11 | import Foundation
12 | import UIKit
13 |
14 | //MARK: ModalAlertUtilities class
15 | /**
16 | Custom alerts for NMessenger
17 | */
18 | open class ModalAlertUtilities {
19 | /**
20 | General error alert message
21 | - parameter controller: Must be UIViewController. Where to present to alert.
22 | */
23 | class func postGenericErrorModal(fromController controller: UIViewController) {
24 | let alert = UIAlertController(title: "Error", message: "An error occurred. Please try again later", preferredStyle: .alert)
25 | let cancelAction = UIAlertAction(title: "Okay", style: .cancel) { (action) in
26 | alert.dismiss(animated: true, completion: nil)
27 | }
28 | alert.addAction(cancelAction)
29 | DispatchQueue.main.async(execute: { () -> Void in
30 | controller.present(alert, animated: true, completion: nil)
31 | })
32 | }
33 | /**
34 | Camera permission alert message
35 | - parameter controller: Must be UIViewController. Where to present to alert.
36 | Alert tells user to go into setting to enable permission for both camera and photo library
37 | */
38 | class func postGoToSettingToEnableCameraAndLibraryModal(fromController controller: UIViewController)
39 | {
40 | let alert = UIAlertController(title: "", message: "Allow access to your camera & photo library to start uploading photos with N1", preferredStyle: .alert)
41 | let cancelAction = UIAlertAction(title: "Cancel", style: .destructive) { (action) in
42 | alert.dismiss(animated: true, completion: nil)
43 | }
44 | let settingsAction = UIAlertAction(title: "Go to Settings", style: .default) { (alertAction) in
45 | if let appSettings = URL(string: UIApplicationOpenSettingsURLString) {
46 | UIApplication.shared.openURL(appSettings)
47 | }
48 | }
49 | alert.addAction(settingsAction)
50 | alert.addAction(cancelAction)
51 |
52 | DispatchQueue.main.async(execute: { () -> Void in
53 | controller.present(alert, animated: true, completion: nil)
54 | })
55 | }
56 | /**
57 | Camera permission alert message
58 | - parameter controller: Must be UIViewController. Where to present to alert.
59 | Alert tells user to go into setting to enable permission for camera
60 | */
61 | class func postGoToSettingToEnableCameraModal(fromController controller: UIViewController)
62 | {
63 | let alert = UIAlertController(title: "", message: "Allow access to your camera to start taking photos and uploading photos from your library with N1", preferredStyle: .alert)
64 | let cancelAction = UIAlertAction(title: "Cancel", style: .destructive) { (action) in
65 | alert.dismiss(animated: true, completion: nil)
66 | }
67 | let settingsAction = UIAlertAction(title: "Go to Settings", style: .default) { (alertAction) in
68 | if let appSettings = URL(string: UIApplicationOpenSettingsURLString) {
69 | UIApplication.shared.openURL(appSettings)
70 | }
71 | }
72 | alert.addAction(settingsAction)
73 | alert.addAction(cancelAction)
74 |
75 | DispatchQueue.main.async(execute: { () -> Void in
76 | controller.present(alert, animated: true, completion: nil)
77 | })
78 | }
79 | /**
80 | Camera permission alert message
81 | - parameter controller: Must be UIViewController. Where to present to alert.
82 | Alert tells user to go into setting to enable permission for photo library
83 | */
84 | class func postGoToSettingToEnableLibraryModal(fromController controller: UIViewController)
85 | {
86 | let alert = UIAlertController(title: "", message: "Allow access to your photo library to start uploading photos from you library with N1", preferredStyle: .alert)
87 | let cancelAction = UIAlertAction(title: "Cancel", style: .destructive) { (action) in
88 | alert.dismiss(animated: true, completion: nil)
89 | }
90 | let settingsAction = UIAlertAction(title: "Go to Settings", style: .default) { (alertAction) in
91 | if let appSettings = URL(string: UIApplicationOpenSettingsURLString) {
92 | UIApplication.shared.openURL(appSettings)
93 | }
94 | }
95 | alert.addAction(settingsAction)
96 | alert.addAction(cancelAction)
97 |
98 | DispatchQueue.main.async(execute: { () -> Void in
99 | controller.present(alert, animated: true, completion: nil)
100 | })
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/nMessenger/Source/Utilities/UIColor+N1Colors.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2016 eBay Software Foundation
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 | //
6 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 | //
8 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 | //
10 |
11 | import Foundation
12 | import UIKit
13 |
14 | //MARK: UIColor extension
15 | /**
16 | Custom Colors for NMessenger
17 | */
18 | extension UIColor {
19 | class func n1MidGreyColor() -> UIColor {
20 | return UIColor(red: 144.0 / 255.0, green: 164.0 / 255.0, blue: 174.0 / 255.0, alpha: 1)
21 | }
22 |
23 | class func n1DarkestGreyColor() -> UIColor {
24 | return UIColor(red: 38.0 / 255.0, green: 50.0 / 255.0, blue: 56.0 / 255.0, alpha: 1)
25 | }
26 |
27 | class func n1DarkGreyColor() -> UIColor {
28 | return UIColor(red: 96.0 / 255.0, green: 125.0 / 255.0, blue: 139.0 / 255.0, alpha: 1)
29 | }
30 |
31 | class func n1WhiteColor() -> UIColor {
32 | return UIColor(white: 255.0 / 255.0, alpha: 1)
33 | }
34 |
35 | class func n1BrandRedColor() -> UIColor {
36 | return UIColor(red: 255.0 / 255.0, green: 38.0 / 255.0, blue: 66.0 / 255.0, alpha: 1)
37 | }
38 |
39 | class func n1ActionBlueColor() -> UIColor {
40 | return UIColor(red: 74.0 / 255.0, green: 144.0 / 255.0, blue: 226.0 / 255.0, alpha: 1)
41 | }
42 |
43 | class func n1OverlayBorderColor() -> UIColor {
44 | return UIColor(red: 38.0 / 255.0, green: 49.0 / 255.0, blue: 56.0 / 255.0, alpha: 0.1)
45 | }
46 |
47 | class func n1AlmostWhiteColor() -> UIColor {
48 | return UIColor(red: 251.0 / 255.0, green: 252.0 / 255.0, blue: 253.0 / 255.0, alpha: 1)
49 | }
50 |
51 | class func n1DarkerGreyColor() -> UIColor {
52 | return UIColor(red: 69.0 / 255.0, green: 90.0 / 255.0, blue: 100.0 / 255.0, alpha: 1)
53 | }
54 |
55 | class func n1LightGreyColor() -> UIColor {
56 | return UIColor(red: 207.0 / 255.0, green: 216.0 / 255.0, blue: 220.0 / 255.0, alpha: 1)
57 | }
58 |
59 | class func n1LighterGreyColor() -> UIColor {
60 | return UIColor(red: 233.0 / 255.0, green: 239.0 / 255.0, blue: 242.0 / 255.0, alpha: 1)
61 | }
62 |
63 | class func n1PaleGreyColor() -> UIColor {
64 | return UIColor(red: 243.0 / 255.0, green: 247.0 / 255.0, blue: 249.0 / 255.0, alpha: 1)
65 | }
66 |
67 | class func n1Black50Color() -> UIColor {
68 | return UIColor(white: 0.0, alpha: 0.5)
69 | }
70 |
71 | class func colorFromRGB(_ rgbHexValue: UInt) -> UIColor {
72 | return UIColor(
73 | red: CGFloat((rgbHexValue & 0xFF0000) >> 16) / 255.0,
74 | green: CGFloat((rgbHexValue & 0x00FF00) >> 8) / 255.0,
75 | blue: CGFloat(rgbHexValue & 0x0000FF) / 255.0,
76 | alpha: CGFloat(1.0)
77 | )
78 | }
79 | /** returns a random color */
80 | class func randomColor() -> UIColor{
81 | let red = CGFloat(drand48())
82 | let green = CGFloat(drand48())
83 | let blue = CGFloat(drand48())
84 | return UIColor(red: red, green: green, blue: blue, alpha: 1.0)
85 | }
86 |
87 | }
88 |
--------------------------------------------------------------------------------
/nMessenger/Source/Utilities/UIFont+N1Fonts.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2016 eBay Software Foundation
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 | //
6 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 | //
8 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 | //
10 |
11 | import Foundation
12 | import UIKit
13 |
14 | //MARK: UIFont extension
15 | /**
16 | Custom Fonts for NMessenger
17 | */
18 | extension UIFont {
19 | class func n1H1Font() -> UIFont {
20 | return UIFont.systemFont(ofSize: 28.0, weight: UIFontWeightThin)
21 | }
22 |
23 | class func n1H2Font() -> UIFont {
24 | return UIFont.systemFont(ofSize: 20.0, weight: UIFontWeightLight)
25 | }
26 |
27 | class func n1H3Font() -> UIFont {
28 | return UIFont.systemFont(ofSize: 18.0, weight: UIFontWeightRegular)
29 | }
30 |
31 | class func n1LinkFont() -> UIFont {
32 | return UIFont.systemFont(ofSize: 16.0, weight: UIFontWeightSemibold)
33 | }
34 |
35 | class func n1TextStyleFont() -> UIFont {
36 | return UIFont.systemFont(ofSize: 16.0, weight: UIFontWeightRegular)
37 | }
38 |
39 | class func n1B1Font() -> UIFont {
40 | return UIFont.systemFont(ofSize: 16.0, weight: UIFontWeightRegular)
41 | }
42 |
43 | class func n1TextStyle3Font() -> UIFont {
44 | return UIFont.systemFont(ofSize: 12.0, weight: UIFontWeightBold)
45 | }
46 |
47 | class func n1TextStyle3MiniFont() -> UIFont {
48 | return UIFont.systemFont(ofSize: 8.0, weight: UIFontWeightBold)
49 | }
50 |
51 | class func n1TextStyle2Font() -> UIFont {
52 | return UIFont.systemFont(ofSize: 14.0, weight: UIFontWeightRegular)
53 | }
54 |
55 | class func n1B2Font() -> UIFont {
56 | return UIFont.systemFont(ofSize: 14.0, weight: UIFontWeightRegular)
57 | }
58 |
59 | class func n1TextStyle4Font() -> UIFont {
60 | return UIFont.systemFont(ofSize: 14.0, weight: UIFontWeightLight)
61 | }
62 |
63 | class func n1CaptionFont() -> UIFont {
64 | return UIFont.systemFont(ofSize: 12.0, weight: UIFontWeightMedium)
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/nMessenger/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2016 eBay Software Foundation
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 | //
6 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 | //
8 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 | //
10 |
11 | import UIKit
12 |
13 | class ViewController: UIViewController {
14 |
15 | override func viewDidLoad() {
16 | super.viewDidLoad()
17 | // Do any additional setup after loading the view, typically from a nib.
18 | }
19 |
20 | override func didReceiveMemoryWarning() {
21 | super.didReceiveMemoryWarning()
22 | // Dispose of any resources that can be recreated.
23 | }
24 |
25 |
26 | }
27 |
28 |
--------------------------------------------------------------------------------
/nMessengerTests/Extensions/UIColorTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIColorTests.swift
3 | // nMessenger
4 | //
5 | // Created by Tainter, Aaron on 8/23/16.
6 | // Copyright © 2016 Ebay Inc. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import nMessenger
11 |
12 | class UIColorTests: XCTestCase {
13 | func testColorsForValues() {
14 | XCTAssertNotNil(UIColor.n1WhiteColor())
15 | XCTAssertNotNil(UIColor.n1MidGreyColor())
16 | XCTAssertNotNil(UIColor.n1BrandRedColor())
17 | XCTAssertNotNil(UIColor.n1DarkGreyColor())
18 | XCTAssertNotNil(UIColor.n1PaleGreyColor())
19 | XCTAssertNotNil(UIColor.n1LightGreyColor())
20 | XCTAssertNotNil(UIColor.n1ActionBlueColor())
21 | XCTAssertNotNil(UIColor.n1DarkerGreyColor())
22 | XCTAssertNotNil(UIColor.n1AlmostWhiteColor())
23 | XCTAssertNotNil(UIColor.n1DarkestGreyColor())
24 | XCTAssertNotNil(UIColor.n1LighterGreyColor())
25 | XCTAssertNotNil(UIColor.n1OverlayBorderColor())
26 | XCTAssertNotNil(UIColor.n1Black50Color())
27 | XCTAssertNotNil(UIColor.randomColor())
28 | XCTAssertNotNil(UIColor.colorFromRGB(0x000000))
29 | }
30 | }
--------------------------------------------------------------------------------
/nMessengerTests/Extensions/UIFontTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIFontTests.swift
3 | // nMessenger
4 | //
5 | // Created by Tainter, Aaron on 8/23/16.
6 | // Copyright © 2016 Ebay Inc. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import nMessenger
11 |
12 | class N1FontTests: XCTestCase {
13 | func testFontsForValues() {
14 | XCTAssertNotNil(UIFont.n1B1Font())
15 | XCTAssertNotNil(UIFont.n1B2Font())
16 | XCTAssertNotNil(UIFont.n1H1Font())
17 | XCTAssertNotNil(UIFont.n1H2Font())
18 | XCTAssertNotNil(UIFont.n1H3Font())
19 | XCTAssertNotNil(UIFont.n1LinkFont())
20 | XCTAssertNotNil(UIFont.n1CaptionFont())
21 | XCTAssertNotNil(UIFont.n1TextStyleFont())
22 | XCTAssertNotNil(UIFont.n1TextStyle3Font())
23 | XCTAssertNotNil(UIFont.n1TextStyle3MiniFont())
24 | XCTAssertNotNil(UIFont.n1TextStyle2Font())
25 | XCTAssertNotNil(UIFont.n1TextStyle4Font())
26 | }
27 | }
--------------------------------------------------------------------------------
/nMessengerTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/nMessengerTests/UI Components/Chat/BubbleConfigurationTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BubbleConfigurationTests.swift
3 | // nMessenger
4 | //
5 | // Created by Tainter, Aaron on 8/23/16.
6 | // Copyright © 2016 Ebay Inc. All rights reserved.
7 | //
8 |
9 |
10 | import XCTest
11 | @testable import nMessenger
12 |
13 | class BubbleConfigurationTests: XCTestCase {
14 |
15 | func testStandardConfig() {
16 | let bc = StandardBubbleConfiguration()
17 | XCTAssertNotNil(bc.getBubble())
18 | XCTAssertNotNil(bc.getSecondaryBubble())
19 | XCTAssertNotNil(bc.getIncomingColor())
20 | XCTAssertNotNil(bc.getOutgoingColor())
21 |
22 | bc.isMasked = true
23 | XCTAssertNotNil(bc.getBubble())
24 | XCTAssertNotNil(bc.getSecondaryBubble())
25 | XCTAssertNotNil(bc.getIncomingColor())
26 | XCTAssertNotNil(bc.getOutgoingColor())
27 |
28 | XCTAssertTrue(bc.getBubble().hasLayerMask)
29 | XCTAssertTrue(bc.getSecondaryBubble().hasLayerMask)
30 |
31 | }
32 |
33 | func testSimpleBubbleConfig() {
34 | let bc = SimpleBubbleConfiguration()
35 | XCTAssertNotNil(bc.getBubble())
36 | XCTAssertNotNil(bc.getSecondaryBubble())
37 | XCTAssertNotNil(bc.getIncomingColor())
38 | XCTAssertNotNil(bc.getOutgoingColor())
39 |
40 | bc.isMasked = true
41 | XCTAssertNotNil(bc.getBubble())
42 | XCTAssertNotNil(bc.getSecondaryBubble())
43 | XCTAssertNotNil(bc.getIncomingColor())
44 | XCTAssertNotNil(bc.getOutgoingColor())
45 |
46 | XCTAssertTrue(bc.getBubble().hasLayerMask)
47 | XCTAssertTrue(bc.getSecondaryBubble().hasLayerMask)
48 | }
49 |
50 | func testImageBubbleConfiguration() {
51 | let bc = ImageBubbleConfiguration()
52 | XCTAssertNotNil(bc.getBubble())
53 | XCTAssertNotNil(bc.getSecondaryBubble())
54 | XCTAssertNotNil(bc.getIncomingColor())
55 | XCTAssertNotNil(bc.getOutgoingColor())
56 |
57 | bc.isMasked = true
58 | XCTAssertNotNil(bc.getBubble())
59 | XCTAssertNotNil(bc.getSecondaryBubble())
60 | XCTAssertNotNil(bc.getIncomingColor())
61 | XCTAssertNotNil(bc.getOutgoingColor())
62 |
63 | XCTAssertTrue(bc.getBubble().hasLayerMask)
64 | XCTAssertTrue(bc.getSecondaryBubble().hasLayerMask)
65 | }
66 |
67 | }
--------------------------------------------------------------------------------
/nMessengerTests/UI Components/Chat/BubbleTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BubbleTests.swift
3 | // n1
4 | //
5 | // Created by Tainter, Aaron on 4/21/16.
6 | // Copyright © 2016 Ebay Inc. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import nMessenger
11 |
12 | class BubbleTests: XCTestCase {
13 |
14 | func testBubble() {
15 | let bubble = Bubble()
16 | XCTAssertNotNil(bubble.layer)
17 | XCTAssertNotNil(bubble.maskLayer)
18 | XCTAssertEqual(bubble.hasLayerMask, false)
19 |
20 | var rect = CGRect(x: 0,y: 0,width: 50,height: 50)
21 | bubble.sizeToBounds(rect)
22 | XCTAssertEqual(rect.minX, bubble.calculatedBounds.minX)
23 | XCTAssertEqual(rect.minY, bubble.calculatedBounds.minY)
24 | XCTAssertEqual(rect.width, bubble.calculatedBounds.width)
25 | XCTAssertEqual(rect.height, bubble.calculatedBounds.height)
26 |
27 | rect = CGRect.zero
28 | bubble.sizeToBounds(rect)
29 | XCTAssertEqual(rect.minX, bubble.calculatedBounds.minX)
30 | XCTAssertEqual(rect.minY, bubble.calculatedBounds.minY)
31 | XCTAssertEqual(rect.width, bubble.calculatedBounds.width)
32 | XCTAssertEqual(rect.height, bubble.calculatedBounds.height)
33 |
34 | bubble.createLayer()
35 | XCTAssertNotNil(bubble.layer)
36 | XCTAssertNotNil(bubble.maskLayer)
37 | }
38 |
39 | func testBubbleSimple() {
40 | let bubble = SimpleBubble()
41 | XCTAssertNotNil(bubble.layer)
42 | XCTAssertNotNil(bubble.maskLayer)
43 | XCTAssertEqual(bubble.hasLayerMask, false)
44 |
45 | var rect = CGRect(x: 0,y: 0,width: 50,height: 50)
46 | bubble.sizeToBounds(rect)
47 | XCTAssertEqual(rect.minX, bubble.calculatedBounds.minX)
48 | XCTAssertEqual(rect.minY, bubble.calculatedBounds.minY)
49 | XCTAssertEqual(rect.width, bubble.calculatedBounds.width)
50 | XCTAssertEqual(rect.height, bubble.calculatedBounds.height)
51 |
52 | rect = CGRect.zero
53 | bubble.sizeToBounds(rect)
54 | XCTAssertEqual(rect.minX, bubble.calculatedBounds.minX)
55 | XCTAssertEqual(rect.minY, bubble.calculatedBounds.minY)
56 | XCTAssertEqual(rect.width, bubble.calculatedBounds.width)
57 | XCTAssertEqual(rect.height, bubble.calculatedBounds.height)
58 |
59 | bubble.createLayer()
60 | XCTAssertNotNil(bubble.layer)
61 | XCTAssertNotNil(bubble.maskLayer)
62 | }
63 |
64 | func testBubbleDefault() {
65 | let bubble = DefaultBubble()
66 | XCTAssertNotNil(bubble.layer)
67 | XCTAssertNotNil(bubble.maskLayer)
68 | XCTAssertEqual(bubble.hasLayerMask, false)
69 |
70 | var rect = CGRect(x: 0,y: 0,width: 50,height: 50)
71 | bubble.sizeToBounds(rect)
72 | XCTAssertEqual(rect.minX, bubble.calculatedBounds.minX)
73 | XCTAssertEqual(rect.minY, bubble.calculatedBounds.minY)
74 | XCTAssertEqual(rect.width, bubble.calculatedBounds.width)
75 | XCTAssertEqual(rect.height, bubble.calculatedBounds.height)
76 |
77 | rect = CGRect.zero
78 | bubble.sizeToBounds(rect)
79 | XCTAssertEqual(rect.minX, bubble.calculatedBounds.minX)
80 | XCTAssertEqual(rect.minY, bubble.calculatedBounds.minY)
81 | XCTAssertEqual(rect.width, bubble.calculatedBounds.width)
82 | XCTAssertEqual(rect.height, bubble.calculatedBounds.height)
83 |
84 | bubble.createLayer()
85 | XCTAssertNotNil(bubble.layer)
86 | XCTAssertNotNil(bubble.maskLayer)
87 | }
88 |
89 | func testBubbleStacked() {
90 | let bubble = StackedBubble()
91 | XCTAssertNotNil(bubble.layer)
92 | XCTAssertNotNil(bubble.maskLayer)
93 | XCTAssertEqual(bubble.hasLayerMask, false)
94 |
95 | var rect = CGRect(x: 0,y: 0,width: 50,height: 50)
96 | bubble.sizeToBounds(rect)
97 | XCTAssertEqual(rect.minX, bubble.calculatedBounds.minX)
98 | XCTAssertEqual(rect.minY, bubble.calculatedBounds.minY)
99 | XCTAssertEqual(rect.width, bubble.calculatedBounds.width)
100 | XCTAssertEqual(rect.height, bubble.calculatedBounds.height)
101 |
102 | rect = CGRect.zero
103 | bubble.sizeToBounds(rect)
104 | XCTAssertEqual(rect.minX, bubble.calculatedBounds.minX)
105 | XCTAssertEqual(rect.minY, bubble.calculatedBounds.minY)
106 | XCTAssertEqual(rect.width, bubble.calculatedBounds.width)
107 | XCTAssertEqual(rect.height, bubble.calculatedBounds.height)
108 |
109 | bubble.createLayer()
110 | XCTAssertNotNil(bubble.layer)
111 | XCTAssertNotNil(bubble.maskLayer)
112 | }
113 |
114 | func testBubbleImage() {
115 | let bubble = ImageBubble()
116 | bubble.bubbleImage = UIImage(named: "MessageBubble", in: Bundle(for: NMessengerViewController.self), compatibleWith: nil)
117 | XCTAssertNotNil(bubble.layer)
118 | XCTAssertNotNil(bubble.maskLayer)
119 | XCTAssertEqual(bubble.hasLayerMask, true)
120 |
121 | let rect = CGRect(x: 0,y: 0,width: 50,height: 50)
122 | bubble.sizeToBounds(rect)
123 | XCTAssertEqual(rect.minX, bubble.calculatedBounds.minX)
124 | XCTAssertEqual(rect.minY, bubble.calculatedBounds.minY)
125 | XCTAssertEqual(rect.width, bubble.calculatedBounds.width)
126 | XCTAssertEqual(rect.height, bubble.calculatedBounds.height)
127 |
128 | bubble.createLayer()
129 | XCTAssertNotNil(bubble.layer)
130 | XCTAssertNotNil(bubble.maskLayer)
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/nMessengerTests/UI Components/Chat/CollectionViewContentNodeTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CollectionViewContentNodeTests.swift
3 | // n1
4 | //
5 | // Created by Schechter, David on 4/28/16.
6 | // Copyright © 2016 Ebay Inc. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | import AsyncDisplayKit
11 | @testable import nMessenger
12 |
13 | class CollectionViewContentNodeTests: XCTestCase {
14 |
15 | func testExample() {
16 | // This is an example of a functional test case.
17 | // Use XCTAssert and related functions to verify your tests produce the correct results.
18 | let tmpView = UIView(frame: CGRect(x: 0,y: 0,width: 100,height: 100))
19 | let tempColectionNode = CollectionViewContentNode(withCustomViews: [tmpView], andNumberOfRows: 1)
20 | let tmpSize = CGSize(width: 100, height: 100)
21 | _ = tempColectionNode.layoutSpecThatFits(ASSizeRangeMake(tmpSize, tmpSize))
22 | let tmpCollection = UICollectionView(frame: CGRect(x: 0,y: 0,width: 100,height: 100), collectionViewLayout: UICollectionViewFlowLayout())
23 | _ = tempColectionNode.collectionView(tmpCollection, numberOfItemsInSection: 0)
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/nMessengerTests/UI Components/Chat/HeadLoadingIndicatorTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HeadLoadingIndicatorTests.swift
3 | // n1
4 | //
5 | // Created by Tainter, Aaron on 4/26/16.
6 | // Copyright © 2016 Ebay Inc. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import XCTest
11 | import AsyncDisplayKit
12 | @testable import nMessenger
13 |
14 | class HeadLoadingIndicatorTests: XCTestCase {
15 |
16 | func testElement() {
17 | let loadingIndicator = HeadLoadingIndicator()
18 | XCTAssertNotNil(loadingIndicator.spinner)
19 | XCTAssertNotNil(loadingIndicator.text)
20 | _ = loadingIndicator.layoutSpecThatFits(ASSizeRange(min: CGSize(width: 50, height: 10), max: CGSize(width: 200, height: 20)))
21 | }
22 |
23 | func testSpinner() {
24 | let spinner = SpinnerNode()
25 | XCTAssertNotNil(spinner.activityIndicatorView)
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/nMessengerTests/UI Components/Chat/MessageGroupTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MessageGroupTests.swift
3 | // n1
4 | //
5 | // Created by Tainter, Aaron on 5/9/16.
6 | // Copyright © 2016 Ebay Inc. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | import AsyncDisplayKit
11 | @testable import nMessenger
12 |
13 | class MessageGroupTests: XCTestCase {
14 | func testInitialize() {
15 | let messageGroup = MessageGroup()
16 |
17 | let textContent = TextContentNode(textMessageString: "blah")
18 | let newCell = MessageNode(content: textContent)
19 | messageGroup.addMessageToGroup(newCell, completion: nil)
20 |
21 | XCTAssertEqual(messageGroup.messages.count, 1)
22 | XCTAssertEqual(messageGroup.messages.last, newCell)
23 |
24 | messageGroup.removeMessageFromGroup(newCell, completion: nil)
25 |
26 | XCTAssertEqual(messageGroup.messages.count, 0)
27 |
28 | messageGroup.removeMessageFromGroup(newCell, completion: nil)
29 |
30 | XCTAssertEqual(messageGroup.messages.count, 0)
31 |
32 | messageGroup.addMessageToGroup(newCell, completion: nil)
33 |
34 | let textContent2 = TextContentNode(textMessageString: "blah")
35 | let newCell2 = MessageNode(content: textContent2)
36 | messageGroup.replaceMessage(newCell, withMessage: newCell2, completion: nil)
37 |
38 | XCTAssertEqual(messageGroup.messages.count, 1)
39 | XCTAssertEqual(messageGroup.messages.last, newCell2)
40 |
41 | //test avatar
42 | var avatarNode = ASDisplayNode()
43 | messageGroup.avatarNode = avatarNode
44 |
45 | XCTAssertNotNil(messageGroup.avatarNode)
46 | XCTAssertEqual(messageGroup.avatarNode, avatarNode)
47 |
48 | avatarNode = ASDisplayNode()
49 | messageGroup.avatarNode = avatarNode
50 |
51 | XCTAssertNotNil(messageGroup.avatarNode)
52 | XCTAssertEqual(messageGroup.avatarNode, avatarNode)
53 |
54 | //avatar insets
55 | let insets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
56 | messageGroup.avatarInsets = insets
57 |
58 | XCTAssertNotNil(messageGroup.avatarInsets)
59 | XCTAssertEqual(messageGroup.avatarInsets, insets)
60 |
61 | //message offset
62 | let messageOffset: CGFloat = 10
63 | messageGroup.messageOffset = messageOffset
64 |
65 | XCTAssertNotNil(messageGroup.messageOffset)
66 | XCTAssertEqual(messageGroup.messageOffset, messageOffset)
67 |
68 | //incoming message
69 | messageGroup.isIncomingMessage = false
70 |
71 | for cell in messageGroup.messages {
72 | if let message = cell as? MessageNode {
73 | XCTAssertNotNil(message.contentNode)
74 | XCTAssertFalse(message.contentNode!.isIncomingMessage)
75 | }
76 | }
77 | }
78 | }
--------------------------------------------------------------------------------
/nMessengerTests/UI Components/Chat/MessageNodeTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MessageNodeTests.swift
3 | // nMessenger
4 | //
5 | // Created by Tainter, Aaron on 8/23/16.
6 | // Copyright © 2016 Ebay Inc. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | import XCTest
12 | import AsyncDisplayKit
13 | @testable import nMessenger
14 |
15 | class MessageNodeTests: XCTestCase {
16 | func testInitialize() {
17 | let textContent = TextContentNode(textMessageString: "blah")
18 | let message = MessageNode(content: textContent)
19 |
20 | XCTAssertNotNil(message)
21 | XCTAssertNotNil(message.contentNode)
22 | XCTAssertEqual(message.contentNode, textContent)
23 |
24 | //reset content
25 | let newContent = TextContentNode(textMessageString: "blah2")
26 | message.contentNode = newContent
27 |
28 | XCTAssertNotNil(message)
29 | XCTAssertNotNil(message.contentNode)
30 | XCTAssertEqual(message.contentNode, newContent)
31 |
32 | //test header
33 | var headerNode = ASDisplayNode()
34 | message.headerNode = headerNode
35 |
36 | XCTAssertNotNil(message.headerNode)
37 | XCTAssertEqual(message.headerNode, headerNode)
38 |
39 | headerNode = ASDisplayNode()
40 | message.headerNode = headerNode
41 |
42 | XCTAssertNotNil(message.headerNode)
43 | XCTAssertEqual(message.headerNode, headerNode)
44 |
45 | //test footer
46 | var footerNode = ASDisplayNode()
47 | message.footerNode = footerNode
48 |
49 | XCTAssertNotNil(message.footerNode)
50 | XCTAssertEqual(message.footerNode, footerNode)
51 |
52 | footerNode = ASDisplayNode()
53 | message.footerNode = footerNode
54 |
55 | XCTAssertNotNil(message.footerNode)
56 | XCTAssertEqual(message.footerNode, footerNode)
57 |
58 | //test avatar
59 | var avatarNode = ASDisplayNode()
60 | message.avatarNode = avatarNode
61 |
62 | XCTAssertNotNil(message.avatarNode)
63 | XCTAssertEqual(message.avatarNode, avatarNode)
64 |
65 | avatarNode = ASDisplayNode()
66 | message.avatarNode = avatarNode
67 |
68 | XCTAssertNotNil(message.avatarNode)
69 | XCTAssertEqual(message.avatarNode, avatarNode)
70 |
71 |
72 | //avatar insets
73 | let insets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
74 | message.avatarInsets = insets
75 |
76 | XCTAssertNotNil(message.avatarInsets)
77 | XCTAssertEqual(message.avatarInsets, insets)
78 |
79 |
80 | //message offset
81 | let messageOffset: CGFloat = 10
82 | message.messageOffset = messageOffset
83 |
84 | XCTAssertNotNil(message.messageOffset)
85 | XCTAssertEqual(message.messageOffset, messageOffset)
86 |
87 |
88 | //header spacing
89 | let headerSpacing: CGFloat = 10
90 | message.headerSpacing = headerSpacing
91 |
92 | XCTAssertNotNil(message.headerSpacing)
93 | XCTAssertEqual(message.headerSpacing, headerSpacing)
94 |
95 |
96 | //footer spacing
97 | let footerSpacing: CGFloat = 10
98 | message.footerSpacing = footerSpacing
99 |
100 | XCTAssertNotNil(message.footerSpacing)
101 | XCTAssertEqual(message.footerSpacing, footerSpacing)
102 |
103 |
104 | //incoming message
105 | message.isIncomingMessage = false
106 | XCTAssertNotNil(message.contentNode)
107 | XCTAssertFalse(message.contentNode!.isIncomingMessage)
108 |
109 | }
110 | }
--------------------------------------------------------------------------------
/nMessengerTests/UI Components/Chat/NetworkImageContentNodeTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NetworkImageContentNodeTests.swift
3 | // n1
4 | //
5 | // Created by Schechter, David on 4/27/16.
6 | // Copyright © 2016 Ebay Inc. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | import AsyncDisplayKit
11 | @testable import nMessenger
12 |
13 | class NetworkImageContentNodeTests: XCTestCase {
14 |
15 | func testNetworkImage() {
16 | // This is an example of a functional test case.
17 | // Use XCTAssert and related functions to verify your tests produce the correct results.
18 | let testNetworkImage = NetworkImageContentNode(imageURL: "http://placehold.it/100x100")
19 | let tmpSize = CGSize(width: 100, height: 100)
20 | let tmpRecongnizer = UITapGestureRecognizer()
21 | _ = testNetworkImage.layoutSpecThatFits(ASSizeRangeMake(tmpSize, tmpSize))
22 | testNetworkImage.messageNodeLongPressSelector(tmpRecongnizer)
23 | testNetworkImage.copySelector()
24 | _ = testNetworkImage.canBecomeFirstResponder()
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/nMessengerTests/UI Components/NMessengerVCTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NMessengerVCTests.swift
3 | // n1
4 | //
5 | // Created by Tainter, Aaron on 5/13/16.
6 | // Copyright © 2016 Ebay Inc. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import XCTest
11 | @testable import nMessenger
12 |
13 | class NMessengerVCTests: XCTestCase {
14 |
15 | func testVC() {
16 | //TODO:
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/nMessengerTests/nMessengerTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2016 eBay Software Foundation
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 | //
6 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 | //
8 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 | //
10 |
11 | import XCTest
12 | @testable import nMessenger
13 |
14 | class nMessengerTests: XCTestCase {
15 |
16 | override func setUp() {
17 | super.setUp()
18 | // Put setup code here. This method is called before the invocation of each test method in the class.
19 | }
20 |
21 | override func tearDown() {
22 | // Put teardown code here. This method is called after the invocation of each test method in the class.
23 | super.tearDown()
24 | }
25 |
26 | func testExample() {
27 | // This is an example of a functional test case.
28 | // Use XCTAssert and related functions to verify your tests produce the correct results.
29 | }
30 |
31 | func testPerformanceExample() {
32 | // This is an example of a performance test case.
33 | self.measure {
34 | // Put the code you want to measure the time of here.
35 | }
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/nMessengerUITests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/nMessengerUITests/OrientationUITest.swift:
--------------------------------------------------------------------------------
1 | //
2 | // OrientationUITest.swift
3 | // nMessenger
4 | //
5 | // Created by Tainter, Aaron on 9/15/16.
6 | // Copyright © 2016 Ebay Inc. All rights reserved.
7 | //
8 |
9 | import XCTest
10 |
11 | class OrientationUITest: XCTestCase {
12 |
13 | override func setUp() {
14 | super.setUp()
15 |
16 | // Put setup code here. This method is called before the invocation of each test method in the class.
17 |
18 | // In UI tests it is usually best to stop immediately when a failure occurs.
19 | continueAfterFailure = false
20 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method.
21 | XCUIApplication().launch()
22 |
23 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
24 |
25 | XCUIDevice.shared().orientation = .portrait
26 | }
27 |
28 | override func tearDown() {
29 | // Put teardown code here. This method is called after the invocation of each test method in the class.
30 | super.tearDown()
31 |
32 | XCUIDevice.shared().orientation = .portrait
33 | }
34 |
35 | func testSPSCLaunchScreenLandscape() {
36 |
37 | XCUIDevice.shared().orientation = .landscapeLeft
38 |
39 | XCTAssert(UIInterfaceOrientationIsPortrait(UIApplication.shared.statusBarOrientation))
40 |
41 | XCUIDevice.shared().orientation = .landscapeRight
42 |
43 | XCTAssert(UIInterfaceOrientationIsPortrait(UIApplication.shared.statusBarOrientation))
44 |
45 | XCUIDevice.shared().orientation = .portrait
46 |
47 | XCTAssert(UIInterfaceOrientationIsPortrait(UIApplication.shared.statusBarOrientation))
48 |
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/nMessengerUITests/nMessengerUITests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2016 eBay Software Foundation
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 | //
6 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 | //
8 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 | //
10 |
11 | import XCTest
12 |
13 | class nMessengerUITests: XCTestCase {
14 |
15 | override func setUp() {
16 | super.setUp()
17 |
18 | // Put setup code here. This method is called before the invocation of each test method in the class.
19 |
20 | // In UI tests it is usually best to stop immediately when a failure occurs.
21 | continueAfterFailure = false
22 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method.
23 | XCUIApplication().launch()
24 |
25 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
26 | }
27 |
28 | override func tearDown() {
29 | // Put teardown code here. This method is called after the invocation of each test method in the class.
30 | super.tearDown()
31 | }
32 |
33 | func testExample() {
34 | // Use recording to get started writing UI tests.
35 | // Use XCTAssert and related functions to verify your tests produce the correct results.
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------