├── .gitignore
├── .swiftlint.yml
├── .travis.yml
├── Dangerfile
├── Example Watch Extension
├── Assets.xcassets
│ └── README__ignoredByTemplate__
├── ExtensionDelegate.swift
├── Info.plist
├── InterfaceController.swift
├── NotificationController.swift
└── PushNotificationPayload.apns
├── Example Watch
├── Assets.xcassets
│ └── AppIcon.appiconset
│ │ └── Contents.json
├── Base.lproj
│ └── Interface.storyboard
└── Info.plist
├── Example
├── AppDelegate.swift
├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ ├── Contents.json
│ ├── first.imageset
│ │ ├── Contents.json
│ │ └── first.pdf
│ ├── puppy.imageset
│ │ ├── Contents.json
│ │ ├── puppy.png
│ │ └── puppy@2x.png
│ └── second.imageset
│ │ ├── Contents.json
│ │ └── second.pdf
├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
├── FirstViewController.swift
├── Info.plist
└── SecondViewController.swift
├── Gemfile
├── Gemfile.lock
├── Images
└── puppy.png
├── LICENSE
├── Package.swift
├── Package@swift-4.swift
├── README.md
├── Sources
├── Info-iOS.plist
├── Info-tvOS.plist
├── Info-watchOS.plist
├── Info.plist
├── ViaSwiftUtils.h
└── ViaSwiftUtils
│ ├── Foundation
│ ├── CGPoint+Operators.swift
│ ├── CGRect+AspectRatio.swift
│ ├── CountableRange+Random.swift
│ ├── Date+ComponentAccessors.swift
│ ├── Date+TimesBetweenDates.swift
│ ├── Dictionary+MapValues.swift
│ ├── ForceUnwrappingOperators.swift
│ ├── MutableCollection+Shuffle.swift
│ ├── Observable.swift
│ ├── ObserverType.swift
│ ├── RandomAccessCollection+SafeAccess.swift
│ ├── Sequence+Helpers.swift
│ ├── SignedInteger+Random.swift
│ ├── TimeInterval+Converter.swift
│ └── TimeInterval+Intervals.swift
│ └── UIKit
│ ├── Bundle+ApplicationInfo.swift
│ ├── CGVector+Operators.swift
│ ├── NibView.swift
│ ├── String+Localized.swift
│ ├── String+Words.swift
│ ├── UIButton+States.swift
│ ├── UIControl+States.swift
│ ├── UIImage+Color.swift
│ ├── UIImage+Rounding.swift
│ ├── UIImageView+Rotation.swift
│ └── UIView+Xib.swift
├── Tests
├── LinuxMain.swift
└── ViaSwiftUtilsTests
│ ├── BetterForceUnwrappingTests.swift
│ ├── CGPoint+OperatorsTest.swift
│ ├── CGRectTests.swift
│ ├── CollectionShuffledTest.swift
│ ├── Date_ComparableTest.swift
│ ├── Date_ComponentAccessorsTest.swift
│ ├── Date_TimesBetween.swift
│ ├── Dictionary+MapValuesTests.swift
│ ├── RandomAccessCollection+SafeAccessTests.swift
│ └── SequenceTypeHelperTests.swift
├── ViaSwiftUtils.playground
├── Contents.swift
├── Resources
│ └── puppy.png
├── contents.xcplayground
├── playground.xcworkspace
│ └── contents.xcworkspacedata
└── timeline.xctimeline
├── ViaSwiftUtils.podspec
├── ViaSwiftUtils.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ └── contents.xcworkspacedata
└── xcshareddata
│ └── xcschemes
│ ├── ViaSwiftUtils_iOS.xcscheme
│ ├── ViaSwiftUtils_tvOS.xcscheme
│ └── ViaSwiftUtils_watchOS.xcscheme
├── ViaSwiftUtils.xcworkspace
├── contents.xcworkspacedata
├── xcshareddata
│ ├── IDEWorkspaceChecks.plist
│ └── ViaSwiftUtils.xcscmblueprint
└── xcuserdata
│ └── feilek.xcuserdatad
│ └── xcdebugger
│ └── Breakpoints_v2.xcbkptlist
├── iOSTests
├── CGVectorOperatorsTest.swift
├── Info.plist
├── NSLocale+Swizzling.swift
├── NibViewTest.swift
├── StringWordsTest.swift
├── TestStoryboard.storyboard
├── TestViewWithOwner.xib
├── TestViewWithoutOwner.xib
├── TimeIntervalConverterArabicTest.swift
├── TimeIntervalConverterTest.swift
├── UIButtonStateTests.swift
├── UIImageColorTest.swift
├── UIImageViewRotationTests.swift
└── UIViewXibTest.swift
├── install_swiftlint.sh
└── tvOSTests
├── Info.plist
└── ViaSwiftUtilsTests_tvOSTests.swift
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | build/
4 | *.pbxuser
5 | !default.pbxuser
6 | *.mode1v3
7 | !default.mode1v3
8 | *.mode2v3
9 | !default.mode2v3
10 | *.perspectivev3
11 | !default.perspectivev3
12 | */xcuserdata/*
13 | *.xccheckout
14 | *.moved-aside
15 | DerivedData
16 | *.hmap
17 | *.ipa
18 | *.xcuserstate
19 |
20 | .DS_Store
21 |
22 | # CocoaPods
23 | #
24 | # We recommend against adding the Pods directory to your .gitignore. However
25 | # you should judge for yourself, the pros and cons are mentioned at:
26 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control
27 | #
28 | Pods/
29 | #*.lock
30 |
31 | # SPM
32 |
33 | .build
34 | /.previous-build
35 |
36 | # Carthage
37 |
38 | Carthage/*
39 |
40 | # Build
41 |
42 | *.log
43 | *.csv
44 | *.dat
45 | *.out
46 | *.pid
47 | *.rdb
48 | *.pyc
49 |
50 | Rakefile
51 |
52 | # fastlane specific
53 | fastlane/report.xml
54 |
55 | # deliver temporary files
56 | fastlane/Preview.html
57 |
58 | # snapshot generated screenshots
59 | fastlane/screenshots/**/*.png
60 | fastlane/screenshots/screenshots.html
61 |
62 | # scan temporary files
63 | fastlane/test_output
64 |
65 | # Local Fastlane Settings
66 | fastlane/.env.local
67 |
68 | # Node.js
69 | Sketch/node_modules/
70 | .jshintrc
71 | /tmp
72 |
73 | # Sigh generated files
74 | *.mobileprovision
75 | *.dSYM.zip
76 |
--------------------------------------------------------------------------------
/.swiftlint.yml:
--------------------------------------------------------------------------------
1 | included:
2 | - Sources
3 | - iOSTests
4 | - Example
5 |
6 | disabled_rules: # rule identifiers to exclude from running
7 | - trailing_whitespace
8 |
9 | opt_in_rules:
10 | - anyobject_protocol
11 | - array_init
12 | - attributes
13 | - closure_body_length
14 | - closure_end_indentation
15 | - closure_spacing
16 | - collection_alignment
17 | - contains_over_filter_count
18 | - contains_over_filter_is_empty
19 | - contains_over_first_not_nil
20 | - contains_over_range_nil_comparison
21 | - convenience_type
22 | - discouraged_optional_boolean
23 | - discouraged_optional_collection
24 | - empty_collection_literal
25 | - empty_count
26 | - empty_enum_arguments
27 | - empty_string
28 | - empty_xctest_method
29 | - expiring_todo
30 | - explicit_init
31 | - extension_access_modifier
32 | - fallthrough
33 | - fatal_error_message
34 | - file_header
35 | - file_name
36 | - first_where
37 | - flatmap_over_map_reduce
38 | - force_unwrapping
39 | - function_default_parameter_at_end
40 | - identical_operands
41 | - implicit_return
42 | - implicitly_unwrapped_optional
43 | - joined_default_parameter
44 | - last_where
45 | - legacy_multiple
46 | - legacy_random
47 | - let_var_whitespace
48 | - literal_expression_end_indentation
49 | - lower_acl_than_parent
50 | - modifier_order
51 | - multiline_arguments
52 | - multiline_function_chains
53 | - multiline_literal_brackets
54 | - multiline_parameters
55 | - multiline_parameters_brackets
56 | - nimble_operator
57 | - no_grouping_extension
58 | - nslocalizedstring_require_bundle
59 | - number_separator
60 | - object_literal
61 | - operator_usage_whitespace
62 | - overridden_super_call
63 | - override_in_extension
64 | - pattern_matching_keywords
65 | - prefixed_toplevel_constant
66 | - private_action
67 | - private_outlet
68 | - prohibited_super_call
69 | - quick_discouraged_call
70 | - quick_discouraged_focused_test
71 | - quick_discouraged_pending_test
72 | - raw_value_for_camel_cased_codable_enum
73 | - reduce_into
74 | - redundant_nil_coalescing
75 | - required_enum_case
76 | - single_test_class
77 | - sorted_first_last
78 | - sorted_imports
79 | - strict_fileprivate
80 | - switch_case_on_newline
81 | - toggle_bool
82 | - trailing_closure
83 | - unavailable_function
84 | - unneeded_parentheses_in_closure_argument
85 | - unowned_variable_capture
86 | - untyped_error_in_catch
87 | - vertical_parameter_alignment_on_call
88 | - xct_specific_matcher
89 | - yoda_condition
90 |
91 | excluded: # paths to ignore during linting. overridden by `included`.
92 | - Carthage
93 | - Submodules
94 |
95 | closure_body_length:
96 | warning: 30
97 | error: 40
98 |
99 | number_separator:
100 | minimum_length: 5
101 |
102 | modifier_order:
103 | preferred_modifier_order:
104 | - acl
105 | - override
106 | - final
107 |
108 | line_length:
109 | warning: 160
110 | error: 200
111 | ignores_comments: true
112 |
113 | type_body_length:
114 | warning: 300
115 | error: 400
116 |
117 | function_body_length:
118 | warning: 60
119 | error: 120
120 |
121 | vertical_whitespace:
122 | max_empty_lines: 2
123 |
124 | file_header:
125 | required_pattern: |
126 | \/\/
127 | \/\/ .*?\.swift
128 | \/\/ ViaSwiftUtils
129 | \/\/
130 | \/\/ Copyright \d{4} Viacom, Inc.
131 | \/\/
132 | \/\/ Licensed under the Apache License, Version 2\.0 \(the "License"\);
133 | \/\/ you may not use this file except in compliance with the License\.
134 | \/\/ You may obtain a copy of the License at
135 | \/\/
136 | \/\/ http:\/\/www.apache.org\/licenses\/LICENSE-2\.0
137 | \/\/
138 | \/\/ Unless required by applicable law or agreed to in writing, software
139 | \/\/ distributed under the License is distributed on an "AS IS" BASIS,
140 | \/\/ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied\.
141 | \/\/ See the License for the specific language governing permissions and
142 | \/\/ limitations under the License\.
143 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | # references:
2 | # * http://www.objc.io/issue-6/travis-ci.html
3 |
4 | jobs:
5 | cache: bundler
6 | include:
7 | # Linux build
8 | - os: linux
9 | dist: xenial
10 | before_install:
11 | - git clone https://github.com/IBM-Swift/Package-Builder.git
12 | script: ./Package-Builder/build-package.sh -projectDir $TRAVIS_BUILD_DIR
13 |
14 | # Mac OS latest Xcode build and test
15 | - os: osx
16 | osx_image: xcode11.1
17 | language: objective-c
18 | xcode_workspace: ViaSwiftUtils.xcworkspace
19 | xcode_scheme: ViaSwiftUtils_iOS
20 | xcode_destination: platform=iOS Simulator,OS=13.1,name=iPhone 11 Pro
21 | install:
22 | - ./install_swiftlint.sh
23 | - bundle install
24 | script:
25 | - bundle exec danger
26 | - set -o pipefail && xcodebuild test -workspace ViaSwiftUtils.xcworkspace -scheme ViaSwiftUtils_iOS -destination "platform=iOS Simulator,OS=13.1,name=iPhone 11 Pro" | xcpretty
27 |
28 | # Mac OS older Xcode build
29 | - os: osx
30 | osx_image: xcode10.3
31 | language: objective-c
32 | xcode_workspace: ViaSwiftUtils.xcworkspace
33 | xcode_scheme: ViaSwiftUtils_iOS
34 | xcode_destination: platform=iOS Simulator,OS=12.4,name=iPhone 8
35 | install:
36 | - ./install_swiftlint.sh
37 | - bundle install
38 |
--------------------------------------------------------------------------------
/Dangerfile:
--------------------------------------------------------------------------------
1 | # Sometimes it's a README fix, or something like that - which isn't relevant for
2 | # including in a project's CHANGELOG for example
3 | declared_trivial = github.pr_title.include? "#trivial"
4 |
5 | # Run swiftlint and output results inline with the code changes
6 | swiftlint.config_file = '.swiftlint.yml'
7 | swiftlint.lint_files inline_mode: true
8 |
9 | # Make it more obvious that a PR is a work in progress and shouldn't be merged yet
10 | warn("PR is classed as Work in Progress") if github.pr_title.include? "[WIP]"
11 |
12 | # Warn when there is a big PR
13 | warn("Big PR") if git.lines_of_code > 500
14 |
15 | # Don't let testing shortcuts get into master by accident
16 | fail("fdescribe left in tests") if `grep -r fdescribe specs/ `.length > 1
17 | fail("fit left in tests") if `grep -r fit specs/ `.length > 1
18 |
19 | # Mainly to encourage writing up some reasoning about the PR, rather than just leaving a title.
20 | if github.pr_body.length < 3 && git.lines_of_code > 10
21 | warn("Please provide a summary in the Pull Request description")
22 | end
23 |
24 | ## Let's check if there are any changes in the project folder
25 | has_app_changes = !git.modified_files.grep(/Sources/).empty?
26 | ## Then, we should check if tests are updated
27 | has_test_changes = !git.modified_files.grep(/iOSTests/).empty?
28 | ## Finally, let's combine them and put extra condition
29 | ## for changed number of lines of code
30 | if has_app_changes && !(has_test_changes) && git.lines_of_code > 20
31 | warn("Tests were not updated", sticky: false)
32 | end
33 |
--------------------------------------------------------------------------------
/Example Watch Extension/Assets.xcassets/README__ignoredByTemplate__:
--------------------------------------------------------------------------------
1 | Did you know that git does not support storing empty directories?
2 |
--------------------------------------------------------------------------------
/Example Watch Extension/ExtensionDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ExtensionDelegate.swift
3 | //
4 | // Copyright 2017 Viacom, Inc.
5 | //
6 | // Licensed under the Apache License, Version 2.0 (the "License");
7 | // you may not use this file except in compliance with the License.
8 | // You may obtain a copy of the License at
9 | //
10 | // http://www.apache.org/licenses/LICENSE-2.0
11 | //
12 | // Unless required by applicable law or agreed to in writing, software
13 | // distributed under the License is distributed on an "AS IS" BASIS,
14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | // See the License for the specific language governing permissions and
16 | // limitations under the License.
17 |
18 | import WatchKit
19 |
20 | class ExtensionDelegate: NSObject, WKExtensionDelegate {
21 |
22 | func applicationDidFinishLaunching() {
23 | // Perform any final initialization of your application.
24 | }
25 |
26 | func applicationDidBecomeActive() {
27 | }
28 |
29 | func applicationWillResignActive() {
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/Example Watch Extension/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | ViaSwiftUtils Example Watch Extension
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | XPC!
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | 1
25 | NSExtension
26 |
27 | NSExtensionAttributes
28 |
29 | WKAppBundleIdentifier
30 | com.vimn.ViaSwiftUtils-Example.watchkitapp
31 |
32 | NSExtensionPointIdentifier
33 | com.apple.watchkit
34 |
35 | WKExtensionDelegateClassName
36 | $(PRODUCT_MODULE_NAME).ExtensionDelegate
37 |
38 |
39 |
--------------------------------------------------------------------------------
/Example Watch Extension/InterfaceController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // InterfaceController.swift
3 | // ViaSwiftUtils Example Watch Extension
4 | //
5 | // Copyright 2017 Viacom, Inc.
6 | //
7 | // Licensed under the Apache License, Version 2.0 (the "License");
8 | // you may not use this file except in compliance with the License.
9 | // You may obtain a copy of the License at
10 | //
11 | // http://www.apache.org/licenses/LICENSE-2.0
12 | //
13 | // Unless required by applicable law or agreed to in writing, software
14 | // distributed under the License is distributed on an "AS IS" BASIS,
15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | // See the License for the specific language governing permissions and
17 | // limitations under the License.
18 |
19 | import Foundation
20 | import WatchKit
21 |
22 | class InterfaceController: WKInterfaceController {
23 |
24 | override func awake(withContext context: Any?) {
25 | super.awake(withContext: context)
26 |
27 | // Configure interface objects here.
28 | }
29 |
30 | override func willActivate() {
31 | // This method is called when watch view controller is about to be visible to user
32 | super.willActivate()
33 | }
34 |
35 | override func didDeactivate() {
36 | // This method is called when watch view controller is no longer visible
37 | super.didDeactivate()
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/Example Watch Extension/NotificationController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NotificationController.swift
3 | //
4 | // Copyright 2017 Viacom, Inc.
5 | //
6 | // Licensed under the Apache License, Version 2.0 (the "License");
7 | // you may not use this file except in compliance with the License.
8 | // You may obtain a copy of the License at
9 | //
10 | // http://www.apache.org/licenses/LICENSE-2.0
11 | //
12 | // Unless required by applicable law or agreed to in writing, software
13 | // distributed under the License is distributed on an "AS IS" BASIS,
14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | // See the License for the specific language governing permissions and
16 | // limitations under the License.
17 |
18 | import Foundation
19 | import WatchKit
20 |
21 | class NotificationController: WKUserNotificationInterfaceController {
22 |
23 | override init() {
24 | // Initialize variables here.
25 | super.init()
26 |
27 | // Configure interface objects here.
28 | }
29 |
30 | override func willActivate() {
31 | // This method is called when watch view controller is about to be visible to user
32 | super.willActivate()
33 | }
34 |
35 | override func didDeactivate() {
36 | // This method is called when watch view controller is no longer visible
37 | super.didDeactivate()
38 | }
39 |
40 | /*
41 | override func didReceiveLocalNotification(localNotification: UILocalNotification,
42 | withCompletion completionHandler: ((WKUserNotificationInterfaceType) -> Void)) {
43 | // This method is called when a local notification needs to be presented.
44 | // Implement it if you use a dynamic notification interface.
45 | // Populate your dynamic notification interface as quickly as possible.
46 | //
47 | // After populating your dynamic notification interface call the completion block.
48 | completionHandler(.Custom)
49 | }
50 | */
51 |
52 | /*
53 | override func didReceiveRemoteNotification(remoteNotification: [NSObject : AnyObject],
54 | withCompletion completionHandler: ((WKUserNotificationInterfaceType) -> Void)) {
55 | // This method is called when a remote notification needs to be presented.
56 | // Implement it if you use a dynamic notification interface.
57 | // Populate your dynamic notification interface as quickly as possible.
58 | //
59 | // After populating your dynamic notification interface call the completion block.
60 | completionHandler(.Custom)
61 | }
62 | */
63 | }
64 |
--------------------------------------------------------------------------------
/Example Watch Extension/PushNotificationPayload.apns:
--------------------------------------------------------------------------------
1 | {
2 | "aps": {
3 | "alert": {
4 | "body": "Test message",
5 | "title": "Optional title"
6 | },
7 | "category": "myCategory"
8 | },
9 |
10 | "WatchKit Simulator Actions": [
11 | {
12 | "title": "First Button",
13 | "identifier": "firstButtonAction"
14 | }
15 | ],
16 |
17 | "customKey": "Use this file to define a testing payload for your notifications. The aps dictionary specifies the category, alert text and title. The WatchKit Simulator Actions array can provide info for one or more action buttons in addition to the standard Dismiss button. Any other top level keys are custom payload. If you have multiple such JSON files in your project, you'll be able to select them when choosing to debug the notification interface of your Watch App."
18 | }
19 |
--------------------------------------------------------------------------------
/Example Watch/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "24x24",
5 | "idiom" : "watch",
6 | "scale" : "2x",
7 | "role" : "notificationCenter",
8 | "subtype" : "38mm"
9 | },
10 | {
11 | "size" : "27.5x27.5",
12 | "idiom" : "watch",
13 | "scale" : "2x",
14 | "role" : "notificationCenter",
15 | "subtype" : "42mm"
16 | },
17 | {
18 | "size" : "29x29",
19 | "idiom" : "watch",
20 | "role" : "companionSettings",
21 | "scale" : "2x"
22 | },
23 | {
24 | "size" : "29x29",
25 | "idiom" : "watch",
26 | "role" : "companionSettings",
27 | "scale" : "3x"
28 | },
29 | {
30 | "size" : "40x40",
31 | "idiom" : "watch",
32 | "scale" : "2x",
33 | "role" : "appLauncher",
34 | "subtype" : "38mm"
35 | },
36 | {
37 | "size" : "86x86",
38 | "idiom" : "watch",
39 | "scale" : "2x",
40 | "role" : "quickLook",
41 | "subtype" : "38mm"
42 | },
43 | {
44 | "size" : "98x98",
45 | "idiom" : "watch",
46 | "scale" : "2x",
47 | "role" : "quickLook",
48 | "subtype" : "42mm"
49 | }
50 | ],
51 | "info" : {
52 | "version" : 1,
53 | "author" : "xcode"
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/Example Watch/Base.lproj/Interface.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 |
--------------------------------------------------------------------------------
/Example Watch/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | ViaSwiftUtils Example
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | 1
25 | UISupportedInterfaceOrientations
26 |
27 | UIInterfaceOrientationPortrait
28 | UIInterfaceOrientationPortraitUpsideDown
29 |
30 | WKCompanionAppBundleIdentifier
31 | com.vimn.ViaSwiftUtils-Example
32 | WKWatchKitApp
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/Example/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // ViaSwiftUtils
4 | //
5 | // Copyright 2017 Viacom, Inc.
6 | //
7 | // Licensed under the Apache License, Version 2.0 (the "License");
8 | // you may not use this file except in compliance with the License.
9 | // You may obtain a copy of the License at
10 | //
11 | // http://www.apache.org/licenses/LICENSE-2.0
12 | //
13 | // Unless required by applicable law or agreed to in writing, software
14 | // distributed under the License is distributed on an "AS IS" BASIS,
15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | // See the License for the specific language governing permissions and
17 | // limitations under the License.
18 |
19 | import UIKit
20 |
21 | @UIApplicationMain
22 | class AppDelegate: UIResponder, UIApplicationDelegate {
23 |
24 | var window: UIWindow?
25 |
26 | //swiftlint:disable:next discouraged_optional_collection
27 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
28 | // Override point for customization after application launch.
29 | return true
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Example/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 | "idiom" : "ios-marketing",
90 | "size" : "1024x1024",
91 | "scale" : "1x"
92 | }
93 | ],
94 | "info" : {
95 | "version" : 1,
96 | "author" : "xcode"
97 | }
98 | }
--------------------------------------------------------------------------------
/Example/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/Example/Assets.xcassets/first.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "first.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/Example/Assets.xcassets/first.imageset/first.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ViacomInc/ViaSwiftUtils/28414e8385a86102121b726dafb99daa9cfe6a1b/Example/Assets.xcassets/first.imageset/first.pdf
--------------------------------------------------------------------------------
/Example/Assets.xcassets/puppy.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "puppy.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "puppy@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/Example/Assets.xcassets/puppy.imageset/puppy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ViacomInc/ViaSwiftUtils/28414e8385a86102121b726dafb99daa9cfe6a1b/Example/Assets.xcassets/puppy.imageset/puppy.png
--------------------------------------------------------------------------------
/Example/Assets.xcassets/puppy.imageset/puppy@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ViacomInc/ViaSwiftUtils/28414e8385a86102121b726dafb99daa9cfe6a1b/Example/Assets.xcassets/puppy.imageset/puppy@2x.png
--------------------------------------------------------------------------------
/Example/Assets.xcassets/second.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "second.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/Example/Assets.xcassets/second.imageset/second.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ViacomInc/ViaSwiftUtils/28414e8385a86102121b726dafb99daa9cfe6a1b/Example/Assets.xcassets/second.imageset/second.pdf
--------------------------------------------------------------------------------
/Example/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/Example/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | Helvetica
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
37 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
89 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
--------------------------------------------------------------------------------
/Example/FirstViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FirstViewController.swift
3 | // ViaSwiftUtils
4 | //
5 | // Copyright 2017 Viacom, Inc.
6 | //
7 | // Licensed under the Apache License, Version 2.0 (the "License");
8 | // you may not use this file except in compliance with the License.
9 | // You may obtain a copy of the License at
10 | //
11 | // http://www.apache.org/licenses/LICENSE-2.0
12 | //
13 | // Unless required by applicable law or agreed to in writing, software
14 | // distributed under the License is distributed on an "AS IS" BASIS,
15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | // See the License for the specific language governing permissions and
17 | // limitations under the License.
18 |
19 | import UIKit
20 | import ViaSwiftUtils
21 |
22 | class FirstViewController: UIViewController {
23 |
24 | @IBOutlet private weak var imageView: UIImageView!
25 |
26 | override func viewDidLoad() {
27 | super.viewDidLoad()
28 |
29 | let rect = CGRect(x: 0, y: 0, width: 10, height: 5)
30 | print("aspect ratio: \(rect.aspectRatio)")
31 |
32 | var mutableNumberList = [1, 2, 3, 4, 5, 6]
33 | mutableNumberList.shuffleInPlace()
34 | print("shuffled numbers: \( mutableNumberList )")
35 |
36 | imageView.image = #imageLiteral(resourceName: "puppy").cornersRounded(usingRadius: 30)
37 | }
38 |
39 | override func didReceiveMemoryWarning() {
40 | super.didReceiveMemoryWarning()
41 | // Dispose of any resources that can be recreated.
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/Example/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 | UIStatusBarTintParameters
34 |
35 | UINavigationBar
36 |
37 | Style
38 | UIBarStyleDefault
39 | Translucent
40 |
41 |
42 |
43 | UISupportedInterfaceOrientations
44 |
45 | UIInterfaceOrientationPortrait
46 | UIInterfaceOrientationLandscapeLeft
47 | UIInterfaceOrientationLandscapeRight
48 |
49 | UISupportedInterfaceOrientations~ipad
50 |
51 | UIInterfaceOrientationPortrait
52 | UIInterfaceOrientationPortraitUpsideDown
53 | UIInterfaceOrientationLandscapeLeft
54 | UIInterfaceOrientationLandscapeRight
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/Example/SecondViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SecondViewController.swift
3 | // ViaSwiftUtils
4 | //
5 | // Copyright 2017 Viacom, Inc.
6 | //
7 | // Licensed under the Apache License, Version 2.0 (the "License");
8 | // you may not use this file except in compliance with the License.
9 | // You may obtain a copy of the License at
10 | //
11 | // http://www.apache.org/licenses/LICENSE-2.0
12 | //
13 | // Unless required by applicable law or agreed to in writing, software
14 | // distributed under the License is distributed on an "AS IS" BASIS,
15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | // See the License for the specific language governing permissions and
17 | // limitations under the License.
18 |
19 | import UIKit
20 |
21 | class SecondViewController: UIViewController {
22 |
23 | override func viewDidLoad() {
24 | super.viewDidLoad()
25 | // Do any additional setup after loading the view, typically from a nib.
26 | }
27 |
28 | override func didReceiveMemoryWarning() {
29 | super.didReceiveMemoryWarning()
30 | // Dispose of any resources that can be recreated.
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 |
3 | gem "danger"
4 | gem "danger-swiftlint"
5 | gem "unicode-display_width"
6 |
--------------------------------------------------------------------------------
/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GEM
2 | remote: https://rubygems.org/
3 | specs:
4 | addressable (2.7.0)
5 | public_suffix (>= 2.0.2, < 5.0)
6 | claide (1.0.3)
7 | claide-plugins (0.9.2)
8 | cork
9 | nap
10 | open4 (~> 1.3)
11 | colored2 (3.1.2)
12 | cork (0.3.0)
13 | colored2 (~> 3.1)
14 | danger (6.0.9)
15 | claide (~> 1.0)
16 | claide-plugins (>= 0.9.2)
17 | colored2 (~> 3.1)
18 | cork (~> 0.1)
19 | faraday (~> 0.9)
20 | faraday-http-cache (~> 2.0)
21 | git (~> 1.5)
22 | kramdown (~> 2.0)
23 | kramdown-parser-gfm (~> 1.0)
24 | no_proxy_fix
25 | octokit (~> 4.7)
26 | terminal-table (~> 1)
27 | danger-swiftlint (0.23.0)
28 | danger
29 | rake (> 10)
30 | thor (~> 0.19)
31 | faraday (0.15.4)
32 | multipart-post (>= 1.2, < 3)
33 | faraday-http-cache (2.0.0)
34 | faraday (~> 0.8)
35 | git (1.5.0)
36 | kramdown (2.1.0)
37 | kramdown-parser-gfm (1.1.0)
38 | kramdown (~> 2.0)
39 | multipart-post (2.1.1)
40 | nap (1.1.0)
41 | no_proxy_fix (0.1.2)
42 | octokit (4.14.0)
43 | sawyer (~> 0.8.0, >= 0.5.3)
44 | open4 (1.3.4)
45 | public_suffix (4.0.1)
46 | rake (12.3.3)
47 | sawyer (0.8.2)
48 | addressable (>= 2.3.5)
49 | faraday (> 0.8, < 2.0)
50 | terminal-table (1.8.0)
51 | unicode-display_width (~> 1.1, >= 1.1.1)
52 | thor (0.20.3)
53 | unicode-display_width (1.6.0)
54 |
55 | PLATFORMS
56 | ruby
57 |
58 | DEPENDENCIES
59 | danger
60 | danger-swiftlint
61 | unicode-display_width
62 |
63 | BUNDLED WITH
64 | 1.17.3
65 |
--------------------------------------------------------------------------------
/Images/puppy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ViacomInc/ViaSwiftUtils/28414e8385a86102121b726dafb99daa9cfe6a1b/Images/puppy.png
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2017 Viacom, Inc.
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | See the License for the specific language governing permissions and
13 | limitations under the License.
14 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:3.1
2 |
3 | import PackageDescription
4 |
5 | let package = Package(
6 | name: "ViaSwiftUtils",
7 | exclude: ["iOSTests", "Example", "Carthage", "Images", "Sources/ViaSwiftUtils/UIKit"]
8 | )
9 |
--------------------------------------------------------------------------------
/Package@swift-4.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:4.0
2 |
3 | import PackageDescription
4 |
5 | let package = Package(
6 | name: "ViaSwiftUtils",
7 | // exclude: ["iOSTests", "Example","Carthage","Images","Sources/ViaSwiftUtils/UIKit"],
8 | products: [
9 | .library(
10 | name: "ViaSwiftUtils",
11 | targets: ["ViaSwiftUtils"]
12 | )
13 | ],
14 | dependencies: [],
15 | targets: [
16 | .target(
17 | name: "ViaSwiftUtils",
18 | dependencies: [],
19 | path: "Sources/ViaSwiftUtils/Foundation"
20 | ),
21 | .testTarget(
22 | name: "ViaSwiftUtilsTests",
23 | dependencies: ["ViaSwiftUtils"]
24 | )
25 | ]
26 | )
27 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ViaSwiftUtils
2 |
3 | [](https://swift.org/)
4 | [](https://github.com/Carthage/Carthage)
5 | [](http://cocoapods.org/pods/ViaSwiftUtils)
6 | [](http://cocoapods.org/pods/ViaSwiftUtils)
7 | [](https://travis-ci.org/ViacomInc/ViaSwiftUtils)
8 | [](http://cocoapods.org/pods/ViaSwiftUtils)
9 |
10 | What can `ViaSwiftUtils` do for you? Here are some examples we compiled:
11 |
12 |
13 | Tired of spelling out `NSLocalizedString` every time you localize a string?
14 | ```swift
15 | title = "HomePage.title".localized
16 | print(title) // 'Main', '頭版', 'صفحه نخست', 'Startseite'
17 | ```
18 |
19 | --------
20 |
21 | Want to find the longest word in a string?
22 | ```swift
23 | print(germanText.longestWord())
24 | // 'Verkehrsinfrastrukturfinanzierungsgesellschaft'
25 | ```
26 |
27 | --------
28 |
29 | Need an array (or any other `MutableCollection`) shuffled? [^3]
30 | ```swift
31 | var numbers = [1, 2, 3, 4, 5, 6]
32 | numbers.shuffleInPlace() //e.g. [4, 1, 5, 2, 6, 3]
33 | ```
34 |
35 | --------
36 |
37 | Want all the unique entries in a `Sequence` with `Hashable` elements?
38 | ```swift
39 | let emojis = ["😀", "👀", "😱", "😡", "👀", "😀", "👀", "😱"]
40 | let uniqueEmojis = emojis.unique() // ["😀", "👀", "😱", "😡"]
41 | ```
42 |
43 | --------
44 |
45 | Is dealing with `TimeInterval` inconvenient?
46 | ```swift
47 | let twelveDays = 12 * TimeInterval.day
48 | let minutes = twelveDays / TimeInterval.minute // 17280
49 | ```
50 |
51 | --------
52 |
53 | Need to create an image with rounded corners from an existing image?
54 |
55 | 
56 |
57 | --------
58 |
59 | Does one of the views in your app need to rotate?
60 | ```swift
61 | someView.startRotating()
62 | // ...
63 | someView.stopRotating()
64 | ```
65 |
66 | --------
67 |
68 | And more date helper methods & variables:
69 | ```swift
70 | let components = DateComponents(calendar: gregorian, era: 0,
71 | year: 44, month: 3, day: 15, hour: 13)
72 | let idesOfMarch = gregorian.date(from: components)!
73 | let weekDay = idesOfMarch.dayOfWeek // 6
74 | let daysSince = idesOfMarch.days(to: Date()) // 752533
75 | ```
76 |
77 |
78 |
79 | These are just a few examples. We are expanding the library continuously and we accept Pull-Requests ☺️
80 |
81 |
82 |
83 |
84 | ## Requirements
85 |
86 | #### Versions support
87 |
88 | | **Swift** | **Xcode** | **ViaSwiftUtils** |
89 | | -- | -- | -- |
90 | | 4.2 - 5.0 | 10.X, 11.X | 2.1.0 |
91 | | 4.0 | 10.X | 2.0.5 |
92 | | 3.2 - 4.1 | 9.X | 2.0.5 |
93 |
94 |
95 |
96 | ## How to install [ViaSwiftUtils](https://github.com/ViacomInc/ViaSwiftUtils)
97 |
98 | #### Via Cocoapods
99 | Add the following line to your `Podfile`.
100 | Remember you'll need to enable `use_frameworks!`.
101 | ```
102 | pod 'ViaSwiftUtils', '2.1.0'
103 | ```
104 |
105 |
106 | #### Via Carthage
107 | Add the following line to your `Cartfile`
108 | ```
109 | github "ViacomInc/ViaSwiftUtils" == 2.1.0
110 | ```
111 |
112 | #### Via Swift package manager
113 |
114 | Add the following to your `Package.swift`
115 | ```swift
116 | dependencies: [
117 | .package(url: "https://github.com/ViacomInc/ViaSwiftUtils.git", .exact("2.1.0")),
118 | ]
119 |
120 | .target(name: <#yourTarget#>, dependencies: ["ViaSwiftUtils"]),
121 | ```
122 | I should mention that only the `Foundation` functions that are part of `ViaSwiftUtils` work via SPM, as `UIKit` is not available on Linux or MacOS.
123 |
124 |
125 | #### Importing
126 | After you installed the framework via one of the 3 above methods, import it in your `.swift` file.
127 | ```swift
128 | import ViaSwiftUtils
129 | ```
130 |
131 |
132 |
133 |
134 | ## License
135 |
136 | Licensed under the Apache License, Version 2.0 (the "License");
137 | you may not use this file except in compliance with the License.
138 | You may obtain a copy of the License at
139 |
140 | http://www.apache.org/licenses/LICENSE-2.0
141 |
142 | Unless required by applicable law or agreed to in writing, software
143 | distributed under the License is distributed on an "AS IS" BASIS,
144 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
145 | See the License for the specific language governing permissions and
146 | limitations under the License.
147 |
--------------------------------------------------------------------------------
/Sources/Info-iOS.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 |
--------------------------------------------------------------------------------
/Sources/Info-tvOS.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 |
--------------------------------------------------------------------------------
/Sources/Info-watchOS.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 |
--------------------------------------------------------------------------------
/Sources/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 |
--------------------------------------------------------------------------------
/Sources/ViaSwiftUtils.h:
--------------------------------------------------------------------------------
1 | //
2 | // ViaSwiftUtils iOS.h
3 | // ViaSwiftUtils iOS
4 | //
5 | // Copyright 2017 Viacom, Inc.
6 | //
7 | // Licensed under the Apache License, Version 2.0 (the "License");
8 | // you may not use this file except in compliance with the License.
9 | // You may obtain a copy of the License at
10 | //
11 | // http://www.apache.org/licenses/LICENSE-2.0
12 | //
13 | // Unless required by applicable law or agreed to in writing, software
14 | // distributed under the License is distributed on an "AS IS" BASIS,
15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | // See the License for the specific language governing permissions and
17 | // limitations under the License.
18 |
19 | #import
20 |
21 | //! Project version number for ViaSwiftUtils iOS.
22 | FOUNDATION_EXPORT double ViaSwiftUtils_iOSVersionNumber;
23 |
24 | //! Project version string for ViaSwiftUtils iOS.
25 | FOUNDATION_EXPORT const unsigned char ViaSwiftUtils_iOSVersionString[];
26 |
27 | // In this header, you should import all the public headers of your framework using statements like #import
28 |
29 | //#import
30 |
--------------------------------------------------------------------------------
/Sources/ViaSwiftUtils/Foundation/CGPoint+Operators.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CGPoint+Operators.swift
3 | // ViaSwiftUtils
4 | //
5 | // Copyright 2017 Viacom, Inc.
6 | //
7 | // Licensed under the Apache License, Version 2.0 (the "License");
8 | // you may not use this file except in compliance with the License.
9 | // You may obtain a copy of the License at
10 | //
11 | // http://www.apache.org/licenses/LICENSE-2.0
12 | //
13 | // Unless required by applicable law or agreed to in writing, software
14 | // distributed under the License is distributed on an "AS IS" BASIS,
15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | // See the License for the specific language governing permissions and
17 | // limitations under the License.
18 |
19 | #if os(OSX) || os(iOS) || os(tvOS) || os(watchOS)
20 | import CoreGraphics
21 | #endif
22 | import Foundation
23 |
24 | public extension CGPoint {
25 | /// Overloads + operator for two CGPoints addition
26 | ///
27 | /// - parameter lhs: as lef hand side parameter - CGPoint type
28 | /// - parameter rhs: as right hand side parameter - CGPoint type
29 | ///
30 | /// - returns: new CGPoint calculated from adding two given points
31 | static func + (lhs: CGPoint, rhs: CGPoint) -> CGPoint {
32 | return self.init(x: lhs.x + rhs.x, y: lhs.y + rhs.y)
33 | }
34 |
35 | /// Overloads - operator for two CGPoints substraction
36 | ///
37 | /// - parameter lhs: as lef hand side parameter - CGPoint type
38 | /// - parameter rhs: as right hand side parameter - CGPoint type
39 | ///
40 | /// - returns: new CGPoint calculated from substractiong two given points
41 | static func - (lhs: CGPoint, rhs: CGPoint) -> CGPoint {
42 | return self.init(x: lhs.x - rhs.x, y: lhs.y - rhs.y)
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/Sources/ViaSwiftUtils/Foundation/CGRect+AspectRatio.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CGRect+AspectRatio.swift
3 | // ViaSwiftUtils
4 | //
5 | // Copyright 2017 Viacom, Inc.
6 | //
7 | // Licensed under the Apache License, Version 2.0 (the "License");
8 | // you may not use this file except in compliance with the License.
9 | // You may obtain a copy of the License at
10 | //
11 | // http://www.apache.org/licenses/LICENSE-2.0
12 | //
13 | // Unless required by applicable law or agreed to in writing, software
14 | // distributed under the License is distributed on an "AS IS" BASIS,
15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | // See the License for the specific language governing permissions and
17 | // limitations under the License.
18 |
19 | // swiftlint:disable identifier_name
20 |
21 | #if os(OSX) || os(iOS) || os(tvOS) || os(watchOS)
22 | import CoreGraphics
23 | #endif
24 | import Foundation
25 |
26 | public extension CGRect {
27 |
28 | ///aspect ratio of the rect, i.e. width/height. For a height of 0 the aspect ratio is 0
29 | var aspectRatio: CGFloat {
30 | guard self.size.height > 0 else { return 0 }
31 | return self.size.width / self.size.height
32 | }
33 |
34 | /// linear combination of the receiver with otherRect
35 | /// - parameter otherRect: The other rect to which linearly combine the receiver
36 | /// - parameter value: linear factor, clamped to [0,1]
37 | /// - returns: A new CGRect that represents the linear combination
38 | func linearCombined(with otherRect: CGRect, by value: CGFloat) -> CGRect {
39 | let minMaxValue = min(1.0, max(0.0, value))
40 | let x = (1 - minMaxValue) * self.origin.x + minMaxValue * otherRect.origin.x
41 | let y = (1 - minMaxValue) * self.origin.y + minMaxValue * otherRect.origin.y
42 | let width = (1 - minMaxValue) * self.size.width + minMaxValue * otherRect.size.width
43 | let height = (1 - minMaxValue) * self.size.height + minMaxValue * otherRect.size.height
44 |
45 | return CGRect(origin: CGPoint(x: x, y: y), size: CGSize(width: width, height: height))
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/Sources/ViaSwiftUtils/Foundation/CountableRange+Random.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Range+Random.swift
3 | // ViaSwiftUtils
4 | //
5 | // Copyright 2017 Viacom, Inc.
6 | //
7 | // Licensed under the Apache License, Version 2.0 (the "License");
8 | // you may not use this file except in compliance with the License.
9 | // You may obtain a copy of the License at
10 | //
11 | // http://www.apache.org/licenses/LICENSE-2.0
12 | //
13 | // Unless required by applicable law or agreed to in writing, software
14 | // distributed under the License is distributed on an "AS IS" BASIS,
15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | // See the License for the specific language governing permissions and
17 | // limitations under the License.
18 |
19 | import Foundation
20 |
21 | public extension CountableRange {
22 |
23 | var arc4random: Bound {
24 | return lowerBound.advanced(by: Bound.Stride.arc4random_uniform(numericCast(count)))
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Sources/ViaSwiftUtils/Foundation/Date+ComponentAccessors.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Date+ComponentAccessors.swift
3 | // ViaSwiftUtils
4 | //
5 | // Copyright 2017 Viacom, Inc.
6 | //
7 | // Licensed under the Apache License, Version 2.0 (the "License");
8 | // you may not use this file except in compliance with the License.
9 | // You may obtain a copy of the License at
10 | //
11 | // http://www.apache.org/licenses/LICENSE-2.0
12 | //
13 | // Unless required by applicable law or agreed to in writing, software
14 | // distributed under the License is distributed on an "AS IS" BASIS,
15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | // See the License for the specific language governing permissions and
17 | // limitations under the License.
18 |
19 | import Foundation
20 |
21 | public extension Date {
22 |
23 | /// returns the hour of the receiver 'NSDate'
24 | var hourOfDay: Int {
25 | return Calendar.current.component(.hour, from: self)
26 | }
27 |
28 | /// returns the day of the week of the receiver 'NSDate'
29 | var dayOfWeek: Int {
30 | return Calendar.current.component(.weekday, from: self)
31 | }
32 |
33 | /// returns the year of the receiver 'NSDate' as Int anno domini
34 | var year: Int {
35 | return Calendar.current.component(.year, from: self)
36 | }
37 |
38 | /// returns the year of the receiver NSDate as localized String anno domini and a fixed dateFormat
39 | var localizedYear: String {
40 | let formatter = DateFormatter()
41 | formatter.dateFormat = "y"
42 | return formatter.string(from: self)
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/Sources/ViaSwiftUtils/Foundation/Date+TimesBetweenDates.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NSDate+TimesBetweenDates.swift
3 | // ViaSwiftUtils
4 | //
5 | // Copyright 2017 Viacom, Inc.
6 | //
7 | // Licensed under the Apache License, Version 2.0 (the "License");
8 | // you may not use this file except in compliance with the License.
9 | // You may obtain a copy of the License at
10 | //
11 | // http://www.apache.org/licenses/LICENSE-2.0
12 | //
13 | // Unless required by applicable law or agreed to in writing, software
14 | // distributed under the License is distributed on an "AS IS" BASIS,
15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | // See the License for the specific language governing permissions and
17 | // limitations under the License.
18 |
19 | import Foundation
20 |
21 | public extension Date {
22 |
23 | /// returns the days from the receiver `Date` to the parameter
24 | /// - parameter date: the date to compare too
25 | /// - returns: the days between the two dates as Int
26 | func days(to date: Date) -> Int? {
27 | let calendar = Calendar.current
28 | let components = calendar.dateComponents([.day], from: self, to: date)
29 | return components.day
30 | }
31 |
32 | /// returns the minutes from the receiver `Date` to the parameter
33 | /// - parameter date: the date to compare too
34 | /// - returns: the minutes between the two dates as Int
35 | func minutes(to date: Date) -> Int? {
36 | let calendar = Calendar.current
37 | let components = calendar.dateComponents([.minute], from: self, to: date)
38 | return components.minute
39 | }
40 |
41 | /// returns the seconds from the receiver `Date` to the parameter
42 | /// - parameter date: the date to compare too
43 | /// - returns: the seconds between the two dates as Int
44 | func seconds(to date: Date) -> Int? {
45 | let calendar = Calendar.current
46 | let components = calendar.dateComponents([.second], from: self, to: date)
47 | return components.second
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Sources/ViaSwiftUtils/Foundation/Dictionary+MapValues.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Dictionary+MapValues.swift
3 | // ViaSwiftUtils
4 | //
5 | // Copyright 2017 Viacom, Inc.
6 | //
7 | // Licensed under the Apache License, Version 2.0 (the "License");
8 | // you may not use this file except in compliance with the License.
9 | // You may obtain a copy of the License at
10 | //
11 | // http://www.apache.org/licenses/LICENSE-2.0
12 | //
13 | // Unless required by applicable law or agreed to in writing, software
14 | // distributed under the License is distributed on an "AS IS" BASIS,
15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | // See the License for the specific language governing permissions and
17 | // limitations under the License.
18 |
19 | import Foundation
20 |
21 | public extension Dictionary {
22 |
23 | /// Merges the Dictionary with a Sequence of (Key, Value)
24 | /// - parameter other: The Sequence that is merged in
25 | mutating func merge(_ other: S) where S.Iterator.Element == Element {
26 | for (key, value) in other {
27 | self[key] = value
28 | }
29 | }
30 |
31 | /// Initializes a Dictionary with a Sequence of (Key, Value)
32 | /// - parameter sequence: The Sequence of elements that this Dictionary will contain after initialization
33 | init(_ sequence: S) where S.Iterator.Element == Element {
34 | self = [:]
35 | self.merge(sequence)
36 | }
37 |
38 | /// Maps the values of a dictionary into new values, creating a new dictionary with the same keys
39 | /// - parameter transform: The transformation the values will be going through
40 | /// - returns: new dictionary with the mapped values but the same keys
41 | func mapValues(_ transform: (Value) -> NewValue) -> [Key: NewValue] {
42 | return [Key: NewValue](map { key, value in
43 | (key, transform(value))
44 | })
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/Sources/ViaSwiftUtils/Foundation/ForceUnwrappingOperators.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ForceUnwrappingOperators.swift
3 | // ViaSwiftUtils
4 | //
5 | // Copyright 2017 Viacom, Inc.
6 | //
7 | // Licensed under the Apache License, Version 2.0 (the "License");
8 | // you may not use this file except in compliance with the License.
9 | // You may obtain a copy of the License at
10 | //
11 | // http://www.apache.org/licenses/LICENSE-2.0
12 | //
13 | // Unless required by applicable law or agreed to in writing, software
14 | // distributed under the License is distributed on an "AS IS" BASIS,
15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | // See the License for the specific language governing permissions and
17 | // limitations under the License.
18 |
19 | import Foundation
20 |
21 | infix operator !!
22 |
23 | /// Use like this:
24 | ///
25 | /// `let s = "foo"`
26 | ///
27 | /// `i = Int(s) !! "Expecting integer, got \(s)"`
28 | ///
29 | /// - Parameters:
30 | /// - wrapped: The Optional(T) value that will be unwrapped
31 | /// - failureText: an autoclosure that will be printed in the case of failure
32 | /// - Returns: The Non-Optional value of Type T
33 | /// - Note:
34 | /// [chapter 'When to Force Unwrap' from Advanced Swift](https://www.objc.io/books/advanced-swift/)
35 |
36 | public func !! (wrapped: T?, failureText: @autoclosure () -> String) -> T {
37 | // swiftlint:disable:next identifier_name
38 | if let x = wrapped { return x }
39 | fatalError(failureText())
40 | }
41 |
42 | infix operator !?
43 |
44 | /// Use like this:
45 | ///
46 | /// `let i = Int(s) !? "Expecting integer, got \(s)"`
47 | ///
48 | /// - Parameters:
49 | /// - wrapped: The Optional(T) value that will be unwrapped
50 | /// - failureText: an autoclosure that will be printed in the case of failure
51 | /// - Returns: The Non-Optional value of Type T
52 | /// - Note:
53 | /// [chapter 'When to Force Unwrap' from Advanced Swift](https://www.objc.io/books/advanced-swift/)
54 | public func !? (wrapped: T?, failureText: @autoclosure () -> String) -> T {
55 | assert(wrapped != nil, failureText())
56 | return wrapped ?? 0
57 | }
58 |
59 | /// use like this:
60 | ///
61 | /// `let i = Array(s) !? "Expecting array, got \(s)"`
62 | ///
63 | /// - Parameters:
64 | /// - wrapped: The Optional(T) value that will be unwrapped
65 | /// - failureText: an autoclosure that will be printed in the case of failure
66 | /// - Returns: The Non-Optional value of Type T
67 | /// - Note:
68 | /// [chapter 'When to Force Unwrap' from Advanced Swift](https://www.objc.io/books/advanced-swift/)
69 | public func !? (wrapped: T?, failureText: @autoclosure () -> String) -> T {
70 | assert(wrapped != nil, failureText())
71 | return wrapped ?? []
72 | }
73 |
74 | /// use like this:
75 | ///
76 | /// `let i = String(s) !? "Expecting string, got \(s)"`
77 | ///
78 | /// - Parameters:
79 | /// - wrapped: The Optional(T) value that will be unwrapped
80 | /// - failureText: an autoclosure that will be printed in the case of failure
81 | /// - Returns: The Non-Optional value of Type T
82 | /// - Note:
83 | /// [chapter 'When to Force Unwrap' from Advanced Swift](https://www.objc.io/books/advanced-swift/)
84 | public func !? (wrapped: T?, failureText: @autoclosure () -> String) -> T {
85 | assert(wrapped != nil, failureText())
86 | return wrapped ?? ""
87 | }
88 |
89 | /// for arbitraty types, with default value. Used in this way:
90 | ///
91 | /// `Int(s) !? (5, "Expected Integer")`
92 | ///
93 | /// - Parameters:
94 | /// - wrapped: The Optional(T) value that will be unwrapped
95 | /// - nilDefault: an tuple (value, text) containing a default value and an error Text
96 | /// - Returns: The Non-Optional value of Type T
97 | /// - Note:
98 | /// [chapter 'When to Force Unwrap' from Advanced Swift](https://www.objc.io/books/advanced-swift/)
99 | public func !? (wrapped: T?, nilDefault: @autoclosure () -> (value: T, text: String)) -> T {
100 | assert(wrapped != nil, nilDefault().text)
101 | return wrapped ?? nilDefault().value
102 | }
103 |
104 | /// for void methods optional chains, like in
105 | ///
106 | /// `var output: String? = nil`
107 | ///
108 | /// `output?.write("something") !? "Wasn't expecting chained nil here"`
109 | ///
110 | /// - Parameters:
111 | /// - wrapped: The Optional(T) value that will be unwrapped
112 | /// - failureText: an autoclosure that will be printed in the case of failure
113 | /// - Returns: The Non-Optional value of Type T
114 | /// - Note:
115 | /// [chapter 'When to Force Unwrap' from Advanced Swift](https://www.objc.io/books/advanced-swift/)
116 | public func !? (wrapped: ()?, failureText: @autoclosure () -> String) {
117 | assert(wrapped != nil, failureText())
118 | }
119 |
--------------------------------------------------------------------------------
/Sources/ViaSwiftUtils/Foundation/MutableCollection+Shuffle.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MutableCollection+Shuffle.swift
3 | // ViaSwiftUtils
4 | //
5 | // Copyright 2017 Viacom, Inc.
6 | //
7 | // Licensed under the Apache License, Version 2.0 (the "License");
8 | // you may not use this file except in compliance with the License.
9 | // You may obtain a copy of the License at
10 | //
11 | // http://www.apache.org/licenses/LICENSE-2.0
12 | //
13 | // Unless required by applicable law or agreed to in writing, software
14 | // distributed under the License is distributed on an "AS IS" BASIS,
15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | // See the License for the specific language governing permissions and
17 | // limitations under the License.
18 |
19 | import Foundation
20 |
21 | public extension MutableCollection where Index == Int {
22 |
23 | /// implements [FisherYates](https://en.wikipedia.org/wiki/Fisher–Yates_shuffle) to shuffle elements in place
24 | mutating func shuffleInPlace() {
25 | if count <= 1 { return }
26 |
27 | for index in indices.dropLast() {
28 | let randomIndex = (index..(_ observer: O) where O.Event == Event
24 | }
25 |
--------------------------------------------------------------------------------
/Sources/ViaSwiftUtils/Foundation/ObserverType.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ObserverType.swift
3 | // ViaSwiftUtils
4 | //
5 | // Copyright 2017 Viacom, Inc.
6 | //
7 | // Licensed under the Apache License, Version 2.0 (the "License");
8 | // you may not use this file except in compliance with the License.
9 | // You may obtain a copy of the License at
10 | //
11 | // http://www.apache.org/licenses/LICENSE-2.0
12 | //
13 | // Unless required by applicable law or agreed to in writing, software
14 | // distributed under the License is distributed on an "AS IS" BASIS,
15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | // See the License for the specific language governing permissions and
17 | // limitations under the License.
18 |
19 | import Foundation
20 |
21 | public protocol ObserverType {
22 | associatedtype Event
23 |
24 | func receive(_ event: Event)
25 | }
26 |
--------------------------------------------------------------------------------
/Sources/ViaSwiftUtils/Foundation/RandomAccessCollection+SafeAccess.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Array+SafeAccess.swift
3 | // ViaSwiftUtils
4 | //
5 | // Copyright 2017 Viacom, Inc.
6 | //
7 | // Licensed under the Apache License, Version 2.0 (the "License");
8 | // you may not use this file except in compliance with the License.
9 | // You may obtain a copy of the License at
10 | //
11 | // http://www.apache.org/licenses/LICENSE-2.0
12 | //
13 | // Unless required by applicable law or agreed to in writing, software
14 | // distributed under the License is distributed on an "AS IS" BASIS,
15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | // See the License for the specific language governing permissions and
17 | // limitations under the License.
18 |
19 | import Foundation
20 |
21 | public extension RandomAccessCollection {
22 |
23 | /// Accesses a `RandomAccessCollection`, while being safe from out of bounds errors
24 | /// Important: Arbitrarily subscripting Arrays in Swift is discouraged,
25 | /// when practical, favor iteration like for-in, `map`, `first` etc
26 | /// - parameter index: The Index at which the access happens
27 | /// - returns: the element at `index`, if out of bounds returns nil
28 | subscript (safe index: Self.Index) -> Self.Iterator.Element? {
29 | return index >= self.startIndex && index < self.endIndex ? self[index] : nil
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/Sources/ViaSwiftUtils/Foundation/Sequence+Helpers.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Sequence+Helpers.swift
3 | // ViaSwiftUtils
4 | //
5 | // Copyright 2017 Viacom, Inc.
6 | //
7 | // Licensed under the Apache License, Version 2.0 (the "License");
8 | // you may not use this file except in compliance with the License.
9 | // You may obtain a copy of the License at
10 | //
11 | // http://www.apache.org/licenses/LICENSE-2.0
12 | //
13 | // Unless required by applicable law or agreed to in writing, software
14 | // distributed under the License is distributed on an "AS IS" BASIS,
15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | // See the License for the specific language governing permissions and
17 | // limitations under the License.
18 |
19 | import Foundation
20 |
21 | public extension Sequence where Iterator.Element: Hashable {
22 |
23 | /// Creates an array of unique elements from the elements of the collection
24 | /// - returns: an array containing the unique elements
25 | func unique() -> [Iterator.Element] {
26 | var seen: Set = []
27 | return filter { element -> Bool in
28 | if seen.contains(element) {
29 | return false
30 | }
31 |
32 | seen.insert(element)
33 | return true
34 | }
35 | }
36 |
37 | }
38 |
39 | public extension Sequence {
40 |
41 | /// Logical method that returns true if at least one element fits the predicate
42 | /// - returns: a boolean indication whether at least one element fits the predicate
43 | func any(_ predicate: (Iterator.Element) throws -> Bool) rethrows -> Bool {
44 | for element in self where try predicate(element) {
45 | return true
46 | }
47 | return false
48 | }
49 |
50 | /// Logical method that returns true if all elements fit the predicate
51 | /// - returns: a boolean indication whether all elements fit the predicate
52 | func all(_ predicate: (Iterator.Element) throws -> Bool) rethrows -> Bool {
53 | for element in self where try !predicate(element) {
54 | return false
55 | }
56 | return true
57 | }
58 |
59 | /// Logical method that returns true if none of the elements fit the predicate
60 | /// - returns: a boolean indication whether none of the elements fit the predicate
61 | func none(_ predicate: (Iterator.Element) throws -> Bool) rethrows -> Bool {
62 | return try all { try !predicate($0) }
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/Sources/ViaSwiftUtils/Foundation/SignedInteger+Random.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SignedInteger+Random.swift
3 | // ViaSwiftUtils
4 | //
5 | // Copyright 2017 Viacom, Inc.
6 | //
7 | // Licensed under the Apache License, Version 2.0 (the "License");
8 | // you may not use this file except in compliance with the License.
9 | // You may obtain a copy of the License at
10 | //
11 | // http://www.apache.org/licenses/LICENSE-2.0
12 | //
13 | // Unless required by applicable law or agreed to in writing, software
14 | // distributed under the License is distributed on an "AS IS" BASIS,
15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | // See the License for the specific language governing permissions and
17 | // limitations under the License.
18 |
19 | import Foundation
20 |
21 | public extension SignedInteger {
22 |
23 | static func arc4random_uniform(_ upperBound: Self) -> Self {
24 | precondition(upperBound > 0 && Int64(upperBound) < UInt32.max,
25 | "arc4random_uniform only callable up to \(UInt32.max)")
26 | #if os(OSX) || os(iOS) || os(tvOS) || os(watchOS)
27 | return numericCast(Darwin.arc4random_uniform(numericCast(upperBound)))
28 | #elseif os(Linux) || CYGWIN
29 | srandom(UInt32(time(nil)))
30 | return numericCast(UInt32(random() % numericCast(upperBound)))
31 | #endif
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Sources/ViaSwiftUtils/Foundation/TimeInterval+Converter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TimeInterval+Converter.swift
3 | // ViaSwiftUtils
4 | //
5 | // Copyright 2017 Viacom, Inc.
6 | //
7 | // Licensed under the Apache License, Version 2.0 (the "License");
8 | // you may not use this file except in compliance with the License.
9 | // You may obtain a copy of the License at
10 | //
11 | // http://www.apache.org/licenses/LICENSE-2.0
12 | //
13 | // Unless required by applicable law or agreed to in writing, software
14 | // distributed under the License is distributed on an "AS IS" BASIS,
15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | // See the License for the specific language governing permissions and
17 | // limitations under the License.
18 |
19 | import Foundation
20 |
21 | extension TimeInterval {
22 |
23 | private static let formatter = DateFormatter()
24 |
25 | /// Returns a string representation of the time interval representing video or music playtime.
26 | /// In minutes and seconds, in `en_US` output is for example "4:36" for 4minutes and 36secs.
27 | /// uses same formatting as Apple Music app across all localizations
28 | public var asMediaDuration: String {
29 | let components = DateComponentsFormatter()
30 | components.zeroFormattingBehavior = .pad
31 | components.allowedUnits = [.minute, .second]
32 | components.unitsStyle = .positional
33 | components.calendar = Locale.current.calendar
34 |
35 | return components.string(from: self) ?? "?"
36 | }
37 |
38 | /// [Data Formatting Guide]: https://developer.apple.com/library/prerelease/content/documentation/Cocoa/Conceptual/DataFormatting/DataFormatting.html#//apple_ref/doc/uid/10000029i
39 | ///
40 | /// Convenience method returns a string representation of the time interval initialized by using a given format string as a template
41 | /// relative to 00:00:00 UTC on 1 January 1970.
42 | ///
43 | /// - Warning: For user facing strings use of `dateStyle`, `timeStyle` or `dateFormat(fromTemplate:options:locale:)`
44 | /// should be preferred over this method.
45 | ///
46 | /// See [Data Formatting Guide] for a list of the conversion specifiers permitted in date format strings.
47 | ///
48 | /// - Parameter format: The output format of string.
49 | /// - Parameter locale: (optional) locale to use for the string conversion. Defaults to en_US_POSIX.
50 | public func string(withFormat format: String, locale: Locale = Locale(identifier: "en_US_POSIX")) -> String {
51 | let date = Date(timeIntervalSince1970: self)
52 | TimeInterval.formatter.dateFormat = format
53 | TimeInterval.formatter.locale = locale
54 |
55 | return String(TimeInterval.formatter.string(from: date))
56 | }
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/Sources/ViaSwiftUtils/Foundation/TimeInterval+Intervals.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TimeInterval+Intervals.swift
3 | // ViaSwiftUtils
4 | //
5 | // Copyright 2017 Viacom, Inc.
6 | //
7 | // Licensed under the Apache License, Version 2.0 (the "License");
8 | // you may not use this file except in compliance with the License.
9 | // You may obtain a copy of the License at
10 | //
11 | // http://www.apache.org/licenses/LICENSE-2.0
12 | //
13 | // Unless required by applicable law or agreed to in writing, software
14 | // distributed under the License is distributed on an "AS IS" BASIS,
15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | // See the License for the specific language governing permissions and
17 | // limitations under the License.
18 |
19 | import Foundation
20 |
21 | public extension TimeInterval {
22 | static let second: TimeInterval = 1
23 | static let minute: TimeInterval = 60 * second
24 | static let hour: TimeInterval = 60 * minute
25 | static let day: TimeInterval = 24 * hour
26 | static let week: TimeInterval = 7 * day
27 | static let year: TimeInterval = 365 * day
28 | }
29 |
--------------------------------------------------------------------------------
/Sources/ViaSwiftUtils/UIKit/Bundle+ApplicationInfo.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NSBundle+Version.swift
3 | // ViaSwiftUtils
4 | //
5 | // Copyright 2017 Viacom, Inc.
6 | //
7 | // Licensed under the Apache License, Version 2.0 (the "License");
8 | // you may not use this file except in compliance with the License.
9 | // You may obtain a copy of the License at
10 | //
11 | // http://www.apache.org/licenses/LICENSE-2.0
12 | //
13 | // Unless required by applicable law or agreed to in writing, software
14 | // distributed under the License is distributed on an "AS IS" BASIS,
15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | // See the License for the specific language governing permissions and
17 | // limitations under the License.
18 |
19 | import Foundation
20 |
21 | public extension Bundle {
22 |
23 | /// fetches the CFBundleShortVersionString from the NSBundle.mainBundle
24 | /// - returns: the version as a String
25 | static var applicationVersion: String? {
26 | return Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String
27 | }
28 |
29 | /// fetches the CFBundleDisplayName from the NSBundle.mainBundle
30 | /// - returns: the version as a String
31 | static var applicationName: String? {
32 | return Bundle.main.object(forInfoDictionaryKey: "CFBundleDisplayName") as? String
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Sources/ViaSwiftUtils/UIKit/CGVector+Operators.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CGVector+Operators.swift
3 | // ViaSwiftUtils
4 | //
5 | // Copyright 2017 Viacom, Inc.
6 | //
7 | // Licensed under the Apache License, Version 2.0 (the "License");
8 | // you may not use this file except in compliance with the License.
9 | // You may obtain a copy of the License at
10 | //
11 | // http://www.apache.org/licenses/LICENSE-2.0
12 | //
13 | // Unless required by applicable law or agreed to in writing, software
14 | // distributed under the License is distributed on an "AS IS" BASIS,
15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | // See the License for the specific language governing permissions and
17 | // limitations under the License.
18 |
19 | import CoreGraphics
20 | import Foundation
21 |
22 | public extension CGVector {
23 | /// Overloads + operator for two CGVectors addition
24 | ///
25 | /// - parameter lhs: as lef hand side parameter - CGVector type
26 | /// - parameter rhs: as right hand side parameter - CGVector type
27 | ///
28 | /// - returns: new CGVector calculated from adding two given vectors
29 | static func + (lhs: CGVector, rhs: CGVector) -> CGVector {
30 | return self.init(dx: lhs.dx + rhs.dx, dy: lhs.dy + rhs.dy)
31 | }
32 |
33 | /// Overloads - operator for two CGVectors substraction
34 | ///
35 | /// - parameter lhs: as lef hand side parameter - CGVector type
36 | /// - parameter rhs: as right hand side parameter - CGVector type
37 | ///
38 | /// - returns: new CGVector calculated from substractiong two given vectors
39 | static func - (lhs: CGVector, rhs: CGVector) -> CGVector {
40 | return self.init(dx: lhs.dx - rhs.dx, dy: lhs.dy - rhs.dy)
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Sources/ViaSwiftUtils/UIKit/NibView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NibView.swift
3 | // ViaSwiftUtils
4 | //
5 | // Copyright 2017 Viacom, Inc.
6 | //
7 | // Licensed under the Apache License, Version 2.0 (the "License");
8 | // you may not use this file except in compliance with the License.
9 | // You may obtain a copy of the License at
10 | //
11 | // http://www.apache.org/licenses/LICENSE-2.0
12 | //
13 | // Unless required by applicable law or agreed to in writing, software
14 | // distributed under the License is distributed on an "AS IS" BASIS,
15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | // See the License for the specific language governing permissions and
17 | // limitations under the License.
18 |
19 | import UIKit
20 |
21 | // MARK: - NibView Class
22 |
23 | /// This class is intended to be subclassed. If you provide a Xib-file inside the same Bundle the subclass
24 | /// lives in, this class will automatically find the layout file, load subviews from the xib and connect to
25 | /// the respective IBOutlets. The class is not intended to be used as is.
26 | open class NibView: UIView {
27 |
28 | private var didEncode: Bool = false
29 | private let didEncodeKey = "didEncodeKey"
30 |
31 | /// Designated initializer for UIView instance that use the nib file
32 | ///
33 | /// - parameter coder: The instance of class NSCoder
34 | ///
35 | public required init?(coder aDecoder: NSCoder) {
36 | super.init(coder: aDecoder)
37 | self.didEncode = aDecoder.decodeBool(forKey: didEncodeKey)
38 | if didEncode == false {
39 | self.loadAssociatedNibView()
40 | }
41 | }
42 |
43 | /// Designated initializer for UIView instance that uses the nib file
44 | ///
45 | /// - parameter frame: The frame of initialized instance
46 | ///
47 | override init(frame: CGRect) {
48 | super.init(frame: frame)
49 | self.loadAssociatedNibView()
50 | }
51 |
52 | open override func encode(with aCoder: NSCoder) {
53 | super.encode(with: aCoder)
54 | didEncode = true
55 | aCoder.encode(didEncode, forKey: didEncodeKey)
56 | }
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/Sources/ViaSwiftUtils/UIKit/String+Localized.swift:
--------------------------------------------------------------------------------
1 | //
2 | // String+Localized.swift
3 | // ViaSwiftUtils
4 | //
5 | // Copyright 2017 Viacom, Inc.
6 | //
7 | // Licensed under the Apache License, Version 2.0 (the "License");
8 | // you may not use this file except in compliance with the License.
9 | // You may obtain a copy of the License at
10 | //
11 | // http://www.apache.org/licenses/LICENSE-2.0
12 | //
13 | // Unless required by applicable law or agreed to in writing, software
14 | // distributed under the License is distributed on an "AS IS" BASIS,
15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | // See the License for the specific language governing permissions and
17 | // limitations under the License.
18 |
19 | import Foundation
20 |
21 | public extension String {
22 |
23 | /// localized version of this string using it as a key in Localizable.strings in the main Bundle
24 | var localized: String {
25 | return NSLocalizedString(self, tableName: nil, bundle: Bundle.main, value: "", comment: "")
26 | }
27 |
28 | /// localized uppercase version of this string, with newline characters escaped
29 | var customLocalizedUppercaseString: String {
30 | return localizedUppercase.replacingOccurrences(of: "\\N", with: "\n")
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/Sources/ViaSwiftUtils/UIKit/String+Words.swift:
--------------------------------------------------------------------------------
1 | //
2 | // String+Words.swift
3 | // ViaSwiftUtils
4 | //
5 | // Copyright 2017 Viacom, Inc.
6 | //
7 | // Licensed under the Apache License, Version 2.0 (the "License");
8 | // you may not use this file except in compliance with the License.
9 | // You may obtain a copy of the License at
10 | //
11 | // http://www.apache.org/licenses/LICENSE-2.0
12 | //
13 | // Unless required by applicable law or agreed to in writing, software
14 | // distributed under the License is distributed on an "AS IS" BASIS,
15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | // See the License for the specific language governing permissions and
17 | // limitations under the License.
18 |
19 | import Foundation
20 |
21 | public extension String {
22 |
23 | /// calculates the longest word in the sentence
24 | ///
25 | /// - returns: the longest word amongst source string sentence
26 | func longestWord() -> String {
27 | let range = startIndex.. newLongestWord.count ? word : newLongestWord
33 | }
34 | }
35 |
36 | return newLongestWord
37 | }
38 |
39 | /// counts all the words present in source sentence
40 | ///
41 | /// - returns: words count in a sentence
42 | func wordCount() -> Int {
43 | let range = startIndex.. Bool {
57 | return wordCount() == 1
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/Sources/ViaSwiftUtils/UIKit/UIButton+States.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIButton+States.swift
3 | // ViaSwiftUtils
4 | //
5 | // Copyright 2017 Viacom, Inc.
6 | //
7 | // Licensed under the Apache License, Version 2.0 (the "License");
8 | // you may not use this file except in compliance with the License.
9 | // You may obtain a copy of the License at
10 | //
11 | // http://www.apache.org/licenses/LICENSE-2.0
12 | //
13 | // Unless required by applicable law or agreed to in writing, software
14 | // distributed under the License is distributed on an "AS IS" BASIS,
15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | // See the License for the specific language governing permissions and
17 | // limitations under the License.
18 |
19 | import UIKit
20 |
21 | public extension UIButton {
22 |
23 | /// Convenience method to set a title for all possible states of the receiver
24 | /// - parameter title: The title being set
25 | func setTitleForAllStates(_ title: String?) {
26 | for controlstate in UIControl.State.allValues {
27 | setTitle(title, for: controlstate)
28 | }
29 | }
30 |
31 | /// Convenience method to set a background image for all possible states of the receiver
32 | /// - parameter image: The image being set for all states
33 | func setBackgroundImageForAllStates(_ image: UIImage?) {
34 | for controlstate in UIControl.State.allValues {
35 | setBackgroundImage(image, for: controlstate)
36 | }
37 | }
38 |
39 | /// Convenience method to set an image for all possible states of the receiver
40 | /// - parameter image: The image being set for all states
41 | func setImageForAllStates(_ image: UIImage?) {
42 | for controlstate in UIControl.State.allValues {
43 | setImage(image, for: controlstate)
44 | }
45 | }
46 |
47 | /// Convenience method to set a title color for all possible states of the receiver
48 | /// - parameter color: The color being set for all states
49 | func setTitleColorForAllStates(_ color: UIColor?) {
50 | for controlstate in UIControl.State.allValues {
51 | setTitleColor(color, for: controlstate)
52 | }
53 | }
54 |
55 | /// Convenience method to set images for all possible states of the receiver
56 | ///
57 | /// - parameter normal: The image for state .normal
58 | /// - parameter highlighted: The image for state .highlighted
59 | /// - parameter selected: The image for state .selected
60 | /// - parameter climax: The image for state [.selected, .highlighted]
61 | func setImagesForStates(normal: UIImage? = nil, highlighted: UIImage? = nil, selected: UIImage? = nil, climax: UIImage? = nil) {
62 | self.setImage(normal, for: .normal)
63 | self.setImage(highlighted, for: .highlighted)
64 | self.setImage(selected, for: .selected)
65 | self.setImage(climax, for: [.selected, .highlighted])
66 | }
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/Sources/ViaSwiftUtils/UIKit/UIControl+States.swift:
--------------------------------------------------------------------------------
1 | //swiftlint:disable:this file_name
2 | //
3 | // UIControl+States.swift
4 | // ViaSwiftUtils
5 | //
6 | // Copyright 2017 Viacom, Inc.
7 | //
8 | // Licensed under the Apache License, Version 2.0 (the "License");
9 | // you may not use this file except in compliance with the License.
10 | // You may obtain a copy of the License at
11 | //
12 | // http://www.apache.org/licenses/LICENSE-2.0
13 | //
14 | // Unless required by applicable law or agreed to in writing, software
15 | // distributed under the License is distributed on an "AS IS" BASIS,
16 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | // See the License for the specific language governing permissions and
18 | // limitations under the License.
19 |
20 | import UIKit
21 |
22 | public extension UIControl.State {
23 |
24 | /// array of all values of UIControlState
25 | static var allValues: [UIControl.State] {
26 | return [.normal, .highlighted, .selected, .disabled, .focused, .application, .reserved]
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Sources/ViaSwiftUtils/UIKit/UIImage+Color.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIImage+Color.swift
3 | // ViaSwiftUtils
4 | //
5 | // Copyright 2017 Viacom, Inc.
6 | //
7 | // Licensed under the Apache License, Version 2.0 (the "License");
8 | // you may not use this file except in compliance with the License.
9 | // You may obtain a copy of the License at
10 | //
11 | // http://www.apache.org/licenses/LICENSE-2.0
12 | //
13 | // Unless required by applicable law or agreed to in writing, software
14 | // distributed under the License is distributed on an "AS IS" BASIS,
15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | // See the License for the specific language governing permissions and
17 | // limitations under the License.
18 |
19 | import UIKit
20 |
21 | public extension UIImage {
22 |
23 | /// Convenience initializer to create an image with a uniform color
24 | ///
25 | /// - parameter color: The color of the image created
26 | /// - parameter size: The size of the image created
27 | convenience init?(color: UIColor?, size: CGSize = CGSize(width: 1.0, height: 1.0)) {
28 | defer {
29 | UIGraphicsEndImageContext()
30 | }
31 | let rect = CGRect(x: 0, y: 0, width: size.width, height: size.height)
32 | UIGraphicsBeginImageContextWithOptions(size, false, 0)
33 | color?.setFill()
34 | UIRectFill(rect)
35 | UIGraphicsGetImageFromCurrentImageContext()
36 | guard let imageRef = UIGraphicsGetImageFromCurrentImageContext()?.cgImage else {
37 | return nil
38 | }
39 | self.init(cgImage: imageRef)
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/Sources/ViaSwiftUtils/UIKit/UIImage+Rounding.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIImageView+Rounding.swift
3 | // ViaSwiftUtils
4 | //
5 | // Copyright 2017 Viacom, Inc.
6 | //
7 | // Licensed under the Apache License, Version 2.0 (the "License");
8 | // you may not use this file except in compliance with the License.
9 | // You may obtain a copy of the License at
10 | //
11 | // http://www.apache.org/licenses/LICENSE-2.0
12 | //
13 | // Unless required by applicable law or agreed to in writing, software
14 | // distributed under the License is distributed on an "AS IS" BASIS,
15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | // See the License for the specific language governing permissions and
17 | // limitations under the License.
18 |
19 | import UIKit
20 |
21 | public extension UIImage {
22 |
23 | /// returns a rounded corner image, rerendered using the receiver
24 | /// - parameter radius: the radius of the rounded corners
25 | /// - returns: the image created by the method
26 | final func cornersRounded(usingRadius radius: CGFloat) -> UIImage? {
27 | UIGraphicsBeginImageContextWithOptions(size, false, 0)
28 |
29 | guard let context = UIGraphicsGetCurrentContext() else {
30 | print("WARNING: Failed to get current Graphics context")
31 | return nil
32 | }
33 |
34 | let rect = CGRect(x: 0, y: 0, width: size.width, height: size.height)
35 |
36 | context.addPath(UIBezierPath(roundedRect: rect, cornerRadius: radius).cgPath)
37 | context.clip()
38 |
39 | self.draw(in: rect)
40 | let output = UIGraphicsGetImageFromCurrentImageContext()
41 |
42 | UIGraphicsEndImageContext()
43 |
44 | return output
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/Sources/ViaSwiftUtils/UIKit/UIImageView+Rotation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIImageView+ActivityIndicator.swift
3 | // ViaSwiftUtils
4 | //
5 | // Copyright 2017 Viacom, Inc.
6 | //
7 | // Licensed under the Apache License, Version 2.0 (the "License");
8 | // you may not use this file except in compliance with the License.
9 | // You may obtain a copy of the License at
10 | //
11 | // http://www.apache.org/licenses/LICENSE-2.0
12 | //
13 | // Unless required by applicable law or agreed to in writing, software
14 | // distributed under the License is distributed on an "AS IS" BASIS,
15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | // See the License for the specific language governing permissions and
17 | // limitations under the License.
18 |
19 | import UIKit
20 |
21 | enum RotationAnimation {
22 | static let key = "ViaSwiftUtils.SpinAnimation"
23 | }
24 |
25 | public extension UIView {
26 |
27 | enum AnimationDuration {
28 | case slow
29 | case normal
30 | case fast
31 | case custom(time: TimeInterval)
32 |
33 | internal var duration: TimeInterval {
34 | switch self {
35 | case .slow:
36 | return 2.0
37 | case .normal:
38 | return 1.0
39 | case .fast:
40 | return 0.5
41 | case .custom(let time):
42 | return time
43 | }
44 | }
45 | }
46 |
47 | final var isRotating: Bool {
48 | return layer.animation(forKey: RotationAnimation.key) != nil
49 | }
50 |
51 | /// Starts animating the image like an activityIndicator.
52 | /// - parameter duration: an NSTimeInterval duration the animation should take
53 | final func startRotating(_ animationDuration: AnimationDuration = .normal, isRemovedOnCompletion: Bool = true) {
54 | layer.removeAnimation(forKey: RotationAnimation.key)
55 | isHidden = false
56 | let animation = CABasicAnimation(keyPath: "transform.rotation.z")
57 | animation.fromValue = CGFloat(0.0)
58 | animation.toValue = 2 * CGFloat.pi
59 | animation.duration = animationDuration.duration
60 | animation.repeatCount = HUGE
61 | animation.isRemovedOnCompletion = isRemovedOnCompletion
62 | layer.add(animation, forKey: RotationAnimation.key)
63 | }
64 |
65 | /// Stops rotating the image
66 | final func stopRotating() {
67 | layer.removeAnimation(forKey: RotationAnimation.key)
68 | isHidden = true
69 | }
70 | }
71 |
72 | public extension UIImageView {
73 |
74 | /// makes the image of UIImageView AlwaysTemplate and sets the tintColor provided
75 | /// - parameter color: color that is set as a tintColor of the templated image
76 | final func colorize(_ color: UIColor) {
77 | if let image = self.image {
78 | self.image = image.withRenderingMode(.alwaysTemplate)
79 | tintColor = color
80 | }
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/Sources/ViaSwiftUtils/UIKit/UIView+Xib.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIView+Xib.swift
3 | // ViaSwiftUtils
4 | //
5 | // Copyright 2017 Viacom, Inc.
6 | //
7 | // Licensed under the Apache License, Version 2.0 (the "License");
8 | // you may not use this file except in compliance with the License.
9 | // You may obtain a copy of the License at
10 | //
11 | // http://www.apache.org/licenses/LICENSE-2.0
12 | //
13 | // Unless required by applicable law or agreed to in writing, software
14 | // distributed under the License is distributed on an "AS IS" BASIS,
15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | // See the License for the specific language governing permissions and
17 | // limitations under the License.
18 |
19 | import UIKit
20 |
21 | public extension UIView {
22 |
23 | class func loadFromNib(named nibName: String, bundle: Bundle? = nil, owner: AnyObject? = nil) -> UIView? {
24 | let nib = UINib(nibName: nibName, bundle: bundle)
25 | return nib.instantiate(withOwner: owner, options: nil).first as? UIView
26 | }
27 |
28 | /// Find nib instance associated with view, name of UIView instance must be the same as name of UINib instance. The owner of nib's view is 'self'.
29 | internal func loadAssociatedNibView() {
30 | self.loadNibView(self)
31 | }
32 |
33 | /// Find nib instance associated with view, name of UIView instance must be the same as name of UINib instance.
34 | ///
35 | /// - parameter owner: The owner of nib's view
36 | internal func loadNibView(_ owner: AnyObject?) {
37 | let bundle = Bundle(for: type(of: self))
38 | UIView.loadFromNib(named: String(describing: type(of: self)), bundle: bundle, owner: owner).map {
39 | $0.frame = self.bounds
40 | self.addSubview($0)
41 | }
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/Tests/LinuxMain.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | @testable import ViaSwiftUtilsTests
3 |
4 | XCTMain([
5 | testCase(BetterForceUnwrappingTests.allTests),
6 | testCase(CGPointOperatorsTest.allTests),
7 | testCase(CollectionShuffledTest.allTests),
8 | testCase(CGRectTests.allTests),
9 | testCase(SequenceTypeHelperTests.allTests),
10 | testCase(DictionaryMapValuesTests.allTests),
11 | testCase(DateComparableTest.allTests),
12 | testCase(RandomAccessCollectionSafeAccessTests.allTests),
13 | testCase(DateComponentAccessorsTest.allTests),
14 | testCase(DateTimesBetweenTests.allTests)
15 | ])
16 |
--------------------------------------------------------------------------------
/Tests/ViaSwiftUtilsTests/BetterForceUnwrappingTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BetterForceUnwrappingTests.swift
3 | // ViaSwiftUtils
4 | //
5 | // Copyright 2017 Viacom, Inc.
6 | //
7 | // Licensed under the Apache License, Version 2.0 (the "License");
8 | // you may not use this file except in compliance with the License.
9 | // You may obtain a copy of the License at
10 | //
11 | // http://www.apache.org/licenses/LICENSE-2.0
12 | //
13 | // Unless required by applicable law or agreed to in writing, software
14 | // distributed under the License is distributed on an "AS IS" BASIS,
15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | // See the License for the specific language governing permissions and
17 | // limitations under the License.
18 |
19 | @testable import ViaSwiftUtils
20 | import XCTest
21 |
22 | class BetterForceUnwrappingTests: XCTestCase {
23 |
24 | static var allTests = [
25 | ("testForceUnwrapping", testForceUnwrapping),
26 | ("testIntegerConvertible", testIntegerConvertible),
27 | ("testStringConvertible", testStringConvertible),
28 | ("testGeneralConvertible", testGeneralConvertible)
29 | ]
30 |
31 | func testForceUnwrapping() {
32 | // Given
33 | let someURLString = "www.test.com/something"
34 |
35 | // When
36 | // swiftlint:disable:next force_unwrapping
37 | let url = URL(string: someURLString) !! "ERROR: \(someURLString) isn't url convertible"
38 |
39 | // Then
40 | XCTAssertEqual(url.path, someURLString)
41 | }
42 |
43 | func testIntegerConvertible() {
44 | // Given
45 | let aSampleString = "10"
46 |
47 | // When
48 | let anInt = Int(aSampleString) !? "WARNING: Couldn't convert \(aSampleString) to int"
49 |
50 | // Then
51 | XCTAssertEqual(anInt, 10)
52 | }
53 |
54 | func testStringConvertible() {
55 | // Given
56 | let anUTF16View = "abc".utf16
57 |
58 | // When
59 | let aString = String(anUTF16View) !? "WARNING: Couldn't convert \(anUTF16View) to String"
60 |
61 | // Then
62 | XCTAssertEqual(aString, "abc")
63 | }
64 |
65 | func testGeneralConvertible() {
66 | // Given
67 | let someURLString = "www.test.com/something"
68 |
69 | // When
70 | let url = URL(string: someURLString) !? (URL(fileURLWithPath: "\\"), "WARNING: \(someURLString) isn't url convertible")
71 |
72 | // Then
73 | XCTAssertEqual(url.path, someURLString)
74 | }
75 |
76 | }
77 |
--------------------------------------------------------------------------------
/Tests/ViaSwiftUtilsTests/CGPoint+OperatorsTest.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CGPoint+OperatorsTest.swift
3 | // ViaSwiftUtils
4 | //
5 | // Copyright 2017 Viacom, Inc.
6 | //
7 | // Licensed under the Apache License, Version 2.0 (the "License");
8 | // you may not use this file except in compliance with the License.
9 | // You may obtain a copy of the License at
10 | //
11 | // http://www.apache.org/licenses/LICENSE-2.0
12 | //
13 | // Unless required by applicable law or agreed to in writing, software
14 | // distributed under the License is distributed on an "AS IS" BASIS,
15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | // See the License for the specific language governing permissions and
17 | // limitations under the License.
18 |
19 | @testable import ViaSwiftUtils
20 | import XCTest
21 |
22 | class CGPointOperatorsTest: XCTestCase {
23 |
24 | static var allTests = [
25 | ("testPlusOperator", testPlusOperator),
26 | ("testMinusOperator", testMinusOperator)
27 | ]
28 |
29 | func testPlusOperator() {
30 | // Given:
31 | let point1 = CGPoint(x: 1.0, y: 1.0)
32 | let point2 = CGPoint(x: 1.0, y: 1.0)
33 |
34 | // When:
35 | let point3 = point1 + point2
36 |
37 | // Then:
38 | XCTAssertEqual(point3, CGPoint(x: 2.0, y: 2.0))
39 | }
40 |
41 | func testMinusOperator() {
42 | // Given:
43 | let point1 = CGPoint(x: 2.0, y: 2.0)
44 | let point2 = CGPoint(x: 1.0, y: 1.0)
45 |
46 | // When:
47 | let point3 = point1 - point2
48 |
49 | // Then:
50 | XCTAssertEqual(point3, CGPoint(x: 1.0, y: 1.0))
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Tests/ViaSwiftUtilsTests/CGRectTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViaSwiftUtils_iOSTests.swift
3 | // ViaSwiftUtils
4 | //
5 | // Copyright 2017 Viacom, Inc.
6 | //
7 | // Licensed under the Apache License, Version 2.0 (the "License");
8 | // you may not use this file except in compliance with the License.
9 | // You may obtain a copy of the License at
10 | //
11 | // http://www.apache.org/licenses/LICENSE-2.0
12 | //
13 | // Unless required by applicable law or agreed to in writing, software
14 | // distributed under the License is distributed on an "AS IS" BASIS,
15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | // See the License for the specific language governing permissions and
17 | // limitations under the License.
18 |
19 | @testable import ViaSwiftUtils
20 | import XCTest
21 |
22 | class CGRectTests: XCTestCase {
23 |
24 | static var allTests = [
25 | ("testRectSize10x5", testRectSize10x5),
26 | ("testRectWithZeroWidth", testRectWithZeroWidth),
27 | ("testRectWithZeroHeight", testRectWithZeroHeight),
28 | ("testRectWithLinearCombineRectsHalf", testRectWithLinearCombineRectsHalf),
29 | ("testRectWithLinearCombineRectsIllegalRatio", testRectWithLinearCombineRectsIllegalRatio)
30 | ]
31 |
32 | func testRectSize10x5() {
33 | // Given a rect sized 10 x 5
34 | let rect = CGRect(x: 0.0, y: 0.0, width: 10.0, height: 5.0)
35 |
36 | // Then
37 | XCTAssertEqual(Double(rect.aspectRatio), 2.0, accuracy: Double.ulpOfOne, "Expected Aspect ratio of 2.0")
38 | }
39 |
40 | func testRectWithZeroWidth() {
41 | // Given a rect sized 0 x 5
42 | let rect = CGRect(x: 0.0, y: 0.0, width: 0.0, height: 5.0)
43 |
44 | // Then
45 | XCTAssertEqual(Double(rect.aspectRatio), 0.0, accuracy: Double.ulpOfOne, "Expected Aspect ratio of 0.0")
46 | }
47 |
48 | func testRectWithZeroHeight() {
49 | // Given a rect sized 10 x 0
50 | let rect = CGRect(x: 0.0, y: 0.0, width: 10.0, height: 0.0)
51 |
52 | // Then
53 | XCTAssertEqual(Double(rect.aspectRatio), 0.0, accuracy: Double.ulpOfOne, "Expected Aspect ratio of 0.0")
54 | }
55 |
56 | func testRectWithLinearCombineRectsHalf() {
57 | // Given two given rects
58 | let rect1 = CGRect(x: 4.0, y: -4.0, width: 20.0, height: 10.0)
59 | let rect2 = CGRect(x: 0.0, y: 0.0, width: 10.0, height: 20.0)
60 |
61 | // When combined 50:50
62 | let combinedRect = rect1.linearCombined(with: rect2, by: 0.5)
63 |
64 | // Then
65 | XCTAssertEqual(Double(combinedRect.origin.x), 2.0,
66 | accuracy: .ulpOfOne, "Expected x to be 2.0")
67 | XCTAssertEqual(Double(combinedRect.origin.y), -2.0,
68 | accuracy: .ulpOfOne, "Expected y to be -2.0")
69 | XCTAssertEqual(Double(combinedRect.size.width), 15,
70 | accuracy: .ulpOfOne, "Expected width to be 15.0")
71 | XCTAssertEqual(Double(combinedRect.size.height), 15.0,
72 | accuracy: .ulpOfOne, "Expected height to be 15.0")
73 | }
74 |
75 | func testRectWithLinearCombineRectsIllegalRatio() {
76 | // Given a two given rects
77 | let rect1 = CGRect(x: 4.0, y: -4.0, width: 20.0, height: 10.0)
78 | let rect2 = CGRect(x: 0.0, y: 0.0, width: 10.0, height: 20.0)
79 |
80 | // When combined with a value < 0
81 | let combinedRect = rect1.linearCombined(with: rect2, by: -1.5)
82 |
83 | // Then
84 | XCTAssertEqual(Double(combinedRect.origin.x), Double(rect1.origin.x),
85 | accuracy: .ulpOfOne, "Expected x to be equal to rect1.x")
86 |
87 | // When combined with a value > 1
88 | let combinedRect2 = rect1.linearCombined(with: rect2, by: 1.5)
89 |
90 | // Then
91 | XCTAssertEqual(Double(combinedRect2.origin.y), Double(rect2.origin.y),
92 | accuracy: .ulpOfOne, "Expected y to be equal to rect2.y")
93 | }
94 |
95 | }
96 |
--------------------------------------------------------------------------------
/Tests/ViaSwiftUtilsTests/CollectionShuffledTest.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Shuffled.swift
3 | // ViaSwiftUtils
4 | //
5 | // Copyright 2017 Viacom, Inc.
6 | //
7 | // Licensed under the Apache License, Version 2.0 (the "License");
8 | // you may not use this file except in compliance with the License.
9 | // You may obtain a copy of the License at
10 | //
11 | // http://www.apache.org/licenses/LICENSE-2.0
12 | //
13 | // Unless required by applicable law or agreed to in writing, software
14 | // distributed under the License is distributed on an "AS IS" BASIS,
15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | // See the License for the specific language governing permissions and
17 | // limitations under the License.
18 |
19 | @testable import ViaSwiftUtils
20 | import XCTest
21 |
22 | class CollectionShuffledTest: XCTestCase {
23 |
24 | static var allTests = [
25 | ("testShuffleDoesNotChangeCount", testShuffleDoesNotChangeCount),
26 | ("testShuffledArraysKeepElements", testShuffledArraysKeepElements)
27 | ]
28 |
29 | func testShuffleDoesNotChangeCount() {
30 | // Given a shuffled
31 | var mutableNumberList = [1, 2, 3, 4, 5, 6]
32 | let originalNumbers = mutableNumberList
33 |
34 | // When shuffled
35 | mutableNumberList.shuffleInPlace()
36 |
37 | // Then array should have the same amount of elements
38 | XCTAssertEqual(originalNumbers.count, mutableNumberList.count,
39 | "Expected equal count of shuffled Collection to Original")
40 | }
41 |
42 | func testShuffledArraysKeepElements() {
43 | // Given hundred random arrays
44 | for _ in 0..<100 {
45 | let array = (0..<100).map({ _ in return (100..<200).arc4random })
46 | var shuffledArray = array
47 |
48 | // When shuffled
49 | shuffledArray.shuffleInPlace()
50 |
51 | // Then each element should occurs in equally often in both original and shuffled array
52 | for element in array.unique() {
53 | XCTAssertEqual(shuffledArray.filter({ element == $0 }).count, array.filter({ element == $0 }).count,
54 | "Expected the same elements in the shuffled array as in the original")
55 | }
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/Tests/ViaSwiftUtilsTests/Date_ComparableTest.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Date_Comparable.swift
3 | // ViaSwiftUtils
4 | //
5 | // Copyright 2017 Viacom, Inc.
6 | //
7 | // Licensed under the Apache License, Version 2.0 (the "License");
8 | // you may not use this file except in compliance with the License.
9 | // You may obtain a copy of the License at
10 | //
11 | // http://www.apache.org/licenses/LICENSE-2.0
12 | //
13 | // Unless required by applicable law or agreed to in writing, software
14 | // distributed under the License is distributed on an "AS IS" BASIS,
15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | // See the License for the specific language governing permissions and
17 | // limitations under the License.
18 |
19 | @testable import ViaSwiftUtils
20 | import XCTest
21 |
22 | class DateComparableTest: XCTestCase {
23 |
24 | static var allTests = [
25 | ("testComparable", testComparable)
26 | ]
27 |
28 | func testComparable() {
29 | // Given, When
30 | let earlyDate = Date(timeIntervalSince1970: 0)
31 | let laterDate = Date(timeIntervalSince1970: 1000)
32 | let otherDate = Date(timeIntervalSince1970: 1000)
33 |
34 | // Then
35 | XCTAssertTrue(earlyDate < laterDate, "Expected earlyDate to be before laterDate")
36 | XCTAssertTrue(laterDate > earlyDate, "Expected earlyDate to be before laterDate")
37 | XCTAssertTrue(otherDate == laterDate, "Expected otherDate to be equal laterDate")
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/Tests/ViaSwiftUtilsTests/Date_ComponentAccessorsTest.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NSCalender+CurrentYear.swift
3 | // ViaSwiftUtils
4 | //
5 | // Copyright 2017 Viacom, Inc.
6 | //
7 | // Licensed under the Apache License, Version 2.0 (the "License");
8 | // you may not use this file except in compliance with the License.
9 | // You may obtain a copy of the License at
10 | //
11 | // http://www.apache.org/licenses/LICENSE-2.0
12 | //
13 | // Unless required by applicable law or agreed to in writing, software
14 | // distributed under the License is distributed on an "AS IS" BASIS,
15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | // See the License for the specific language governing permissions and
17 | // limitations under the License.
18 |
19 | @testable import ViaSwiftUtils
20 | import XCTest
21 |
22 | class DateComponentAccessorsTest: XCTestCase {
23 |
24 | static var allTests = [
25 | ("testDateComponentAsInts", testDateComponentAsInts),
26 | ("testCurrentYear", testCurrentYear),
27 | ("testHistoricalYear", testHistoricalYear)
28 | ]
29 |
30 | func testDateComponentAsInts() {
31 | // Given
32 | let eightAM1970 = Date(timeIntervalSince1970: 8 * TimeInterval.hour + 0.5 * TimeInterval.minute)
33 |
34 | // When in UTC time zone then
35 | if let utcZone = TimeZone(abbreviation: "UTC") { NSTimeZone.default = utcZone }
36 |
37 | // Then
38 | XCTAssertEqual(eightAM1970.hourOfDay, 8, "Expected 8:00AM 1/1/1970 to be in the 8th hour of the day")
39 | XCTAssertEqual(eightAM1970.dayOfWeek, 5, "Expected 8:00AM 1/1/1970 to be a thursday")
40 | XCTAssertEqual(eightAM1970.year, 1970, "Expected 8:00AM 1/1/1970 to be year 1970")
41 | }
42 |
43 | func testCurrentYear() {
44 | // Given the current date
45 | let currentYear = Date().localizedYear
46 |
47 | // Then
48 | XCTAssertEqual(currentYear.count, 4, "Expected currentyear to have 4 characters")
49 | }
50 |
51 | func testHistoricalYear() {
52 | // Given the fall of the west roman empire
53 | let fallOfRome = Date(timeIntervalSince1970: -TimeInterval.year * (1970 - 476))
54 |
55 | // When converting to localized string
56 | let localizedString = fallOfRome.localizedYear
57 |
58 | // Then
59 | XCTAssertEqual(localizedString.count, 3, "Expected year of the fall of west rome to have 3 characters")
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/Tests/ViaSwiftUtilsTests/Date_TimesBetween.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Date_TimesBetween.swift
3 | // ViaSwiftUtils
4 | //
5 | // Copyright 2017 Viacom, Inc.
6 | //
7 | // Licensed under the Apache License, Version 2.0 (the "License");
8 | // you may not use this file except in compliance with the License.
9 | // You may obtain a copy of the License at
10 | //
11 | // http://www.apache.org/licenses/LICENSE-2.0
12 | //
13 | // Unless required by applicable law or agreed to in writing, software
14 | // distributed under the License is distributed on an "AS IS" BASIS,
15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | // See the License for the specific language governing permissions and
17 | // limitations under the License.
18 |
19 | @testable import ViaSwiftUtils
20 | import XCTest
21 |
22 | class DateTimesBetweenTests: XCTestCase {
23 |
24 | static var allTests = [
25 | ("testTomorrow", testTomorrow),
26 | ("testNextMinute", testNextMinute),
27 | ("testNextSecond", testNextSecond)
28 | ]
29 |
30 | func testTomorrow() {
31 | // Given the current date
32 | let now = Date()
33 |
34 | // When comparing to tomorrow
35 | let tomorrow = Date(timeIntervalSinceNow: TimeInterval.day)
36 | // Then
37 | XCTAssertEqual(now.days(to: tomorrow), 1, "Expected today to be 1 day from tomorrow")
38 | }
39 |
40 | func testNextMinute() {
41 | // Given the current date
42 | let now = Date()
43 | // When comparing to next minute
44 | let nextMinute = Date(timeIntervalSinceNow: TimeInterval.minute)
45 | // Then
46 | XCTAssertEqual(now.minutes(to: nextMinute), 1, "Expected nextMinute to be 1 minute from now")
47 | }
48 |
49 | func testNextSecond() {
50 | // Given the current date
51 | let now = Date()
52 | // When comparing to next second
53 | let nextSecond = Date(timeIntervalSinceNow: TimeInterval.second)
54 | // Then
55 | XCTAssertEqual(now.seconds(to: nextSecond), 1, "Expected nextSecond to be 1 second from now")
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/Tests/ViaSwiftUtilsTests/Dictionary+MapValuesTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Dictionary+MapValuesTests.swift
3 | // ViaSwiftUtils
4 | //
5 | // Copyright 2017 Viacom, Inc.
6 | //
7 | // Licensed under the Apache License, Version 2.0 (the "License");
8 | // you may not use this file except in compliance with the License.
9 | // You may obtain a copy of the License at
10 | //
11 | // http://www.apache.org/licenses/LICENSE-2.0
12 | //
13 | // Unless required by applicable law or agreed to in writing, software
14 | // distributed under the License is distributed on an "AS IS" BASIS,
15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | // See the License for the specific language governing permissions and
17 | // limitations under the License.
18 |
19 | @testable import ViaSwiftUtils
20 | import XCTest
21 |
22 | class DictionaryMapValuesTests: XCTestCase {
23 |
24 | static var allTests = [
25 | ("testMergeDictionariesOfEqualType", testMergeDictionariesOfEqualType),
26 | ("testMergeDictionariesWithOverlappingKeys", testMergeDictionariesWithOverlappingKeys),
27 | ("testMapValues", testMapValues)
28 | ]
29 |
30 | func testMergeDictionariesOfEqualType() {
31 | // Given two dictionarys of the same types
32 | var dict1 = ["One": 1, "Two": 2, "Three": 3]
33 | let dict2 = ["Four": 10, "Five": 2, "Six": 3]
34 |
35 | // When
36 | dict1.merge(dict2)
37 |
38 | // Then
39 | XCTAssertEqual(dict1.count, 6, "Expected count of the combined arrays to be 6")
40 | }
41 |
42 | func testMergeDictionariesWithOverlappingKeys() {
43 | // Given two dictionarys with overlapping keys
44 | var dict3 = ["One": 1, "Two": 2, "Three": 3]
45 | let dict4 = ["Four": 10, "Two": 2, "Six": 3]
46 |
47 | // When
48 | dict3.merge(dict4)
49 |
50 | // Then
51 | XCTAssertEqual(dict3.count, 5, "Expected count of the combined arrays to be 5")
52 | }
53 |
54 | func testMapValues() {
55 | // Given two dictionarys [String: Int]
56 | let dict = ["One": 1, "Two": 2, "Three": 3]
57 |
58 | // When
59 | let mappedDict = dict.mapValues { number -> String in
60 | let numberFormatter = NumberFormatter()
61 | return numberFormatter.string(from: NSNumber(value: number)) ?? "N.A."
62 | }
63 |
64 | // Then
65 | XCTAssertEqual(Array(dict.keys.sorted()), Array(mappedDict.keys.sorted()), "Expected both dicts to have the same keys")
66 | }
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/Tests/ViaSwiftUtilsTests/RandomAccessCollection+SafeAccessTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Date_Comparable.swift
3 | // ViaSwiftUtils
4 | //
5 | // Copyright 2017 Viacom, Inc.
6 | //
7 | // Licensed under the Apache License, Version 2.0 (the "License");
8 | // you may not use this file except in compliance with the License.
9 | // You may obtain a copy of the License at
10 | //
11 | // http://www.apache.org/licenses/LICENSE-2.0
12 | //
13 | // Unless required by applicable law or agreed to in writing, software
14 | // distributed under the License is distributed on an "AS IS" BASIS,
15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | // See the License for the specific language governing permissions and
17 | // limitations under the License.
18 |
19 | @testable import ViaSwiftUtils
20 | import XCTest
21 |
22 | class RandomAccessCollectionSafeAccessTests: XCTestCase {
23 |
24 | static var allTests = [
25 | ("testOutOfBoundsIndex", testOutOfBoundsIndex),
26 | ("testValidIndex", testValidIndex),
27 | ("testNegativeIndex", testNegativeIndex),
28 | ("testArraySliceOutOfBounds", testArraySliceOutOfBounds),
29 | ("testArraySliceInBounds", testArraySliceInBounds),
30 | ("testContiguousArray", testContiguousArray)
31 | ]
32 |
33 | private let testArray = ["zero", "one", "two", "three", "four"]
34 |
35 | func testOutOfBoundsIndex() {
36 | // Given an index that is out of bounds
37 | let index = testArray.count
38 | // then the safe access should return nil
39 | XCTAssertNil(testArray[safe: index])
40 | }
41 |
42 | func testValidIndex() {
43 | // Given an index that is inside the bounds
44 | let index = 3
45 | // then the correct value is returned
46 | XCTAssertEqual(testArray[safe: index], "three")
47 | }
48 |
49 | func testNegativeIndex() {
50 | // Given an index that is out of bounds
51 | let index = -1
52 | // then the safe access should return nil
53 | XCTAssertNil(testArray[safe: index])
54 | }
55 |
56 | private var testSlice: ArraySlice { return testArray[1...3] }
57 |
58 | func testArraySliceOutOfBounds() {
59 | // Given an out of bounds index is requested
60 | let outOfBoundsIndex = 0
61 | // then the safe access should still return the correct value
62 | XCTAssertNil(testSlice[safe: outOfBoundsIndex])
63 | }
64 |
65 | func testArraySliceInBounds() {
66 | // Given a value inside the subsclice is asked for
67 | let validIndex = 1
68 | // then the safe access should still return the correct value
69 | XCTAssertEqual(testSlice[safe: validIndex], "one")
70 | }
71 |
72 | func testContiguousArray() {
73 | // Given a (more efficient) ContiguousArray
74 | let array = ContiguousArray(testArray)
75 | // then the safe access should still return the correct value
76 | XCTAssertEqual(testArray[safe: 1], array[safe: 1])
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/Tests/ViaSwiftUtilsTests/SequenceTypeHelperTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SequenceTypeHelperTests.swift
3 | // ViaSwiftUtils
4 | //
5 | // Copyright 2017 Viacom, Inc.
6 | //
7 | // Licensed under the Apache License, Version 2.0 (the "License");
8 | // you may not use this file except in compliance with the License.
9 | // You may obtain a copy of the License at
10 | //
11 | // http://www.apache.org/licenses/LICENSE-2.0
12 | //
13 | // Unless required by applicable law or agreed to in writing, software
14 | // distributed under the License is distributed on an "AS IS" BASIS,
15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | // See the License for the specific language governing permissions and
17 | // limitations under the License.
18 |
19 | @testable import ViaSwiftUtils
20 | import XCTest
21 |
22 | class SequenceTypeHelperTests: XCTestCase {
23 |
24 | static var allTests = [
25 | ("testFindFirstExistentOfMultiple", testFindFirstExistentOfMultiple),
26 | ("testUniqueElements", testUniqueElements),
27 | ("testANYALLNONE", testANYALLNONE)
28 | ]
29 |
30 | private struct TestElement {
31 | let number: Int
32 | let value: Int
33 | }
34 |
35 | func testFindFirstExistentOfMultiple() {
36 | // given a set of items with multiple values over 10
37 | let elements = [TestElement(number: 0, value: 10),
38 | TestElement(number: 1, value: 10),
39 | TestElement(number: 2, value: 20),
40 | TestElement(number: 3, value: 10),
41 | TestElement(number: 4, value: 20),
42 | TestElement(number: 5, value: 10),
43 | TestElement(number: 6, value: 20),
44 | TestElement(number: 7, value: 10)]
45 |
46 | // Then
47 | XCTAssertEqual(elements.first(where: { $0.value > 10 })?.number, 2, "Expected first element to be larger then 10 to be 2")
48 | }
49 |
50 | func testUniqueElements() {
51 | // Given an already unique arrays of elements, When
52 | let elements = [1, 2, 3, 4, 5, 6]
53 |
54 | // Then
55 | XCTAssertEqual(elements.unique().count, elements.count, "Expected elements to be equal to unique elements")
56 |
57 | // Given a bigger array of elements, When
58 | let moreElements = [1, 2, 3, 4, 5, 6, 1, 2, 3, 8]
59 |
60 | // Then
61 | XCTAssertEqual(moreElements.unique().count, 7, "Expected elements to be equal to unique elements")
62 | }
63 |
64 | func testANYALLNONE() {
65 | // Given, When
66 | let elements = [1, 2, 3, 4, 5, 6]
67 |
68 | // Then
69 | XCTAssertTrue(elements.any { $0 > 3 }, "Expected 'any number larger 3' to be true")
70 | XCTAssertTrue(elements.all { $0 > 0 }, "Expected 'all to be bigger then 0' to be true")
71 | XCTAssertTrue(elements.none { $0 < 0 }, "Expected 'none to be negative' to be true")
72 | XCTAssertFalse(elements.any { $0 > 6 }, "Expected 'any larger then 6' to be false")
73 | XCTAssertFalse(elements.all { $0 > 2 }, "Expected all to be false")
74 | XCTAssertFalse(elements.all { $0 > 6 }, "Expected all to be false")
75 | XCTAssertFalse(elements.none { $0 > 1 }, "Expected 'none over 1' to be false")
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/ViaSwiftUtils.playground/Contents.swift:
--------------------------------------------------------------------------------
1 | //: Playground - noun: a place where people can play
2 |
3 | import UIKit
4 | import ViaSwiftUtils
5 |
6 | //CGRect
7 | let rect = CGRect(x: 0, y: 0, width: 10, height: 5)
8 | print("aspect ratio: \(rect.aspectRatio)")
9 |
10 | let otherRect = CGRect(x: 5, y: -5, width: 20, height: 5)
11 | print("combined: \(rect.linearCombined(with: otherRect, by: 0.5) )")
12 |
13 | var mutableNumberList = [1, 2, 3, 4, 5, 6]
14 | mutableNumberList.shuffleInPlace()
15 |
16 | let emojis = ["😀", "👀", "😱", "😡", "👀", "😀", "👀", "😱"]
17 | let uniqueEmojis = emojis.unique()
18 |
19 | let image = #imageLiteral(resourceName: "puppy").cornersRounded(usingRadius: 100)
20 |
21 | //Example type-safe Observer Pattern
22 | enum VideoEvent {
23 | case started
24 | case ended
25 | }
26 |
27 | struct VideoEventEventReceiver: ObserverType {
28 | let name: String
29 |
30 | func receive(_ event: VideoEvent) {
31 | print("\(name) received \(event)")
32 | }
33 | }
34 |
35 | struct Player: Observable {
36 | typealias Event = VideoEvent
37 |
38 | // var observes: [ObserverType] = [] would not work, because ObserverType has an associated type
39 | var observers: [(Event) -> Void] = []
40 |
41 | mutating func register(_ observer: O) where O.Event == Event {
42 | observers.append({ observer.receive($0) })
43 | }
44 |
45 | func fire(event: VideoEvent) {
46 | for observer in observers { observer(event) }
47 | }
48 | }
49 |
50 | var player = Player()
51 | let sko = VideoEventEventReceiver(name: "SKO")
52 | var gallup = VideoEventEventReceiver(name: "Gallup")
53 | player.register(sko)
54 | player.register(gallup)
55 | player.fire(event: .started)
56 |
57 | Date().year
58 | Date().dayOfWeek
59 |
60 | let formatter = DateFormatter()
61 | formatter.dateFormat = "y"
62 | let twelveDays = 12 * TimeInterval.day
63 | let minutes = twelveDays / TimeInterval.minute
64 |
65 | let gregorian = Calendar(identifier: .gregorian)
66 | let components = DateComponents(calendar: gregorian,
67 | era: 0, year: 44, month: 3, day: 15, hour: 13)
68 | let idesOfMarch = gregorian.date(from: components)!
69 | let weekDay = idesOfMarch.dayOfWeek
70 | let daysSince = idesOfMarch.days(to: Date())
71 |
72 | formatter.string(from: idesOfMarch)
73 | formatter.string(from: Date())
74 |
75 | formatter.locale = Locale(identifier: "hi_IN")
76 |
77 | formatter.string(from: idesOfMarch)
78 | formatter.string(from: Date())
79 |
80 | var dict1 = ["One": 1, "Two": 2, "Three": 3]
81 | let dict2 = ["Four": 10, "Five": 2, "Six": 3]
82 |
83 | dict1.merge(dict2)
84 |
85 | print(dict1)
86 |
87 | let someString = "10"
88 | let someInt = Int(someString) !? "Couldn't convert \(someString) to int"
89 |
--------------------------------------------------------------------------------
/ViaSwiftUtils.playground/Resources/puppy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ViacomInc/ViaSwiftUtils/28414e8385a86102121b726dafb99daa9cfe6a1b/ViaSwiftUtils.playground/Resources/puppy.png
--------------------------------------------------------------------------------
/ViaSwiftUtils.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/ViaSwiftUtils.playground/playground.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ViaSwiftUtils.playground/timeline.xctimeline:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
9 |
10 |
14 |
15 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/ViaSwiftUtils.podspec:
--------------------------------------------------------------------------------
1 | # Copyright 2019 Viacom, Inc.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.#
14 | # Be sure to run `pod lib lint KDTree.podspec' to ensure this is a
15 | # valid spec before submitting.
16 | #
17 | # Any lines starting with a # are optional, but their use is encouraged
18 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html
19 | #
20 |
21 | Pod::Spec.new do |s|
22 | s.name = "ViaSwiftUtils"
23 | s.version = "2.1.0"
24 | s.summary = "Swift Utilities written with and for Viacom Inc."
25 | s.swift_versions = ['4.0', '4.2', '5.0']
26 |
27 | # This description is used to generate tags and improve search results.
28 | s.description = "Goodie box of small helper functions/extensions used in many Swift Apps at Viacom"
29 |
30 | s.homepage = "https://github.com/ViacomInc/ViaSwiftUtils"
31 | s.license = { :type => 'Apache License, Version 2.0' }
32 | s.author = { "Konrad Feiler" => "konrad.feiler@vimn.com" }
33 | s.source = { :git => "https://github.com/ViacomInc/ViaSwiftUtils.git", :tag => s.version.to_s }
34 |
35 | s.ios.deployment_target = '9.0'
36 | s.watchos.deployment_target = '2.0'
37 | s.tvos.deployment_target = '9.0'
38 | s.requires_arc = true
39 |
40 | s.ios.source_files = 'Sources/ViaSwiftUtils/**/*'
41 | s.osx.source_files = 'Sources/ViaSwiftUtils/Foundation/*'
42 | s.watchos.source_files = 'Sources/ViaSwiftUtils/Foundation/*'
43 | s.tvos.source_files = 'Sources/ViaSwiftUtils/Foundation/*'
44 |
45 | # s.public_header_files = 'Pod/Classes/**/*.h'
46 | end
47 |
--------------------------------------------------------------------------------
/ViaSwiftUtils.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ViaSwiftUtils.xcodeproj/xcshareddata/xcschemes/ViaSwiftUtils_iOS.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
34 |
40 |
41 |
42 |
43 |
44 |
50 |
51 |
52 |
53 |
54 |
55 |
65 |
66 |
72 |
73 |
74 |
75 |
76 |
77 |
83 |
84 |
90 |
91 |
92 |
93 |
95 |
96 |
99 |
100 |
101 |
--------------------------------------------------------------------------------
/ViaSwiftUtils.xcodeproj/xcshareddata/xcschemes/ViaSwiftUtils_tvOS.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
49 |
50 |
51 |
52 |
53 |
54 |
64 |
65 |
71 |
72 |
73 |
74 |
75 |
76 |
82 |
83 |
89 |
90 |
91 |
92 |
94 |
95 |
98 |
99 |
100 |
--------------------------------------------------------------------------------
/ViaSwiftUtils.xcodeproj/xcshareddata/xcschemes/ViaSwiftUtils_watchOS.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 |
--------------------------------------------------------------------------------
/ViaSwiftUtils.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/ViaSwiftUtils.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ViaSwiftUtils.xcworkspace/xcshareddata/ViaSwiftUtils.xcscmblueprint:
--------------------------------------------------------------------------------
1 | {
2 | "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "74667E66266B70EF860E327D2D4A8B3182F679FB",
3 | "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : {
4 |
5 | },
6 | "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : {
7 | "74667E66266B70EF860E327D2D4A8B3182F679FB" : 0,
8 | "D676CDCA5771490D15D8EB193B74E257D80F2D2E" : 0
9 | },
10 | "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "87558D39-4567-4480-AA1A-2FCCCF0C21CC",
11 | "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : {
12 | "74667E66266B70EF860E327D2D4A8B3182F679FB" : "ViaSwiftUtils\/",
13 | "D676CDCA5771490D15D8EB193B74E257D80F2D2E" : "..\/PlayPlex-iOS"
14 | },
15 | "DVTSourceControlWorkspaceBlueprintNameKey" : "ViaSwiftUtils",
16 | "DVTSourceControlWorkspaceBlueprintVersion" : 204,
17 | "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "ViaSwiftUtils.xcworkspace",
18 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [
19 | {
20 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/vimn-north\/ViaSwiftUtils.git",
21 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
22 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "74667E66266B70EF860E327D2D4A8B3182F679FB"
23 | },
24 | {
25 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/vimn-north\/PlayPlex-iOS.git",
26 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
27 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "D676CDCA5771490D15D8EB193B74E257D80F2D2E"
28 | }
29 | ]
30 | }
--------------------------------------------------------------------------------
/ViaSwiftUtils.xcworkspace/xcuserdata/feilek.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
--------------------------------------------------------------------------------
/iOSTests/CGVectorOperatorsTest.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CGVectorOperatorsTest.swift
3 | // ViaSwiftUtils
4 | //
5 | // Copyright 2017 Viacom, Inc.
6 | //
7 | // Licensed under the Apache License, Version 2.0 (the "License");
8 | // you may not use this file except in compliance with the License.
9 | // You may obtain a copy of the License at
10 | //
11 | // http://www.apache.org/licenses/LICENSE-2.0
12 | //
13 | // Unless required by applicable law or agreed to in writing, software
14 | // distributed under the License is distributed on an "AS IS" BASIS,
15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | // See the License for the specific language governing permissions and
17 | // limitations under the License.
18 |
19 | @testable import ViaSwiftUtils
20 | import XCTest
21 |
22 | class CGVectorOperatorsTest: XCTestCase {
23 |
24 | func testPlusOperator() {
25 | // Given:
26 | let vector1 = CGVector(dx: 1.0, dy: 1.0)
27 | let vector2 = CGVector(dx: 1.0, dy: 1.0)
28 |
29 | // When:
30 | let vector3 = vector1 + vector2
31 |
32 | // Then:
33 | XCTAssertEqual(vector3, CGVector(dx: 2.0, dy: 2.0))
34 | }
35 |
36 | func testMinusOperator() {
37 | // Given:
38 | let vector1 = CGVector(dx: 2.0, dy: 2.0)
39 | let vector2 = CGVector(dx: 1.0, dy: 1.0)
40 |
41 | // When:
42 | let vector3 = vector1 - vector2
43 |
44 | // Then:
45 | XCTAssertEqual(vector3, CGVector(dx: 1.0, dy: 1.0))
46 | }
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/iOSTests/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 |
--------------------------------------------------------------------------------
/iOSTests/NSLocale+Swizzling.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NSLocale+Swizzling.swift
3 | // ViaSwiftUtils
4 | //
5 | // Copyright 2017 Viacom, Inc.
6 | //
7 | // Licensed under the Apache License, Version 2.0 (the "License");
8 | // you may not use this file except in compliance with the License.
9 | // You may obtain a copy of the License at
10 | //
11 | // http://www.apache.org/licenses/LICENSE-2.0
12 | //
13 | // Unless required by applicable law or agreed to in writing, software
14 | // distributed under the License is distributed on an "AS IS" BASIS,
15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | // See the License for the specific language governing permissions and
17 | // limitations under the License.
18 |
19 | import Foundation
20 | @testable import ViaSwiftUtils
21 |
22 | // swiftlint:disable identifier_name
23 |
24 | extension NSLocale {
25 | @nonobjc static var ttt_locale = "en_US"
26 | @nonobjc static var ttt_swizzled = false
27 |
28 | @objc
29 | class func customizedLocale() -> NSLocale {
30 | return NSLocale(localeIdentifier: NSLocale.ttt_locale)
31 | }
32 |
33 | class func forceLocale(identifier: String) {
34 | NSLocale.ttt_locale = identifier
35 |
36 | print("Swizzling to locale \(identifier)")
37 |
38 | if !NSLocale.ttt_swizzled {
39 | NSLocale.ttt_swizzled = true
40 | let originalSelector = #selector(getter: NSLocale.current)
41 | let swizzledSelector = #selector(self.customizedLocale)
42 |
43 | let originalMethod = class_getClassMethod(self, originalSelector) !! "Expected NSLocale.current exists"
44 | let swizzledMethod = class_getClassMethod(self, swizzledSelector) !! "Expected customizedLocale exists"
45 |
46 | method_exchangeImplementations(originalMethod, swizzledMethod)
47 | }
48 | }
49 |
50 | class func undoForcing() {
51 | print("Undoing the swizzling")
52 |
53 | if NSLocale.ttt_swizzled {
54 | NSLocale.ttt_swizzled = false
55 | let swizzledSelector = #selector(self.customizedLocale)
56 | let originalSelector = #selector(getter: NSLocale.current)
57 |
58 | let originalMethod = class_getClassMethod(self, originalSelector) !! "Expected NSLocale.current exists"
59 | let swizzledMethod = class_getClassMethod(self, swizzledSelector) !! "Expected customizedLocale exists"
60 |
61 | method_exchangeImplementations(originalMethod, swizzledMethod)
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/iOSTests/NibViewTest.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NibViewTest.swift
3 | // ViaSwiftUtils
4 | //
5 | // Copyright 2017 Viacom, Inc.
6 | //
7 | // Licensed under the Apache License, Version 2.0 (the "License");
8 | // you may not use this file except in compliance with the License.
9 | // You may obtain a copy of the License at
10 | //
11 | // http://www.apache.org/licenses/LICENSE-2.0
12 | //
13 | // Unless required by applicable law or agreed to in writing, software
14 | // distributed under the License is distributed on an "AS IS" BASIS,
15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | // See the License for the specific language governing permissions and
17 | // limitations under the License.
18 |
19 | import Foundation
20 | @testable import ViaSwiftUtils
21 | import XCTest
22 |
23 | //swiftlint:disable strict_fileprivate
24 | class TestViewController: UIViewController {
25 |
26 | @IBOutlet fileprivate var horizontalTestViewConstraint: NSLayoutConstraint?
27 | @IBOutlet fileprivate var testView: TestViewWithOwner?
28 |
29 | }
30 |
31 | class TestViewWithOwner: NibView {
32 |
33 | @IBOutlet fileprivate var horizontalLabelConstraint: NSLayoutConstraint?
34 | @IBOutlet fileprivate var testLabel: UILabel?
35 |
36 | }
37 | //swiftlint:enable strict_fileprivate
38 |
39 | class NibViewTest: XCTestCase {
40 |
41 | func testInitializationWithinStoryboard() {
42 | // Given
43 | let storyboard = UIStoryboard(name: "TestStoryboard", bundle: Bundle(for: type(of: self)))
44 |
45 | // When
46 | let testViewController = storyboard.instantiateInitialViewController() as? TestViewController
47 | _ = testViewController?.view
48 | let testView = testViewController?.testView
49 |
50 | // Then
51 | XCTAssertNotNil(testViewController)
52 | XCTAssertNotNil(testViewController?.testView)
53 | XCTAssertNotNil(testViewController?.horizontalTestViewConstraint)
54 | XCTAssertNotNil(testView)
55 | XCTAssertNotNil(testView?.testLabel)
56 | XCTAssertNotNil(testView?.horizontalLabelConstraint)
57 | }
58 |
59 | func testInitializationWithFrame() {
60 | // Given
61 | let frame = CGRect(x: 0.0, y: 0.0, width: 10.0, height: 10.0)
62 | let expectedNumberOfSubviews = 1
63 | let expectedSubviewType = String(describing: XibView.self)
64 |
65 | // When
66 | let testView = TestViewWithOwner(frame: frame)
67 |
68 | // Then
69 | XCTAssertEqual(testView.subviews.count, expectedNumberOfSubviews, "Expected number of subviews to be \(expectedNumberOfSubviews)")
70 |
71 | let subviewType = String(describing: type(of: testView.subviews[0]))
72 | XCTAssertEqual(subviewType, expectedSubviewType, "Expected subview type to be \(expectedSubviewType)")
73 | }
74 |
75 | func testInitializationWithCoder() {
76 | // Given
77 | let frame = CGRect(x: 0.0, y: 0.0, width: 10.0, height: 10.0)
78 | let expectedNumberOfSubviews = 1
79 | let expectedSubviewType = String(describing: XibView.self)
80 | let archivePath = NSTemporaryDirectory().appending("testView")
81 |
82 | // When
83 | let testView = TestViewWithOwner(frame: frame)
84 | NSKeyedArchiver.archiveRootObject(testView, toFile: archivePath)
85 | let unarchivedTestView = NSKeyedUnarchiver.unarchiveObject(withFile: archivePath) as? TestViewWithOwner
86 |
87 | // Then
88 | XCTAssertNotNil(unarchivedTestView, "Expected unarchived view not to be nil")
89 | unarchivedTestView.map {
90 | XCTAssertEqual($0.subviews.count, expectedNumberOfSubviews, "Expected number of subviews to be \(expectedNumberOfSubviews)")
91 |
92 | let subviewType = String(describing: type(of: $0.subviews[0]))
93 | XCTAssertEqual(subviewType, expectedSubviewType, "Expected subview type to be \(expectedSubviewType)")
94 | }
95 | }
96 |
97 | }
98 |
--------------------------------------------------------------------------------
/iOSTests/StringWordsTest.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StringWordsTest.swift
3 | // ViaSwiftUtils
4 | //
5 | // Copyright 2017 Viacom, Inc.
6 | //
7 | // Licensed under the Apache License, Version 2.0 (the "License");
8 | // you may not use this file except in compliance with the License.
9 | // You may obtain a copy of the License at
10 | //
11 | // http://www.apache.org/licenses/LICENSE-2.0
12 | //
13 | // Unless required by applicable law or agreed to in writing, software
14 | // distributed under the License is distributed on an "AS IS" BASIS,
15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | // See the License for the specific language governing permissions and
17 | // limitations under the License.
18 |
19 | @testable import ViaSwiftUtils
20 | import XCTest
21 |
22 | class StringWordsTest: XCTestCase {
23 |
24 | static var allTests = [
25 | ("test_longestWordWithSuccessScenario", test_longestWordWithSuccessScenario),
26 | ("test_longestWordWithFailureScenario", test_longestWordWithFailureScenario),
27 | ("test_longestWordWithCommaSuccessScenario", test_longestWordWithCommaSuccessScenario),
28 | ("test_longestWordWithCommaFailureScenario", test_longestWordWithCommaFailureScenario),
29 | ("test_wordCountWithSuccessScenario", test_wordCountWithSuccessScenario),
30 | ("test_wordCountWithFailureScenario", test_wordCountWithFailureScenario),
31 | ("test_wordCountWithCommaSuccessScenario", test_wordCountWithCommaSuccessScenario),
32 | ("test_wordCountWithCommaFailureScenario", test_wordCountWithCommaFailureScenario),
33 | ("test_isOneWordWithSuccessScenario", test_isOneWordWithSuccessScenario),
34 | ("test_isOneWordWithFailureScenario", test_isOneWordWithFailureScenario),
35 | ("test_isOneWordWithCommaFailureScenario", test_isOneWordWithCommaFailureScenario),
36 | ("test_isOneWordWithFailureScenario_Japanese", test_isOneWordWithFailureScenario_Japanese)
37 | ]
38 |
39 | func test_longestWordWithSuccessScenario() {
40 | // Given:
41 | let source = "This is a test string"
42 | let longestWordToCompare = "string"
43 |
44 | // When:
45 | let longestWordCalculated = source.longestWord()
46 |
47 | // Then:
48 | XCTAssertEqual(longestWordToCompare, longestWordCalculated)
49 | }
50 |
51 | func test_longestWordWithFailureScenario() {
52 | // Given:
53 | let source = "This is a test string"
54 | let notTheLongestWord = "test"
55 |
56 | // When:
57 | let longestWordCalculated = source.longestWord()
58 |
59 | // Then:
60 | XCTAssertNotEqual(notTheLongestWord, longestWordCalculated)
61 | }
62 |
63 | func test_longestWordWithCommaSuccessScenario() {
64 | // Given:
65 | let source = "This is just, a test"
66 | let longestWordToCompare = "This"
67 |
68 | // When:
69 | let longestWordCalculated = source.longestWord()
70 |
71 | // Then:
72 | XCTAssertEqual(longestWordToCompare, longestWordCalculated)
73 | }
74 |
75 | func test_longestWordWithCommaFailureScenario() {
76 | // Given:
77 | let source = "This is just, a test"
78 | let notTheLongestWord = "just"
79 |
80 | // When:
81 | let longestWordCalculated = source.longestWord()
82 |
83 | // Then:
84 | XCTAssertNotEqual(notTheLongestWord, longestWordCalculated)
85 | }
86 |
87 | func test_wordCountWithSuccessScenario() {
88 | // Given:
89 | let source = "This is a test string"
90 |
91 | // When:
92 | let wordCount = source.wordCount()
93 |
94 | // Then:
95 | XCTAssertEqual(wordCount, 5)
96 | }
97 |
98 | func test_wordCountWithFailureScenario() {
99 | // Given:
100 | let source = "This is a test string"
101 |
102 | // When:
103 | let wordCount = source.wordCount()
104 |
105 | // Then:
106 | XCTAssertNotEqual(wordCount, 2)
107 | }
108 |
109 | func test_wordCountWithCommaSuccessScenario() {
110 | // Given:
111 | let source = "This is a test,string"
112 |
113 | // When:
114 | let wordCount = source.wordCount()
115 |
116 | // Then:
117 | XCTAssertEqual(wordCount, 5)
118 | }
119 |
120 | func test_wordCountWithCommaFailureScenario() {
121 | // Given:
122 | let source = "This is a test,string"
123 |
124 | // When:
125 | let wordCount = source.wordCount()
126 |
127 | // Then:
128 | XCTAssertNotEqual(wordCount, 4)
129 | }
130 |
131 | func test_isOneWordWithSuccessScenario() {
132 | // Given:
133 | let source = "Thisisateststring"
134 |
135 | // When:
136 | let isOneWord = source.isOneWord()
137 |
138 | // Then:
139 | XCTAssertTrue(isOneWord)
140 | }
141 |
142 | func test_isOneWordWithFailureScenario() {
143 | // Given:
144 | let source = "This is a test string"
145 |
146 | // When:
147 | let isOneWord = source.isOneWord()
148 |
149 | // Then:
150 | XCTAssertFalse(isOneWord)
151 | }
152 |
153 | func test_isOneWordWithCommaFailureScenario() {
154 | // Given:
155 | let source = "This,is,a,test,string"
156 |
157 | // When:
158 | let isOneWord = source.isOneWord()
159 |
160 | // Then:
161 | XCTAssertFalse(isOneWord)
162 | }
163 |
164 | func test_isOneWordWithFailureScenario_Japanese() {
165 | // Given:
166 | let source = "あなたはそれを行うべきではありません"
167 |
168 | // When:
169 | let isOneWord = source.isOneWord()
170 |
171 | // Then:
172 | XCTAssertFalse(isOneWord)
173 | }
174 | }
175 |
--------------------------------------------------------------------------------
/iOSTests/TestStoryboard.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/iOSTests/TestViewWithOwner.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/iOSTests/TestViewWithoutOwner.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/iOSTests/TimeIntervalConverterArabicTest.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TimeIntervalConverterArabicTest.swift
3 | // ViaSwiftUtils
4 | //
5 | // Copyright 2017 Viacom, Inc.
6 | //
7 | // Licensed under the Apache License, Version 2.0 (the "License");
8 | // you may not use this file except in compliance with the License.
9 | // You may obtain a copy of the License at
10 | //
11 | // http://www.apache.org/licenses/LICENSE-2.0
12 | //
13 | // Unless required by applicable law or agreed to in writing, software
14 | // distributed under the License is distributed on an "AS IS" BASIS,
15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | // See the License for the specific language governing permissions and
17 | // limitations under the License.
18 |
19 | import Foundation
20 | @testable import ViaSwiftUtils
21 | import XCTest
22 |
23 | class TimeIntervalConverterArabicTest: XCTestCase {
24 |
25 | override func setUp() {
26 | super.setUp()
27 |
28 | NSLocale.forceLocale(identifier: "ar_SA")
29 | }
30 |
31 | override func tearDown() {
32 | super.tearDown()
33 |
34 | NSLocale.undoForcing()
35 | }
36 |
37 | func testMediaDuration() {
38 | // Given
39 | let interval: TimeInterval = 18 * 60 + 37
40 |
41 | // When
42 | let formattedString = interval.asMediaDuration
43 |
44 | // Then
45 | let expected = "١٨:٣٧"
46 | XCTAssertEqual(formattedString, expected, "Expected string \(expected)")
47 | }
48 |
49 | func testToStringMinutes() {
50 | // Given
51 | let format = "mm:ss"
52 | let interval = 600
53 | let expected = "10:00"
54 | let timeInterval = TimeInterval(interval)
55 |
56 | // When
57 | let formattedString = timeInterval.string(withFormat: format)
58 |
59 | // Then
60 | XCTAssertEqual(formattedString, expected, "Expected string \(expected) even when locale is \(Locale.current)")
61 | }
62 |
63 | func testSecondsToStringHours() {
64 | // Given
65 | let format = "mm:ss"
66 | let interval = 3603
67 | let expected = "00:03"
68 | let timeInterval = TimeInterval(interval)
69 |
70 | // When
71 | let formattedString = timeInterval.string(withFormat: format)
72 |
73 | // Then
74 | XCTAssertEqual(formattedString, expected, "Expected string \(expected) even when locale is \(Locale.current)")
75 | }
76 |
77 | func testSecondsToStringYears() {
78 | // Given
79 | let format = "yyyy, mm:ss"
80 | let interval = 360_045_003
81 | let expected = "1981, 30:03"
82 | let timeInterval = TimeInterval(interval)
83 |
84 | // When
85 | let formattedString = timeInterval.string(withFormat: format)
86 |
87 | // Then
88 | XCTAssertEqual(formattedString, expected, "Expected string \(expected) even when locale is \(Locale.current)")
89 | }
90 |
91 | }
92 |
--------------------------------------------------------------------------------
/iOSTests/TimeIntervalConverterTest.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TimeIntervalConverterTest.swift
3 | // ViaSwiftUtils
4 | //
5 | // Copyright 2017 Viacom, Inc.
6 | //
7 | // Licensed under the Apache License, Version 2.0 (the "License");
8 | // you may not use this file except in compliance with the License.
9 | // You may obtain a copy of the License at
10 | //
11 | // http://www.apache.org/licenses/LICENSE-2.0
12 | //
13 | // Unless required by applicable law or agreed to in writing, software
14 | // distributed under the License is distributed on an "AS IS" BASIS,
15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | // See the License for the specific language governing permissions and
17 | // limitations under the License.
18 |
19 | import Foundation
20 | @testable import ViaSwiftUtils
21 | import XCTest
22 |
23 | class TimeIntervalConverterTest: XCTestCase {
24 |
25 | override func setUp() {
26 | super.setUp()
27 |
28 | NSLocale.forceLocale(identifier: "en_US")
29 | }
30 |
31 | override func tearDown() {
32 | super.tearDown()
33 |
34 | NSLocale.undoForcing()
35 | }
36 |
37 | func testMediaDuration() {
38 | // Given
39 | let interval: TimeInterval = 18 * 60 + 37
40 |
41 | // When
42 | let formattedString = interval.asMediaDuration
43 |
44 | // Then
45 | let expected = "18:37"
46 | XCTAssertEqual(formattedString, expected, "Expected string \(expected)")
47 | }
48 |
49 | func testToStringMinutes() {
50 | // Given
51 | let format = "mm:ss"
52 | let interval = 600
53 | let expected = "10:00"
54 | let timeInterval = TimeInterval(interval)
55 |
56 | // When
57 | let formattedString = timeInterval.string(withFormat: format)
58 |
59 | // Then
60 | XCTAssertEqual(formattedString, expected, "Expected string \(expected)")
61 | }
62 |
63 | func testSecondsToStringHours() {
64 | // Given
65 | let format = "mm:ss"
66 | let interval = 3603
67 | let expected = "00:03"
68 | let timeInterval = TimeInterval(interval)
69 |
70 | // When
71 | let formattedString = timeInterval.string(withFormat: format)
72 |
73 | // Then
74 | XCTAssertEqual(formattedString, expected, "Expected string \(expected)")
75 | }
76 |
77 | func testSecondsToStringYears() {
78 | // Given
79 | let format = "yyyy, mm:ss"
80 | let interval = 360_045_003
81 | let expected = "1981, 30:03"
82 | let timeInterval = TimeInterval(interval)
83 |
84 | // When
85 | let formattedString = timeInterval.string(withFormat: format)
86 |
87 | // Then
88 | XCTAssertEqual(formattedString, expected, "Expected string \(expected)")
89 | }
90 |
91 | }
92 |
--------------------------------------------------------------------------------
/iOSTests/UIButtonStateTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIButtonStateTests.swift
3 | // ViaSwiftUtils
4 | //
5 | // Copyright 2017 Viacom, Inc.
6 | //
7 | // Licensed under the Apache License, Version 2.0 (the "License");
8 | // you may not use this file except in compliance with the License.
9 | // You may obtain a copy of the License at
10 | //
11 | // http://www.apache.org/licenses/LICENSE-2.0
12 | //
13 | // Unless required by applicable law or agreed to in writing, software
14 | // distributed under the License is distributed on an "AS IS" BASIS,
15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | // See the License for the specific language governing permissions and
17 | // limitations under the License.
18 |
19 | @testable import ViaSwiftUtils
20 | import XCTest
21 |
22 | class UIButtonStateTests: XCTestCase {
23 |
24 | func testAllControlStates() {
25 | // Given
26 | for state in [UIControl.State.normal, .highlighted, .selected, .disabled, .application, .reserved] {
27 |
28 | // When, Then
29 | XCTAssertTrue(UIControl.State.allValues.contains(state), "Expected allValues to contain \(state)")
30 | }
31 | }
32 |
33 | func testFunctionsForAllControlStates() {
34 | // Given a button
35 | let button = UIButton(type: UIButton.ButtonType.custom)
36 | let title = "Click me!"
37 | let backgroundImage = UIImage()
38 | let frontImage = UIImage()
39 | let color = UIColor.brown
40 |
41 | // When
42 | button.setTitleForAllStates(title)
43 | button.setImageForAllStates(frontImage)
44 | button.setBackgroundImageForAllStates(backgroundImage)
45 | button.setTitleColorForAllStates(color)
46 |
47 | // Then
48 | for state in UIControl.State.allValues {
49 | //title is set for all states
50 | XCTAssertEqual(button.title(for: state), title, "Expected title for state \(state) to be \(title)")
51 | XCTAssertEqual(button.backgroundImage(for: state), backgroundImage, "Expected background image for state \(state) to be backgroundImage")
52 | XCTAssertEqual(button.image(for: state), frontImage, "Expected image for state \(state) to be frontImage")
53 | XCTAssertEqual(button.titleColor(for: state), color, "Expected color for state \(state) to be \(color)")
54 | }
55 |
56 | }
57 |
58 | func testImageForState() {
59 | // Given
60 | let button = UIButton(type: UIButton.ButtonType.custom)
61 | let frontImageNormal = UIImage()
62 | let frontImageHighlighted = UIImage()
63 | let frontImageSelected = UIImage()
64 | let frontImageClimax = UIImage()
65 |
66 | // When
67 | button.setImagesForStates(normal: frontImageNormal, highlighted: frontImageHighlighted, selected: frontImageSelected, climax: frontImageClimax )
68 |
69 | // Then
70 | XCTAssertEqual(button.image(for: .normal),
71 | frontImageNormal,
72 | "Expected image for state \(UIControl.State.normal) to be frontImageNormal")
73 | XCTAssertEqual(button.image(for: .highlighted),
74 | frontImageHighlighted,
75 | "Expected image for state \(UIControl.State.highlighted) to be frontImageHighlighted")
76 | XCTAssertEqual(button.image(for: .selected),
77 | frontImageSelected,
78 | "Expected image for state \(UIControl.State.selected) to be frontImageSelected")
79 | XCTAssertEqual(button.image(for: [.selected, .highlighted]),
80 | frontImageClimax,
81 | "Expected image for state \([UIControl.State.selected, UIControl.State.highlighted]) to be frontImageClimax")
82 | }
83 |
84 | }
85 |
--------------------------------------------------------------------------------
/iOSTests/UIImageColorTest.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIImageColorTest.swift
3 | // ViaSwiftUtils
4 | //
5 | // Copyright 2017 Viacom, Inc.
6 | //
7 | // Licensed under the Apache License, Version 2.0 (the "License");
8 | // you may not use this file except in compliance with the License.
9 | // You may obtain a copy of the License at
10 | //
11 | // http://www.apache.org/licenses/LICENSE-2.0
12 | //
13 | // Unless required by applicable law or agreed to in writing, software
14 | // distributed under the License is distributed on an "AS IS" BASIS,
15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | // See the License for the specific language governing permissions and
17 | // limitations under the License.
18 |
19 | @testable import ViaSwiftUtils
20 | import XCTest
21 |
22 | class UIImageColorTest: XCTestCase {
23 |
24 | func testConvenienceFailableInitializer() {
25 | // Given
26 | let black = UIColor.black
27 | let defaultSize = CGSize(width: 1.0 * UIScreen.main.scale, height: 1.0 * UIScreen.main.scale)
28 |
29 | // When
30 | let image = UIImage(color: black)
31 |
32 | // Then
33 | XCTAssertNotNil(image, "Expected image should not be nil")
34 | XCTAssertEqual(image?.size, defaultSize, "Expected image size to be \(defaultSize)")
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/iOSTests/UIImageViewRotationTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIImageViewRotationTests.swift
3 | // ViaSwiftUtils
4 | //
5 | // Copyright 2017 Viacom, Inc.
6 | //
7 | // Licensed under the Apache License, Version 2.0 (the "License");
8 | // you may not use this file except in compliance with the License.
9 | // You may obtain a copy of the License at
10 | //
11 | // http://www.apache.org/licenses/LICENSE-2.0
12 | //
13 | // Unless required by applicable law or agreed to in writing, software
14 | // distributed under the License is distributed on an "AS IS" BASIS,
15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | // See the License for the specific language governing permissions and
17 | // limitations under the License.
18 |
19 | @testable import ViaSwiftUtils
20 | import XCTest
21 |
22 | class UIImageViewRotationTests: XCTestCase {
23 |
24 | func testIsRotating() {
25 | // Given, When
26 | let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
27 |
28 | // Then
29 | XCTAssertFalse(imageView.isRotating, "Expected imageView to not be rotating before starts")
30 | }
31 |
32 | func testStartRotating() {
33 | // Given, When
34 | let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
35 |
36 | // When
37 | imageView.startRotating()
38 |
39 | // Then
40 | XCTAssertTrue(imageView.isRotating, "Expected imageView to be rotating after startRotating")
41 | }
42 |
43 | func testStopRotating() {
44 | // Given, When
45 | let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
46 |
47 | // When
48 | imageView.startRotating()
49 | imageView.stopRotating()
50 |
51 | // Then
52 | XCTAssertFalse(imageView.isRotating, "Expected imageView to not be rotating after stopRotating")
53 | }
54 |
55 | func testSlowIsSlowerThanNormal() {
56 | // Given, When
57 | let slow = UIImageView.AnimationDuration.slow
58 | let normal = UIImageView.AnimationDuration.normal
59 |
60 | // Then
61 | XCTAssertGreaterThan(slow.duration, normal.duration, "Expected slow duration to be slower than normal duration")
62 | }
63 |
64 | func testNormalIsSlowerThanFast() {
65 | // Given, When
66 | let normal = UIImageView.AnimationDuration.normal
67 | let fast = UIImageView.AnimationDuration.fast
68 |
69 | // Then
70 | XCTAssertGreaterThan(normal.duration, fast.duration, "Expected normal duration to be slower than fast duration")
71 | }
72 |
73 | func testCustomIsWhatYouGiveIt() {
74 | // Given, When
75 | let custom = UIImageView.AnimationDuration.custom(time: 0.2)
76 |
77 | // Then
78 | XCTAssertEqual(custom.duration, 0.2, "Expected custom duration to be exactly what you give it")
79 | }
80 |
81 | func testIsRemovedOnCompletion() {
82 | // Given
83 | let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
84 |
85 | // When
86 | imageView.startRotating(isRemovedOnCompletion: false)
87 |
88 | // Then
89 | if let animation = imageView.layer.animation(forKey: RotationAnimation.key) {
90 | XCTAssertFalse(animation.isRemovedOnCompletion)
91 | } else {
92 | XCTFail("imageView is missing animation for \(RotationAnimation.key)")
93 | }
94 | }
95 |
96 | }
97 |
--------------------------------------------------------------------------------
/iOSTests/UIViewXibTest.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIViewXibTest.swift
3 | // ViaSwiftUtils
4 | //
5 | // Copyright 2017 Viacom, Inc.
6 | //
7 | // Licensed under the Apache License, Version 2.0 (the "License");
8 | // you may not use this file except in compliance with the License.
9 | // You may obtain a copy of the License at
10 | //
11 | // http://www.apache.org/licenses/LICENSE-2.0
12 | //
13 | // Unless required by applicable law or agreed to in writing, software
14 | // distributed under the License is distributed on an "AS IS" BASIS,
15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | // See the License for the specific language governing permissions and
17 | // limitations under the License.
18 |
19 | import Foundation
20 | @testable import ViaSwiftUtils
21 | import XCTest
22 |
23 | class XibView: UIView { }
24 | class TestViewWithoutOwner: UIView { }
25 |
26 | class UIViewXibTest: XCTestCase {
27 |
28 | let expectedSubviewType = String(describing: XibView.self)
29 |
30 | func testLoadNibView() {
31 | // Given
32 | let frame = CGRect(x: 0.0, y: 0.0, width: 10.0, height: 10.0)
33 | let testView = TestViewWithoutOwner(frame: frame)
34 | let owner = testView
35 | let expectedNumberOfSubviews = 1
36 |
37 | // When
38 | testView.loadNibView(owner)
39 |
40 | // Then
41 | XCTAssertEqual(testView.subviews.count, expectedNumberOfSubviews, "Expected number of subviews to be \(expectedNumberOfSubviews)")
42 |
43 | let subviewType = String(describing: type(of: testView.subviews[0]))
44 | XCTAssertEqual(subviewType, expectedSubviewType, "Expected subview type to be \(expectedSubviewType)")
45 | }
46 |
47 | func testLoadFromNib() {
48 | // Given
49 | let nibName = String(describing: TestViewWithoutOwner.self)
50 | let bundle = Bundle(for: TestViewWithoutOwner.self)
51 |
52 | // When
53 | let view = UIView.loadFromNib(named: nibName, bundle: bundle)
54 |
55 | // Then
56 | XCTAssertNotNil(view, "Expected view not to be nil")
57 | view.map {
58 | let subviewType = String(describing: type(of: $0))
59 | XCTAssertEqual(subviewType, expectedSubviewType, "Expected view type to be \(expectedSubviewType)")
60 | }
61 | }
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/install_swiftlint.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Installs the SwiftLint package.
4 | # Tries to get the precompiled .pkg file from Github, but if that
5 | # fails just recompiles from source.
6 |
7 | set -e
8 |
9 | SWIFTLINT_PKG_PATH="/tmp/SwiftLint.pkg"
10 | SWIFTLINT_PKG_URL="https://github.com/realm/SwiftLint/releases/download/0.38.0/SwiftLint.pkg"
11 |
12 | wget --output-document=$SWIFTLINT_PKG_PATH $SWIFTLINT_PKG_URL
13 |
14 | if [ -f $SWIFTLINT_PKG_PATH ]; then
15 | echo "SwiftLint package exists! Installing it..."
16 | sudo installer -pkg $SWIFTLINT_PKG_PATH -target /
17 | else
18 | echo "SwiftLint package doesn't exist. Compiling from source..." &&
19 | git clone https://github.com/realm/SwiftLint.git /tmp/SwiftLint &&
20 | cd /tmp/SwiftLint &&
21 | git submodule update --init --recursive &&
22 | sudo make install
23 | fi
24 |
--------------------------------------------------------------------------------
/tvOSTests/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 |
--------------------------------------------------------------------------------
/tvOSTests/ViaSwiftUtilsTests_tvOSTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViaSwiftUtilsTests_tvOSTests.swift
3 | // ViaSwiftUtilsTests tvOSTests
4 | //
5 | // Copyright 2017 Viacom, Inc.
6 | //
7 | // Licensed under the Apache License, Version 2.0 (the "License");
8 | // you may not use this file except in compliance with the License.
9 | // You may obtain a copy of the License at
10 | //
11 | // http://www.apache.org/licenses/LICENSE-2.0
12 | //
13 | // Unless required by applicable law or agreed to in writing, software
14 | // distributed under the License is distributed on an "AS IS" BASIS,
15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | // See the License for the specific language governing permissions and
17 | // limitations under the License.
18 |
19 | import XCTest
20 |
21 | class ViaSwiftUtilsTestsTVOSTests: XCTestCase {
22 |
23 | override func setUp() {
24 | super.setUp()
25 | // Put setup code here. This method is called before the invocation of each test method in the class.
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 | // This is an example of a functional test case.
35 | // Use XCTAssert and related functions to verify your tests produce the correct results.
36 | }
37 |
38 | func testPerformanceExample() {
39 | // This is an example of a performance test case.
40 | self.measureBlock {
41 | // Put the code you want to measure the time of here.
42 | }
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------