Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9ec0cfaa8e | |||
| 1c78258f17 |
+2
-6
@@ -3,10 +3,6 @@ use_frameworks!
|
||||
target 'VersaPlayerOverlayContentExtension_Example' do
|
||||
pod 'VersaPlayerOverlayContentExtension', :path => '../'
|
||||
|
||||
target 'VersaPlayerOverlayContentExtension_Tests' do
|
||||
inherit! :search_paths
|
||||
|
||||
pod 'VersaPlayer'
|
||||
pod 'FBSnapshotTestCase' , '~> 2.1.4'
|
||||
end
|
||||
pod 'VersaPlayer'
|
||||
pod 'FBSnapshotTestCase' , '~> 2.1.4'
|
||||
end
|
||||
|
||||
@@ -4,8 +4,8 @@ PODS:
|
||||
- FBSnapshotTestCase/Core (2.1.4)
|
||||
- FBSnapshotTestCase/SwiftSupport (2.1.4):
|
||||
- FBSnapshotTestCase/Core
|
||||
- VersaPlayer (0.1.1)
|
||||
- VersaPlayerOverlayContentExtension (0.1.4):
|
||||
- VersaPlayer (1.2.1)
|
||||
- VersaPlayerOverlayContentExtension (0.1.6):
|
||||
- VersaPlayer
|
||||
|
||||
DEPENDENCIES:
|
||||
@@ -24,9 +24,9 @@ EXTERNAL SOURCES:
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
FBSnapshotTestCase: 094f9f314decbabe373b87cc339bea235a63e07a
|
||||
VersaPlayer: 92f5eab6d9ce0a12bcfc5eca4618446f03931ec8
|
||||
VersaPlayerOverlayContentExtension: d3cca8a799cf58369d4ac4637276a67a090f01b4
|
||||
VersaPlayer: ae33859d21559ff631b0dfb159f212af70631ef2
|
||||
VersaPlayerOverlayContentExtension: ddddd5e0da8aea0ba1b48511019b6122dbac8dea
|
||||
|
||||
PODFILE CHECKSUM: 26320abea2adf3d2ed79e3e641641149244c0896
|
||||
PODFILE CHECKSUM: 7373f52ff6adc7369a4d55b4c114f3805aafefb7
|
||||
|
||||
COCOAPODS: 1.5.3
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "VersaPlayerOverlayContentExtension",
|
||||
"version": "0.1.4",
|
||||
"version": "0.1.6",
|
||||
"summary": "VersaPlayer extension to enable overlay content.",
|
||||
"description": "VersaPlayer extension to enable overlay content functionality.",
|
||||
"homepage": "https://github.com/josejuanqm/VersaPlayerOverlayContentExtension",
|
||||
@@ -13,7 +13,7 @@
|
||||
},
|
||||
"source": {
|
||||
"git": "https://github.com/josejuanqm/VersaPlayerOverlayContentExtension.git",
|
||||
"tag": "0.1.4"
|
||||
"tag": "0.1.6"
|
||||
},
|
||||
"social_media_url": "https://twitter.com/josejuanqm",
|
||||
"platforms": {
|
||||
|
||||
Generated
+5
-5
@@ -4,8 +4,8 @@ PODS:
|
||||
- FBSnapshotTestCase/Core (2.1.4)
|
||||
- FBSnapshotTestCase/SwiftSupport (2.1.4):
|
||||
- FBSnapshotTestCase/Core
|
||||
- VersaPlayer (0.1.1)
|
||||
- VersaPlayerOverlayContentExtension (0.1.4):
|
||||
- VersaPlayer (1.2.1)
|
||||
- VersaPlayerOverlayContentExtension (0.1.6):
|
||||
- VersaPlayer
|
||||
|
||||
DEPENDENCIES:
|
||||
@@ -24,9 +24,9 @@ EXTERNAL SOURCES:
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
FBSnapshotTestCase: 094f9f314decbabe373b87cc339bea235a63e07a
|
||||
VersaPlayer: 92f5eab6d9ce0a12bcfc5eca4618446f03931ec8
|
||||
VersaPlayerOverlayContentExtension: d3cca8a799cf58369d4ac4637276a67a090f01b4
|
||||
VersaPlayer: ae33859d21559ff631b0dfb159f212af70631ef2
|
||||
VersaPlayerOverlayContentExtension: ddddd5e0da8aea0ba1b48511019b6122dbac8dea
|
||||
|
||||
PODFILE CHECKSUM: 26320abea2adf3d2ed79e3e641641149244c0896
|
||||
PODFILE CHECKSUM: 7373f52ff6adc7369a4d55b4c114f3805aafefb7
|
||||
|
||||
COCOAPODS: 1.5.3
|
||||
|
||||
+577
-715
File diff suppressed because it is too large
Load Diff
+33
@@ -1,6 +1,39 @@
|
||||
# Acknowledgements
|
||||
This application makes use of the following third party libraries:
|
||||
|
||||
## FBSnapshotTestCase
|
||||
|
||||
BSD License
|
||||
|
||||
For the FBSnapshotTestCase software
|
||||
|
||||
Copyright (c) 2013, Facebook, Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name Facebook nor the names of its contributors may be used to
|
||||
endorse or promote products derived from this software without specific
|
||||
prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
## VersaPlayer
|
||||
|
||||
Copyright (c) 2018 jose.juan.qm@gmail.com <jose.quintero@fox.com>
|
||||
|
||||
+39
@@ -12,6 +12,45 @@
|
||||
<key>Type</key>
|
||||
<string>PSGroupSpecifier</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>FooterText</key>
|
||||
<string>BSD License
|
||||
|
||||
For the FBSnapshotTestCase software
|
||||
|
||||
Copyright (c) 2013, Facebook, Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name Facebook nor the names of its contributors may be used to
|
||||
endorse or promote products derived from this software without specific
|
||||
prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
</string>
|
||||
<key>License</key>
|
||||
<string>BSD</string>
|
||||
<key>Title</key>
|
||||
<string>FBSnapshotTestCase</string>
|
||||
<key>Type</key>
|
||||
<string>PSGroupSpecifier</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>FooterText</key>
|
||||
<string>Copyright (c) 2018 jose.juan.qm@gmail.com <jose.quintero@fox.com>
|
||||
|
||||
+2
@@ -143,10 +143,12 @@ strip_invalid_archs() {
|
||||
|
||||
|
||||
if [[ "$CONFIGURATION" == "Debug" ]]; then
|
||||
install_framework "${BUILT_PRODUCTS_DIR}/FBSnapshotTestCase/FBSnapshotTestCase.framework"
|
||||
install_framework "${BUILT_PRODUCTS_DIR}/VersaPlayer/VersaPlayer.framework"
|
||||
install_framework "${BUILT_PRODUCTS_DIR}/VersaPlayerOverlayContentExtension/VersaPlayerOverlayContentExtension.framework"
|
||||
fi
|
||||
if [[ "$CONFIGURATION" == "Release" ]]; then
|
||||
install_framework "${BUILT_PRODUCTS_DIR}/FBSnapshotTestCase/FBSnapshotTestCase.framework"
|
||||
install_framework "${BUILT_PRODUCTS_DIR}/VersaPlayer/VersaPlayer.framework"
|
||||
install_framework "${BUILT_PRODUCTS_DIR}/VersaPlayerOverlayContentExtension/VersaPlayerOverlayContentExtension.framework"
|
||||
fi
|
||||
|
||||
+3
-3
@@ -1,9 +1,9 @@
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
|
||||
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/VersaPlayer" "${PODS_CONFIGURATION_BUILD_DIR}/VersaPlayerOverlayContentExtension"
|
||||
FRAMEWORK_SEARCH_PATHS = $(inherited) $(PLATFORM_DIR)/Developer/Library/Frameworks "${PODS_CONFIGURATION_BUILD_DIR}/FBSnapshotTestCase" "${PODS_CONFIGURATION_BUILD_DIR}/VersaPlayer" "${PODS_CONFIGURATION_BUILD_DIR}/VersaPlayerOverlayContentExtension"
|
||||
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
|
||||
LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
|
||||
OTHER_CFLAGS = $(inherited) -iquote "${PODS_CONFIGURATION_BUILD_DIR}/VersaPlayer/VersaPlayer.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/VersaPlayerOverlayContentExtension/VersaPlayerOverlayContentExtension.framework/Headers"
|
||||
OTHER_LDFLAGS = $(inherited) -framework "VersaPlayer" -framework "VersaPlayerOverlayContentExtension"
|
||||
OTHER_CFLAGS = $(inherited) -iquote "${PODS_CONFIGURATION_BUILD_DIR}/FBSnapshotTestCase/FBSnapshotTestCase.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/VersaPlayer/VersaPlayer.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/VersaPlayerOverlayContentExtension/VersaPlayerOverlayContentExtension.framework/Headers"
|
||||
OTHER_LDFLAGS = $(inherited) -framework "FBSnapshotTestCase" -framework "VersaPlayer" -framework "VersaPlayerOverlayContentExtension"
|
||||
OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
|
||||
PODS_BUILD_DIR = ${BUILD_DIR}
|
||||
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
||||
|
||||
+3
-3
@@ -1,9 +1,9 @@
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
|
||||
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/VersaPlayer" "${PODS_CONFIGURATION_BUILD_DIR}/VersaPlayerOverlayContentExtension"
|
||||
FRAMEWORK_SEARCH_PATHS = $(inherited) $(PLATFORM_DIR)/Developer/Library/Frameworks "${PODS_CONFIGURATION_BUILD_DIR}/FBSnapshotTestCase" "${PODS_CONFIGURATION_BUILD_DIR}/VersaPlayer" "${PODS_CONFIGURATION_BUILD_DIR}/VersaPlayerOverlayContentExtension"
|
||||
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
|
||||
LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
|
||||
OTHER_CFLAGS = $(inherited) -iquote "${PODS_CONFIGURATION_BUILD_DIR}/VersaPlayer/VersaPlayer.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/VersaPlayerOverlayContentExtension/VersaPlayerOverlayContentExtension.framework/Headers"
|
||||
OTHER_LDFLAGS = $(inherited) -framework "VersaPlayer" -framework "VersaPlayerOverlayContentExtension"
|
||||
OTHER_CFLAGS = $(inherited) -iquote "${PODS_CONFIGURATION_BUILD_DIR}/FBSnapshotTestCase/FBSnapshotTestCase.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/VersaPlayer/VersaPlayer.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/VersaPlayerOverlayContentExtension/VersaPlayerOverlayContentExtension.framework/Headers"
|
||||
OTHER_LDFLAGS = $(inherited) -framework "FBSnapshotTestCase" -framework "VersaPlayer" -framework "VersaPlayerOverlayContentExtension"
|
||||
OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
|
||||
PODS_BUILD_DIR = ${BUILD_DIR}
|
||||
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
||||
|
||||
Generated
-26
@@ -1,26 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>${CURRENT_PROJECT_VERSION}</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</plist>
|
||||
-59
@@ -1,59 +0,0 @@
|
||||
# Acknowledgements
|
||||
This application makes use of the following third party libraries:
|
||||
|
||||
## VersaPlayer
|
||||
|
||||
Copyright (c) 2018 jose.juan.qm@gmail.com <jose.quintero@fox.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
|
||||
## FBSnapshotTestCase
|
||||
|
||||
BSD License
|
||||
|
||||
For the FBSnapshotTestCase software
|
||||
|
||||
Copyright (c) 2013, Facebook, Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name Facebook nor the names of its contributors may be used to
|
||||
endorse or promote products derived from this software without specific
|
||||
prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Generated by CocoaPods - https://cocoapods.org
|
||||
-97
@@ -1,97 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>PreferenceSpecifiers</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>FooterText</key>
|
||||
<string>This application makes use of the following third party libraries:</string>
|
||||
<key>Title</key>
|
||||
<string>Acknowledgements</string>
|
||||
<key>Type</key>
|
||||
<string>PSGroupSpecifier</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>FooterText</key>
|
||||
<string>Copyright (c) 2018 jose.juan.qm@gmail.com <jose.quintero@fox.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
</string>
|
||||
<key>License</key>
|
||||
<string>MIT</string>
|
||||
<key>Title</key>
|
||||
<string>VersaPlayer</string>
|
||||
<key>Type</key>
|
||||
<string>PSGroupSpecifier</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>FooterText</key>
|
||||
<string>BSD License
|
||||
|
||||
For the FBSnapshotTestCase software
|
||||
|
||||
Copyright (c) 2013, Facebook, Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name Facebook nor the names of its contributors may be used to
|
||||
endorse or promote products derived from this software without specific
|
||||
prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
</string>
|
||||
<key>License</key>
|
||||
<string>BSD</string>
|
||||
<key>Title</key>
|
||||
<string>FBSnapshotTestCase</string>
|
||||
<key>Type</key>
|
||||
<string>PSGroupSpecifier</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>FooterText</key>
|
||||
<string>Generated by CocoaPods - https://cocoapods.org</string>
|
||||
<key>Title</key>
|
||||
<string></string>
|
||||
<key>Type</key>
|
||||
<string>PSGroupSpecifier</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>StringsTable</key>
|
||||
<string>Acknowledgements</string>
|
||||
<key>Title</key>
|
||||
<string>Acknowledgements</string>
|
||||
</dict>
|
||||
</plist>
|
||||
-5
@@ -1,5 +0,0 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
@interface PodsDummy_Pods_VersaPlayerOverlayContentExtension_Tests : NSObject
|
||||
@end
|
||||
@implementation PodsDummy_Pods_VersaPlayerOverlayContentExtension_Tests
|
||||
@end
|
||||
-155
@@ -1,155 +0,0 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
set -u
|
||||
set -o pipefail
|
||||
|
||||
if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then
|
||||
# If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy
|
||||
# frameworks to, so exit 0 (signalling the script phase was successful).
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
|
||||
mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
|
||||
|
||||
COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}"
|
||||
SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}"
|
||||
|
||||
# Used as a return value for each invocation of `strip_invalid_archs` function.
|
||||
STRIP_BINARY_RETVAL=0
|
||||
|
||||
# This protects against multiple targets copying the same framework dependency at the same time. The solution
|
||||
# was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html
|
||||
RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????")
|
||||
|
||||
# Copies and strips a vendored framework
|
||||
install_framework()
|
||||
{
|
||||
if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then
|
||||
local source="${BUILT_PRODUCTS_DIR}/$1"
|
||||
elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then
|
||||
local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")"
|
||||
elif [ -r "$1" ]; then
|
||||
local source="$1"
|
||||
fi
|
||||
|
||||
local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
|
||||
|
||||
if [ -L "${source}" ]; then
|
||||
echo "Symlinked..."
|
||||
source="$(readlink "${source}")"
|
||||
fi
|
||||
|
||||
# Use filter instead of exclude so missing patterns don't throw errors.
|
||||
echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\""
|
||||
rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}"
|
||||
|
||||
local basename
|
||||
basename="$(basename -s .framework "$1")"
|
||||
binary="${destination}/${basename}.framework/${basename}"
|
||||
if ! [ -r "$binary" ]; then
|
||||
binary="${destination}/${basename}"
|
||||
fi
|
||||
|
||||
# Strip invalid architectures so "fat" simulator / device frameworks work on device
|
||||
if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then
|
||||
strip_invalid_archs "$binary"
|
||||
fi
|
||||
|
||||
# Resign the code if required by the build settings to avoid unstable apps
|
||||
code_sign_if_enabled "${destination}/$(basename "$1")"
|
||||
|
||||
# Embed linked Swift runtime libraries. No longer necessary as of Xcode 7.
|
||||
if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then
|
||||
local swift_runtime_libs
|
||||
swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]})
|
||||
for lib in $swift_runtime_libs; do
|
||||
echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\""
|
||||
rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}"
|
||||
code_sign_if_enabled "${destination}/${lib}"
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
# Copies and strips a vendored dSYM
|
||||
install_dsym() {
|
||||
local source="$1"
|
||||
if [ -r "$source" ]; then
|
||||
# Copy the dSYM into a the targets temp dir.
|
||||
echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DERIVED_FILES_DIR}\""
|
||||
rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DERIVED_FILES_DIR}"
|
||||
|
||||
local basename
|
||||
basename="$(basename -s .framework.dSYM "$source")"
|
||||
binary="${DERIVED_FILES_DIR}/${basename}.framework.dSYM/Contents/Resources/DWARF/${basename}"
|
||||
|
||||
# Strip invalid architectures so "fat" simulator / device frameworks work on device
|
||||
if [[ "$(file "$binary")" == *"Mach-O dSYM companion"* ]]; then
|
||||
strip_invalid_archs "$binary"
|
||||
fi
|
||||
|
||||
if [[ $STRIP_BINARY_RETVAL == 1 ]]; then
|
||||
# Move the stripped file into its final destination.
|
||||
echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\""
|
||||
rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.framework.dSYM" "${DWARF_DSYM_FOLDER_PATH}"
|
||||
else
|
||||
# The dSYM was not stripped at all, in this case touch a fake folder so the input/output paths from Xcode do not reexecute this script because the file is missing.
|
||||
touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.framework.dSYM"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Signs a framework with the provided identity
|
||||
code_sign_if_enabled() {
|
||||
if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then
|
||||
# Use the current code_sign_identitiy
|
||||
echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}"
|
||||
local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'"
|
||||
|
||||
if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
|
||||
code_sign_cmd="$code_sign_cmd &"
|
||||
fi
|
||||
echo "$code_sign_cmd"
|
||||
eval "$code_sign_cmd"
|
||||
fi
|
||||
}
|
||||
|
||||
# Strip invalid architectures
|
||||
strip_invalid_archs() {
|
||||
binary="$1"
|
||||
# Get architectures for current target binary
|
||||
binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)"
|
||||
# Intersect them with the architectures we are building for
|
||||
intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)"
|
||||
# If there are no archs supported by this binary then warn the user
|
||||
if [[ -z "$intersected_archs" ]]; then
|
||||
echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)."
|
||||
STRIP_BINARY_RETVAL=0
|
||||
return
|
||||
fi
|
||||
stripped=""
|
||||
for arch in $binary_archs; do
|
||||
if ! [[ "${ARCHS}" == *"$arch"* ]]; then
|
||||
# Strip non-valid architectures in-place
|
||||
lipo -remove "$arch" -output "$binary" "$binary" || exit 1
|
||||
stripped="$stripped $arch"
|
||||
fi
|
||||
done
|
||||
if [[ "$stripped" ]]; then
|
||||
echo "Stripped $binary of architectures:$stripped"
|
||||
fi
|
||||
STRIP_BINARY_RETVAL=1
|
||||
}
|
||||
|
||||
|
||||
if [[ "$CONFIGURATION" == "Debug" ]]; then
|
||||
install_framework "${BUILT_PRODUCTS_DIR}/VersaPlayer/VersaPlayer.framework"
|
||||
install_framework "${BUILT_PRODUCTS_DIR}/FBSnapshotTestCase/FBSnapshotTestCase.framework"
|
||||
fi
|
||||
if [[ "$CONFIGURATION" == "Release" ]]; then
|
||||
install_framework "${BUILT_PRODUCTS_DIR}/VersaPlayer/VersaPlayer.framework"
|
||||
install_framework "${BUILT_PRODUCTS_DIR}/FBSnapshotTestCase/FBSnapshotTestCase.framework"
|
||||
fi
|
||||
if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
|
||||
wait
|
||||
fi
|
||||
-118
@@ -1,118 +0,0 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
set -u
|
||||
set -o pipefail
|
||||
|
||||
if [ -z ${UNLOCALIZED_RESOURCES_FOLDER_PATH+x} ]; then
|
||||
# If UNLOCALIZED_RESOURCES_FOLDER_PATH is not set, then there's nowhere for us to copy
|
||||
# resources to, so exit 0 (signalling the script phase was successful).
|
||||
exit 0
|
||||
fi
|
||||
|
||||
mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
|
||||
|
||||
RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt
|
||||
> "$RESOURCES_TO_COPY"
|
||||
|
||||
XCASSET_FILES=()
|
||||
|
||||
# This protects against multiple targets copying the same framework dependency at the same time. The solution
|
||||
# was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html
|
||||
RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????")
|
||||
|
||||
case "${TARGETED_DEVICE_FAMILY:-}" in
|
||||
1,2)
|
||||
TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone"
|
||||
;;
|
||||
1)
|
||||
TARGET_DEVICE_ARGS="--target-device iphone"
|
||||
;;
|
||||
2)
|
||||
TARGET_DEVICE_ARGS="--target-device ipad"
|
||||
;;
|
||||
3)
|
||||
TARGET_DEVICE_ARGS="--target-device tv"
|
||||
;;
|
||||
4)
|
||||
TARGET_DEVICE_ARGS="--target-device watch"
|
||||
;;
|
||||
*)
|
||||
TARGET_DEVICE_ARGS="--target-device mac"
|
||||
;;
|
||||
esac
|
||||
|
||||
install_resource()
|
||||
{
|
||||
if [[ "$1" = /* ]] ; then
|
||||
RESOURCE_PATH="$1"
|
||||
else
|
||||
RESOURCE_PATH="${PODS_ROOT}/$1"
|
||||
fi
|
||||
if [[ ! -e "$RESOURCE_PATH" ]] ; then
|
||||
cat << EOM
|
||||
error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script.
|
||||
EOM
|
||||
exit 1
|
||||
fi
|
||||
case $RESOURCE_PATH in
|
||||
*.storyboard)
|
||||
echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true
|
||||
ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS}
|
||||
;;
|
||||
*.xib)
|
||||
echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true
|
||||
ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS}
|
||||
;;
|
||||
*.framework)
|
||||
echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true
|
||||
mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
|
||||
echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true
|
||||
rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
|
||||
;;
|
||||
*.xcdatamodel)
|
||||
echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\"" || true
|
||||
xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom"
|
||||
;;
|
||||
*.xcdatamodeld)
|
||||
echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\"" || true
|
||||
xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd"
|
||||
;;
|
||||
*.xcmappingmodel)
|
||||
echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\"" || true
|
||||
xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm"
|
||||
;;
|
||||
*.xcassets)
|
||||
ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH"
|
||||
XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE")
|
||||
;;
|
||||
*)
|
||||
echo "$RESOURCE_PATH" || true
|
||||
echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
|
||||
rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
|
||||
if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then
|
||||
mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
|
||||
rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
|
||||
fi
|
||||
rm -f "$RESOURCES_TO_COPY"
|
||||
|
||||
if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "${XCASSET_FILES:-}" ]
|
||||
then
|
||||
# Find all other xcassets (this unfortunately includes those of path pods and other targets).
|
||||
OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d)
|
||||
while read line; do
|
||||
if [[ $line != "${PODS_ROOT}*" ]]; then
|
||||
XCASSET_FILES+=("$line")
|
||||
fi
|
||||
done <<<"$OTHER_XCASSETS"
|
||||
|
||||
if [ -z ${ASSETCATALOG_COMPILER_APPICON_NAME+x} ]; then
|
||||
printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
|
||||
else
|
||||
printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" --app-icon "${ASSETCATALOG_COMPILER_APPICON_NAME}" --output-partial-info-plist "${TARGET_TEMP_DIR}/assetcatalog_generated_info_cocoapods.plist"
|
||||
fi
|
||||
fi
|
||||
-16
@@ -1,16 +0,0 @@
|
||||
#ifdef __OBJC__
|
||||
#import <UIKit/UIKit.h>
|
||||
#else
|
||||
#ifndef FOUNDATION_EXPORT
|
||||
#if defined(__cplusplus)
|
||||
#define FOUNDATION_EXPORT extern "C"
|
||||
#else
|
||||
#define FOUNDATION_EXPORT extern
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
FOUNDATION_EXPORT double Pods_VersaPlayerOverlayContentExtension_TestsVersionNumber;
|
||||
FOUNDATION_EXPORT const unsigned char Pods_VersaPlayerOverlayContentExtension_TestsVersionString[];
|
||||
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
|
||||
FRAMEWORK_SEARCH_PATHS = $(inherited) $(PLATFORM_DIR)/Developer/Library/Frameworks "${PODS_CONFIGURATION_BUILD_DIR}/FBSnapshotTestCase" "${PODS_CONFIGURATION_BUILD_DIR}/VersaPlayer" "${PODS_CONFIGURATION_BUILD_DIR}/VersaPlayer" "${PODS_CONFIGURATION_BUILD_DIR}/VersaPlayerOverlayContentExtension"
|
||||
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
|
||||
LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
|
||||
OTHER_CFLAGS = $(inherited) -iquote "${PODS_CONFIGURATION_BUILD_DIR}/FBSnapshotTestCase/FBSnapshotTestCase.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/VersaPlayer/VersaPlayer.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/VersaPlayer/VersaPlayer.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/VersaPlayerOverlayContentExtension/VersaPlayerOverlayContentExtension.framework/Headers"
|
||||
OTHER_LDFLAGS = $(inherited) -framework "FBSnapshotTestCase" -framework "VersaPlayer"
|
||||
OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
|
||||
PODS_BUILD_DIR = ${BUILD_DIR}
|
||||
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
||||
PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
|
||||
PODS_ROOT = ${SRCROOT}/Pods
|
||||
-6
@@ -1,6 +0,0 @@
|
||||
framework module Pods_VersaPlayerOverlayContentExtension_Tests {
|
||||
umbrella header "Pods-VersaPlayerOverlayContentExtension_Tests-umbrella.h"
|
||||
|
||||
export *
|
||||
module * { export * }
|
||||
}
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
|
||||
FRAMEWORK_SEARCH_PATHS = $(inherited) $(PLATFORM_DIR)/Developer/Library/Frameworks "${PODS_CONFIGURATION_BUILD_DIR}/FBSnapshotTestCase" "${PODS_CONFIGURATION_BUILD_DIR}/VersaPlayer" "${PODS_CONFIGURATION_BUILD_DIR}/VersaPlayer" "${PODS_CONFIGURATION_BUILD_DIR}/VersaPlayerOverlayContentExtension"
|
||||
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
|
||||
LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
|
||||
OTHER_CFLAGS = $(inherited) -iquote "${PODS_CONFIGURATION_BUILD_DIR}/FBSnapshotTestCase/FBSnapshotTestCase.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/VersaPlayer/VersaPlayer.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/VersaPlayer/VersaPlayer.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/VersaPlayerOverlayContentExtension/VersaPlayerOverlayContentExtension.framework/Headers"
|
||||
OTHER_LDFLAGS = $(inherited) -framework "FBSnapshotTestCase" -framework "VersaPlayer"
|
||||
OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
|
||||
PODS_BUILD_DIR = ${BUILD_DIR}
|
||||
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
||||
PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
|
||||
PODS_ROOT = ${SRCROOT}/Pods
|
||||
+1
-1
@@ -15,7 +15,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.1.1</string>
|
||||
<string>1.2.1</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.1.4</string>
|
||||
<string>0.1.6</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
|
||||
Generated
+236
-10
@@ -9,10 +9,92 @@
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<ol>
|
||||
<li>
|
||||
<a href="#example">Example</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#installation">Installation</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#usage">Usage</a>
|
||||
</li>
|
||||
<ol>
|
||||
<li>
|
||||
<a href="#basic-usage">Basic Usage</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#adding-controls">Adding Controls</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#advanced-usage">Advanced Usage</a>
|
||||
</li>
|
||||
<ol>
|
||||
<li>
|
||||
<a href="#drm">Encrypted Content (Digital Rights Management)</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#tracks">Track Selection</a>
|
||||
</li>
|
||||
<ol>
|
||||
<li>
|
||||
<a href="#audio-tracks">Audio Tracks</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#video-tracks">Video Tracks</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#caption-tracks">Caption Tracks</a>
|
||||
</li>
|
||||
<ol>
|
||||
<li>
|
||||
<a href="#caption-styling">Caption Styling</a>
|
||||
</li>
|
||||
</ol>
|
||||
</ol>
|
||||
</ol>
|
||||
</ol>
|
||||
<li>
|
||||
<a href="#extensions">Extensions</a>
|
||||
</li>
|
||||
<ol>
|
||||
<li>
|
||||
<a href="#extensions">Airplay Extension</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#extensions">Ads Extension</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#extensions">Overlay Content Extension</a>
|
||||
</li>
|
||||
</ol>
|
||||
<li>
|
||||
<a href="#documentation">Documentation</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#contributors">Awesome People (Contributors)</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#donation">Donation</a>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
## :warning: tvOS Information
|
||||
|
||||
If you are looking for the tvOS player, head over to https://github.com/josejuanqm/TVersaPlayer
|
||||
|
||||
## Example
|
||||
|
||||
To run the example project, clone the repo, and run `pod install` from the Example directory first.
|
||||
|
||||
<div>
|
||||
<p align="center">
|
||||
<img src="https://github.com/josejuanqm/VersaPlayer/blob/master/RepoAssets/iphone.png" />
|
||||
</p>
|
||||
</div>
|
||||
|
||||
## Installation
|
||||
|
||||
[CocoaPods](http://cocoapods.org) is a dependency manager for Cocoa projects.
|
||||
@@ -35,21 +117,151 @@ pod 'VersaPlayer'
|
||||
|
||||
VersaPlayer aims to be simple to use but also flexible, to start using VersaPlayer first create a view programatically or via storyboard. Then add this few lines of code to start playing your video.
|
||||
|
||||
<div>
|
||||
<p align="center">
|
||||
<img src="https://github.com/josejuanqm/VersaPlayer/blob/master/simple_example.png" />
|
||||
</p>
|
||||
</div>
|
||||
```swift
|
||||
@IBOutlet weak var playerView: VersaPlayerView!
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
if let url = URL.init(string: "http://rmcdn.2mdn.net/Demo/html5/output.mp4") {
|
||||
let item = VersaPlayerItem(url: url)
|
||||
playerView.set(item: item)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Adding Controls
|
||||
|
||||
To add controls for your player use the VersaPlayerControls class, which comes packed with outlets to control your player, you can also add as many as you like by making a custom implementation.
|
||||
|
||||
<div>
|
||||
<p align="center">
|
||||
<img src="https://github.com/josejuanqm/VersaPlayer/blob/master/controls_example.png" />
|
||||
</p>
|
||||
</div>
|
||||
VersaPlayerControls class include the following outlets:
|
||||
|
||||
Outlet Name | Type | Action
|
||||
------------------------- | ------------------------- | -------------------------
|
||||
playPauseButton | VersaStatefullButton | Toggle playback
|
||||
fullscreenButton | VersaStatefullButton | Toggle fullscreen mode
|
||||
pipButton | VersaStatefullButton | Toggle PIP mode in supported devices
|
||||
rewindButton | VersaStatefullButton | Rewind playback
|
||||
forwardButton | VersaStatefullButton | Fast forward playback
|
||||
skipForwardButton | VersaStatefullButton | Skip forward the time specified in second at skipSize (found in VersaPlayerControls)
|
||||
skipBackwardButton | VersaStatefullButton | Skip backward the time specified in second at skipSize (found in VersaPlayerControls)
|
||||
seekbarSlider | VersaSeekbarSlider | Seek through playback
|
||||
currentTimeLabel | VersaTimeLabel | Indicate the current time
|
||||
totalTimeLabel | VersaTimeLabel | Indicate the total time
|
||||
bufferingView | UIView | Shown when player is buffering
|
||||
|
||||
```swift
|
||||
@IBOutlet weak var playerView: VersaPlayerView!
|
||||
@IBOutlet weak var controls: VersaPlayerControls!
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
playerView.use(controls: controls)
|
||||
if let url = URL.init(string: "http://rmcdn.2mdn.net/Demo/html5/output.mp4") {
|
||||
let item = VersaPlayerItem(url: url)
|
||||
playerView.set(item: item)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Advanced Usage
|
||||
|
||||
#### DRM
|
||||
|
||||
VersaPlayer also brings support for encrypted content, to make use of this funcionality you must implement VersaPlayerDecryptionDelegate and assign it to VersaPlayer's decryptionDelegate property.
|
||||
|
||||
To read more about this topic go to:
|
||||
|
||||
https://josejuanqm.github.io/Libraries-Documentation/VersaPlayerCore/Protocols/VersaPlayerDecryptionDelegate.html
|
||||
|
||||
#### Tracks
|
||||
|
||||
To make use of different media tracks, such as audio, video, or captioning, use VersaPlayerMediaTracks, found in VersaPlayer class.
|
||||
|
||||
to learn more about this properties go to:
|
||||
|
||||
https://josejuanqm.github.io/Libraries-Documentation/VersaPlayerCore/Classes/VersaPlayerMediaTrack.html
|
||||
|
||||
##### Audio Tracks
|
||||
|
||||
Audio tracks are specially helpfull when dealing with different languages, for example for a movie playback.
|
||||
|
||||
To select an audio track simply fetch available tracks with VersaPlayer's audioTracks property.
|
||||
|
||||
```swift
|
||||
@IBOutlet weak var playerView: VersaPlayer!
|
||||
|
||||
...
|
||||
|
||||
let tracks: [VersaPlayerMediaTrack] = playerView.player.currentItem?.audioTracks
|
||||
/// the name of the track
|
||||
let name = tracks.first?.name
|
||||
/// the language of the track
|
||||
let name = tracks.first?.language
|
||||
/// selecting the first one
|
||||
tracks.first?.select(for: playerView.player)
|
||||
```
|
||||
|
||||
##### Video Tracks
|
||||
|
||||
Video tracks are most helpfull when dealing with different renditions or different streams per video quality.
|
||||
|
||||
To select an video track simply follow the same principles as an audio track.
|
||||
|
||||
```swift
|
||||
@IBOutlet weak var playerView: VersaPlayer!
|
||||
|
||||
...
|
||||
|
||||
let tracks: [VersaPlayerMediaTrack] = playerView.player.currentItem?.videoTracks
|
||||
/// the name of the track
|
||||
let name = tracks.first?.name
|
||||
/// selecting the first one
|
||||
tracks.first?.select(for: playerView.player)
|
||||
```
|
||||
|
||||
##### Caption Tracks
|
||||
|
||||
Caption tracks are almost always helpfull. This can be used from a movie playback all the way to assitive content.
|
||||
|
||||
To select an video track simply follow the same principles as video and audio tracks.
|
||||
|
||||
```swift
|
||||
@IBOutlet weak var playerView: VersaPlayer!
|
||||
|
||||
...
|
||||
|
||||
let tracks: [VersaPlayerMediaTrack] = playerView.player.currentItem?.captionTracks
|
||||
/// the name of the track
|
||||
let name = tracks.first?.name
|
||||
/// the language of the track
|
||||
let name = tracks.first?.language
|
||||
/// selecting the first one
|
||||
tracks.first?.select(for: playerView.player)
|
||||
```
|
||||
|
||||
###### Caption Styling
|
||||
|
||||
Caption styling are not usually managed by the user, but when necessary, captionStyling property from VersaPlayer comes in handy.
|
||||
|
||||
Explore all the available attributes that can be changed here:
|
||||
|
||||
https://josejuanqm.github.io/Libraries-Documentation/VersaPlayerCore/Classes/VersaPlayerCaptionStyling.html
|
||||
|
||||
## Extensions
|
||||
|
||||
Versa is aimed to be versatile, and that's why it comes with an extensions feature, that lets you customize any aspect of the player by inheriting from VersaPlayerExtension.
|
||||
|
||||
This class comes with a player attribute that points to the player instance from which is being used.
|
||||
To add an extension use the add(extension ext:) method found in https://josejuanqm.github.io/Libraries-Documentation/VersaPlayerCore/Classes/VersaPlayer.html.
|
||||
|
||||
Here are some extensions for VersaPlayer that may be useful for you.
|
||||
|
||||
1. [AirPlay Extension](https://github.com/josejuanqm/VersaPlayerAirplayExtension)
|
||||
|
||||
2. [Ads Extension](https://github.com/josejuanqm/VersaPlayerAdsExtension)
|
||||
|
||||
3. [Overlay Content Extension](https://github.com/josejuanqm/VersaPlayerOverlayContentExtension)
|
||||
|
||||
|
||||
## Documentation
|
||||
|
||||
@@ -59,6 +271,20 @@ Full documentation avilable https://josejuanqm.github.io/Libraries-Documentation
|
||||
|
||||
Jose Quintero - jose.juan.qm@gmail.com
|
||||
|
||||
## Contributors
|
||||
|
||||
People that make VersaPlayer possible, Thank you!
|
||||
|
||||
<span><a href="https://github.com/josejuanqm"><img src="https://github.com/josejuanqm.png" alt="josejuanqm" width="50px"></a></span>
|
||||
<span><a href="https://github.com/pbeast"><img src="https://github.com/pbeast.png" alt="pbeast" width="50px"></a></span>
|
||||
|
||||
## Donation
|
||||
|
||||
If you like this project or has been helpful to you, you can buy me a cup of coffe :)
|
||||
Appreciate it!
|
||||
|
||||
[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=KGX5UDWNHBRNY)
|
||||
|
||||
## License
|
||||
|
||||
VersaPlayer is available under the MIT license. See the LICENSE file for more info.
|
||||
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// VersaPlayerPlaybackError.swift
|
||||
// VersaPlayer
|
||||
//
|
||||
// Created by Jose Quintero on 10/23/18.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public enum VersaPlayerPlaybackError {
|
||||
case unknown
|
||||
case notFound
|
||||
case unauthorized
|
||||
case authenticationError
|
||||
case forbidden
|
||||
case unavailable
|
||||
case mediaFileError
|
||||
case bandwidthExceeded
|
||||
case playlistUnchanged
|
||||
case wrongHostIP
|
||||
case wrongHostDNS
|
||||
case badURL
|
||||
case invalidRequest
|
||||
}
|
||||
@@ -1,171 +0,0 @@
|
||||
//
|
||||
// VPlayer.swift
|
||||
// VersaPlayer Demo
|
||||
//
|
||||
// Created by Jose Quintero on 10/11/18.
|
||||
// Copyright © 2018 Quasar. All rights reserved.
|
||||
//
|
||||
|
||||
import AVFoundation
|
||||
|
||||
open class VPlayer: AVPlayer {
|
||||
|
||||
/// Notification key to extract info
|
||||
public enum VPlayerNotificationInfoKey: String {
|
||||
case time = "VERSA_PLAYER_TIME"
|
||||
}
|
||||
|
||||
/// Notification name to post
|
||||
public enum VPlayerNotificationName: String {
|
||||
case assetLoaded = "VERSA_ASSET_ADDED"
|
||||
case timeChanged = "VERSA_TIME_CHANGED"
|
||||
case willPlay = "VERSA_PLAYER_STATE_WILL_PLAY"
|
||||
case play = "VERSA_PLAYER_STATE_PLAY"
|
||||
case pause = "VERSA_PLAYER_STATE_PAUSE"
|
||||
case buffering = "VERSA_PLAYER_BUFFERING"
|
||||
case endBuffering = "VERSA_PLAYER_END_BUFFERING"
|
||||
case didEnd = "VERSA_PLAYER_END_PLAYING"
|
||||
|
||||
/// Notification name representation
|
||||
public var notification: NSNotification.Name {
|
||||
return NSNotification.Name.init(self.rawValue)
|
||||
}
|
||||
}
|
||||
|
||||
/// VersaPlayer instance
|
||||
public var handler: VersaPlayer!
|
||||
|
||||
/// Whether player is buffering
|
||||
public var isBuffering: Bool = false
|
||||
|
||||
deinit {
|
||||
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.AVPlayerItemTimeJumped, object: self)
|
||||
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: self)
|
||||
}
|
||||
|
||||
/// Play content
|
||||
override open func play() {
|
||||
handler.playbackDelegate?.playbackWillBegin(forPlayer: self)
|
||||
NotificationCenter.default.post(name: VPlayer.VPlayerNotificationName.willPlay.notification, object: self, userInfo: nil)
|
||||
if !(handler.playbackDelegate?.playbackShouldBegin(forPlayer: self) ?? true) {
|
||||
return
|
||||
}
|
||||
NotificationCenter.default.post(name: VPlayer.VPlayerNotificationName.play.notification, object: self, userInfo: nil)
|
||||
super.play()
|
||||
handler.playbackDelegate?.playbackDidBegin(forPlayer: self)
|
||||
}
|
||||
|
||||
/// Pause content
|
||||
override open func pause() {
|
||||
NotificationCenter.default.post(name: VPlayer.VPlayerNotificationName.pause.notification, object: self, userInfo: nil)
|
||||
super.pause()
|
||||
}
|
||||
|
||||
/// Replace current item with a new one
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - item: AVPlayer item instance to be added
|
||||
override open func replaceCurrentItem(with item: AVPlayerItem?) {
|
||||
super.replaceCurrentItem(with: item)
|
||||
NotificationCenter.default.post(name: VPlayer.VPlayerNotificationName.assetLoaded.notification, object: self, userInfo: nil)
|
||||
if item != nil {
|
||||
currentItem!.addObserver(self, forKeyPath: "playbackBufferEmpty", options: .new, context: nil)
|
||||
currentItem!.addObserver(self, forKeyPath: "playbackLikelyToKeepUp", options: .new, context: nil)
|
||||
currentItem!.addObserver(self, forKeyPath: "playbackBufferFull", options: .new, context: nil)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension VPlayer {
|
||||
|
||||
/// Start time
|
||||
///
|
||||
/// - Returns: Player's current item start time as CMTime
|
||||
public func startTime() -> CMTime {
|
||||
guard let item = currentItem else {
|
||||
return CMTime(seconds: 0, preferredTimescale: CMTimeScale(NSEC_PER_SEC))
|
||||
}
|
||||
|
||||
if item.reversePlaybackEndTime.isValid {
|
||||
return item.reversePlaybackEndTime
|
||||
}else {
|
||||
return CMTime(seconds: 0, preferredTimescale: CMTimeScale(NSEC_PER_SEC))
|
||||
}
|
||||
}
|
||||
|
||||
/// End time
|
||||
///
|
||||
/// - Returns: Player's current item end time as CMTime
|
||||
public func endTime() -> CMTime {
|
||||
guard let item = currentItem else {
|
||||
return CMTime(seconds: 0, preferredTimescale: CMTimeScale(NSEC_PER_SEC))
|
||||
}
|
||||
|
||||
if item.forwardPlaybackEndTime.isValid {
|
||||
return item.forwardPlaybackEndTime
|
||||
}else {
|
||||
if item.duration.isValid && !item.duration.isIndefinite {
|
||||
return item.duration
|
||||
}else {
|
||||
return CMTime(seconds: 0, preferredTimescale: CMTimeScale(NSEC_PER_SEC))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Prepare players playback delegate observers
|
||||
public func preparePlayerPlaybackDelegate() {
|
||||
NotificationCenter.default.addObserver(forName: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: self, queue: OperationQueue.main) { (notification) in
|
||||
NotificationCenter.default.post(name: VPlayer.VPlayerNotificationName.didEnd.notification, object: self, userInfo: nil)
|
||||
self.handler.playbackDelegate?.playbackDidEnd(forPlayer: self)
|
||||
}
|
||||
NotificationCenter.default.addObserver(forName: NSNotification.Name.AVPlayerItemTimeJumped, object: self, queue: OperationQueue.main) { (notification) in
|
||||
self.handler.playbackDelegate?.playbackDidJump(forPlayer: self)
|
||||
}
|
||||
addPeriodicTimeObserver(
|
||||
forInterval: CMTime(
|
||||
seconds: 1,
|
||||
preferredTimescale: CMTimeScale(NSEC_PER_SEC)
|
||||
),
|
||||
queue: DispatchQueue.main) { (time) in
|
||||
NotificationCenter.default.post(name: VPlayer.VPlayerNotificationName.timeChanged.notification, object: self, userInfo: [VPlayerNotificationInfoKey.time.rawValue: time])
|
||||
self.handler.playbackDelegate?.timeDidChange(forPlayer: self, to: time)
|
||||
|
||||
}
|
||||
addObserver(self, forKeyPath: "status", options: NSKeyValueObservingOptions.new, context: nil)
|
||||
}
|
||||
|
||||
/// Value observer
|
||||
override open func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
|
||||
if let obj = object as? VPlayer, obj == self {
|
||||
if keyPath == "status" {
|
||||
switch status {
|
||||
case AVPlayerStatus.readyToPlay:
|
||||
handler.playbackDelegate?.playbackReady(forPlayer: self)
|
||||
case AVPlayerStatus.failed:
|
||||
handler.playbackDelegate?.playerDidFailToStart(forPlayer: self)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}else {
|
||||
switch keyPath ?? "" {
|
||||
case "playbackBufferEmpty":
|
||||
isBuffering = true
|
||||
NotificationCenter.default.post(name: VPlayer.VPlayerNotificationName.buffering.notification, object: self, userInfo: nil)
|
||||
handler.playbackDelegate?.startBuffering(forPlayer: self)
|
||||
case "playbackLikelyToKeepUp":
|
||||
isBuffering = false
|
||||
NotificationCenter.default.post(name: VPlayer.VPlayerNotificationName.endBuffering.notification, object: self, userInfo: nil)
|
||||
handler.playbackDelegate?.endBuffering(forPlayer: self)
|
||||
case "playbackBufferFull":
|
||||
isBuffering = false
|
||||
NotificationCenter.default.post(name: VPlayer.VPlayerNotificationName.endBuffering.notification, object: self, userInfo: nil)
|
||||
handler.playbackDelegate?.endBuffering(forPlayer: self)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
//
|
||||
// VPlayerItem.swift
|
||||
// VersaPlayer Demo
|
||||
//
|
||||
// Created by Jose Quintero on 10/11/18.
|
||||
// Copyright © 2018 Quasar. All rights reserved.
|
||||
//
|
||||
|
||||
import AVFoundation
|
||||
|
||||
open class VPlayerItem: AVPlayerItem {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,276 @@
|
||||
//
|
||||
// VersaPlayer.swift
|
||||
// VersaPlayer Demo
|
||||
//
|
||||
// Created by Jose Quintero on 10/11/18.
|
||||
// Copyright © 2018 Quasar. All rights reserved.
|
||||
//
|
||||
|
||||
import AVFoundation
|
||||
|
||||
open class VersaPlayer: AVPlayer, AVAssetResourceLoaderDelegate {
|
||||
|
||||
/// Dispatch queue for resource loader
|
||||
private let queue = DispatchQueue(label: "quasar.studio.versaplayer")
|
||||
|
||||
/// Notification key to extract info
|
||||
public enum VPlayerNotificationInfoKey: String {
|
||||
case time = "VERSA_PLAYER_TIME"
|
||||
}
|
||||
|
||||
/// Notification name to post
|
||||
public enum VPlayerNotificationName: String {
|
||||
case assetLoaded = "VERSA_ASSET_ADDED"
|
||||
case timeChanged = "VERSA_TIME_CHANGED"
|
||||
case willPlay = "VERSA_PLAYER_STATE_WILL_PLAY"
|
||||
case play = "VERSA_PLAYER_STATE_PLAY"
|
||||
case pause = "VERSA_PLAYER_STATE_PAUSE"
|
||||
case buffering = "VERSA_PLAYER_BUFFERING"
|
||||
case endBuffering = "VERSA_PLAYER_END_BUFFERING"
|
||||
case didEnd = "VERSA_PLAYER_END_PLAYING"
|
||||
|
||||
/// Notification name representation
|
||||
public var notification: NSNotification.Name {
|
||||
return NSNotification.Name.init(self.rawValue)
|
||||
}
|
||||
}
|
||||
|
||||
/// VersaPlayer instance
|
||||
public var handler: VersaPlayerView!
|
||||
|
||||
/// Caption text style rules
|
||||
lazy public var captionStyling: VersaPlayerCaptionStyling = {
|
||||
return VersaPlayerCaptionStyling(with: self)
|
||||
}()
|
||||
|
||||
/// Whether player is buffering
|
||||
public var isBuffering: Bool = false
|
||||
|
||||
deinit {
|
||||
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.AVPlayerItemTimeJumped, object: self)
|
||||
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: self)
|
||||
}
|
||||
|
||||
/// Play content
|
||||
override open func play() {
|
||||
handler.playbackDelegate?.playbackWillBegin(player: self)
|
||||
NotificationCenter.default.post(name: VersaPlayer.VPlayerNotificationName.willPlay.notification, object: self, userInfo: nil)
|
||||
if !(handler.playbackDelegate?.playbackShouldBegin(player: self) ?? true) {
|
||||
return
|
||||
}
|
||||
NotificationCenter.default.post(name: VersaPlayer.VPlayerNotificationName.play.notification, object: self, userInfo: nil)
|
||||
super.play()
|
||||
handler.playbackDelegate?.playbackDidBegin(player: self)
|
||||
}
|
||||
|
||||
/// Pause content
|
||||
override open func pause() {
|
||||
NotificationCenter.default.post(name: VersaPlayer.VPlayerNotificationName.pause.notification, object: self, userInfo: nil)
|
||||
super.pause()
|
||||
}
|
||||
|
||||
/// Replace current item with a new one
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - item: AVPlayer item instance to be added
|
||||
override open func replaceCurrentItem(with item: AVPlayerItem?) {
|
||||
if let asset = item?.asset as? AVURLAsset, let vitem = item as? VersaPlayerItem, vitem.isEncrypted {
|
||||
asset.resourceLoader.setDelegate(self, queue: queue)
|
||||
}
|
||||
|
||||
if currentItem != nil {
|
||||
currentItem!.removeObserver(self, forKeyPath: "playbackBufferEmpty")
|
||||
currentItem!.removeObserver(self, forKeyPath: "playbackLikelyToKeepUp")
|
||||
currentItem!.removeObserver(self, forKeyPath: "playbackBufferFull")
|
||||
currentItem!.removeObserver(self, forKeyPath: "status")
|
||||
}
|
||||
|
||||
super.replaceCurrentItem(with: item)
|
||||
NotificationCenter.default.post(name: VersaPlayer.VPlayerNotificationName.assetLoaded.notification, object: self, userInfo: nil)
|
||||
if item != nil {
|
||||
currentItem!.addObserver(self, forKeyPath: "playbackBufferEmpty", options: .new, context: nil)
|
||||
currentItem!.addObserver(self, forKeyPath: "playbackLikelyToKeepUp", options: .new, context: nil)
|
||||
currentItem!.addObserver(self, forKeyPath: "playbackBufferFull", options: .new, context: nil)
|
||||
currentItem!.addObserver(self, forKeyPath: "status", options: .new, context: nil)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension VersaPlayer {
|
||||
|
||||
/// Start time
|
||||
///
|
||||
/// - Returns: Player's current item start time as CMTime
|
||||
open func startTime() -> CMTime {
|
||||
guard let item = currentItem else {
|
||||
return CMTime(seconds: 0, preferredTimescale: CMTimeScale(NSEC_PER_SEC))
|
||||
}
|
||||
|
||||
if item.reversePlaybackEndTime.isValid {
|
||||
return item.reversePlaybackEndTime
|
||||
}else {
|
||||
return CMTime(seconds: 0, preferredTimescale: CMTimeScale(NSEC_PER_SEC))
|
||||
}
|
||||
}
|
||||
|
||||
/// End time
|
||||
///
|
||||
/// - Returns: Player's current item end time as CMTime
|
||||
open func endTime() -> CMTime {
|
||||
guard let item = currentItem else {
|
||||
return CMTime(seconds: 0, preferredTimescale: CMTimeScale(NSEC_PER_SEC))
|
||||
}
|
||||
|
||||
if item.forwardPlaybackEndTime.isValid {
|
||||
return item.forwardPlaybackEndTime
|
||||
}else {
|
||||
if item.duration.isValid && !item.duration.isIndefinite {
|
||||
return item.duration
|
||||
}else {
|
||||
return item.currentTime()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Prepare players playback delegate observers
|
||||
open func preparePlayerPlaybackDelegate() {
|
||||
NotificationCenter.default.addObserver(forName: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: nil, queue: OperationQueue.main) { (notification) in
|
||||
NotificationCenter.default.post(name: VersaPlayer.VPlayerNotificationName.didEnd.notification, object: self, userInfo: nil)
|
||||
self.handler.playbackDelegate?.playbackDidEnd(player: self)
|
||||
}
|
||||
NotificationCenter.default.addObserver(forName: NSNotification.Name.AVPlayerItemTimeJumped, object: self, queue: OperationQueue.main) { (notification) in
|
||||
self.handler.playbackDelegate?.playbackDidJump(player: self)
|
||||
}
|
||||
addPeriodicTimeObserver(
|
||||
forInterval: CMTime(
|
||||
seconds: 1,
|
||||
preferredTimescale: CMTimeScale(NSEC_PER_SEC)
|
||||
),
|
||||
queue: DispatchQueue.main) { (time) in
|
||||
NotificationCenter.default.post(name: VersaPlayer.VPlayerNotificationName.timeChanged.notification, object: self, userInfo: [VPlayerNotificationInfoKey.time.rawValue: time])
|
||||
self.handler.playbackDelegate?.timeDidChange(player: self, to: time)
|
||||
|
||||
}
|
||||
addObserver(self, forKeyPath: "status", options: NSKeyValueObservingOptions.new, context: nil)
|
||||
}
|
||||
|
||||
/// Value observer
|
||||
override open func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
|
||||
if let obj = object as? VersaPlayer, obj == self {
|
||||
if keyPath == "status" {
|
||||
switch status {
|
||||
case AVPlayerStatus.readyToPlay:
|
||||
handler.playbackDelegate?.playbackReady(player: self)
|
||||
case AVPlayerStatus.failed:
|
||||
handler.playbackDelegate?.playbackDidFailed(with: VersaPlayerPlaybackError.unknown)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}else {
|
||||
switch keyPath ?? "" {
|
||||
case "status":
|
||||
if let value = change?[.newKey] as? Int, let status = AVPlayerItem.Status(rawValue: value), let item = object as? AVPlayerItem {
|
||||
if status == .failed, let error = item.error as NSError?, let underlyingError = error.userInfo[NSUnderlyingErrorKey] as? NSError {
|
||||
var playbackError = VersaPlayerPlaybackError.unknown
|
||||
switch underlyingError.code {
|
||||
case -12937:
|
||||
playbackError = .authenticationError
|
||||
case -16840:
|
||||
playbackError = .unauthorized
|
||||
case -12660:
|
||||
playbackError = .forbidden
|
||||
case -12938:
|
||||
playbackError = .notFound
|
||||
case -12661:
|
||||
playbackError = .unavailable
|
||||
case -12645, -12889:
|
||||
playbackError = .mediaFileError
|
||||
case -12318:
|
||||
playbackError = .bandwidthExceeded
|
||||
case -12642:
|
||||
playbackError = .playlistUnchanged
|
||||
case -1004:
|
||||
playbackError = .wrongHostIP
|
||||
case -1003:
|
||||
playbackError = .wrongHostDNS
|
||||
case -1000:
|
||||
playbackError = .badURL
|
||||
case -1202:
|
||||
playbackError = .invalidRequest
|
||||
default:
|
||||
playbackError = .unknown
|
||||
}
|
||||
handler.playbackDelegate?.playbackDidFailed(with: playbackError)
|
||||
}
|
||||
}
|
||||
case "playbackBufferEmpty":
|
||||
isBuffering = true
|
||||
NotificationCenter.default.post(name: VersaPlayer.VPlayerNotificationName.buffering.notification, object: self, userInfo: nil)
|
||||
handler.playbackDelegate?.startBuffering(layer: self)
|
||||
case "playbackLikelyToKeepUp":
|
||||
isBuffering = false
|
||||
NotificationCenter.default.post(name: VersaPlayer.VPlayerNotificationName.endBuffering.notification, object: self, userInfo: nil)
|
||||
handler.playbackDelegate?.endBuffering(player: self)
|
||||
case "playbackBufferFull":
|
||||
isBuffering = false
|
||||
NotificationCenter.default.post(name: VersaPlayer.VPlayerNotificationName.endBuffering.notification, object: self, userInfo: nil)
|
||||
handler.playbackDelegate?.endBuffering(player: self)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func resourceLoader(_ resourceLoader: AVAssetResourceLoader, shouldWaitForLoadingOfRequestedResource loadingRequest: AVAssetResourceLoadingRequest) -> Bool {
|
||||
guard let url = loadingRequest.request.url else {
|
||||
print("VersaPlayerResourceLoadingError", #function, "Unable to read the url/host data.")
|
||||
loadingRequest.finishLoading(with: NSError(domain: "quasar.studio.error", code: -1, userInfo: nil))
|
||||
return false
|
||||
}
|
||||
|
||||
print("VersaPlayerResourceLoading: \(url)")
|
||||
|
||||
guard
|
||||
let certificateURL = handler.decryptionDelegate?.urlFor(player: self),
|
||||
let certificateData = try? Data(contentsOf: certificateURL) else {
|
||||
print("VersaPlayerResourceLoadingError", #function, "Unable to read the certificate data.")
|
||||
loadingRequest.finishLoading(with: NSError(domain: "quasar.studio.error", code: -2, userInfo: nil))
|
||||
return false
|
||||
}
|
||||
|
||||
let contentId = handler.decryptionDelegate?.contentIdFor(player: self) ?? ""
|
||||
guard
|
||||
let contentIdData = contentId.data(using: String.Encoding.utf8),
|
||||
let spcData = try? loadingRequest.streamingContentKeyRequestData(forApp: certificateData, contentIdentifier: contentIdData, options: nil),
|
||||
let dataRequest = loadingRequest.dataRequest else {
|
||||
loadingRequest.finishLoading(with: NSError(domain: "quasar.studio.error", code: -3, userInfo: nil))
|
||||
print("VersaPlayerResourceLoadingError", #function, "Unable to read the SPC data.")
|
||||
return false
|
||||
}
|
||||
|
||||
guard let ckcURL = handler.decryptionDelegate?.contentKeyContextURLFor(player: self) else {
|
||||
loadingRequest.finishLoading(with: NSError(domain: "quasar.studio.error", code: -4, userInfo: nil))
|
||||
print("VersaPlayerResourceLoadingError", #function, "Unable to read the ckcURL.")
|
||||
return false
|
||||
}
|
||||
var request = URLRequest(url: ckcURL)
|
||||
request.httpMethod = "POST"
|
||||
request.httpBody = spcData
|
||||
let session = URLSession(configuration: URLSessionConfiguration.default)
|
||||
let task = session.dataTask(with: request) { data, response, error in
|
||||
if let data = data {
|
||||
dataRequest.respond(with: data)
|
||||
loadingRequest.finishLoading()
|
||||
} else {
|
||||
print("VersaPlayerResourceLoadingError", #function, "Unable to fetch the CKC.")
|
||||
loadingRequest.finishLoading(with: NSError(domain: "quasar.studio.error", code: -5, userInfo: nil))
|
||||
}
|
||||
}
|
||||
task.resume()
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
+142
@@ -0,0 +1,142 @@
|
||||
//
|
||||
// VersaPlayerCaptionStyling.swift
|
||||
// VersaPlayer
|
||||
//
|
||||
// Created by Jose Quintero on 10/31/18.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import AVFoundation
|
||||
|
||||
public class VersaPlayerCaptionStyling {
|
||||
|
||||
var player: VersaPlayer
|
||||
var rules: [AVTextStyleRule] = []
|
||||
|
||||
init(with player: VersaPlayer) {
|
||||
self.player = player
|
||||
}
|
||||
|
||||
/// Set attribute
|
||||
public func set(attribute: CFString, value: Any, selector: String? = nil) {
|
||||
guard let style = AVTextStyleRule.init(textMarkupAttributes: [attribute as String : value], textSelector: selector) else {
|
||||
return
|
||||
}
|
||||
rules.append(style)
|
||||
player.currentItem?.textStyleRules = rules
|
||||
}
|
||||
|
||||
/// Remove all previously set attribute
|
||||
public func clearAttributes() {
|
||||
rules = []
|
||||
player.currentItem?.textStyleRules = rules
|
||||
}
|
||||
|
||||
/// Remove any previously set attribute
|
||||
public func remove(attribute: CFString) {
|
||||
player.currentItem?.textStyleRules?.removeAll(where: { (rule) -> Bool in
|
||||
return rule.textMarkupAttributes.contains(where: { (key, value) -> Bool in
|
||||
return key == attribute as String
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/// Value must be one of the CFString constants in Alignment Type Constants indicating the alignment in the writing direction of the first line of text of the cue. The writing direction is indicated by the value (or absence) of the kCMTextMarkupAttribute_VerticalLayout attribute. The default value of this attribute is kCMTextMarkupAlignmentType_Middle.
|
||||
/// If used, this attribute must be applied to the entire attributed string.
|
||||
public func set(alignment value: Any) {
|
||||
let attribute: CFString = kCMTextMarkupAttribute_Alignment
|
||||
set(attribute: attribute, value: value)
|
||||
}
|
||||
|
||||
/// Value must be a CFBoolean. The default is kCFBooleanFalse. If this attribute is kCFBooleanTrue, the text will be drawn with a bold style. Other styles such as italic may or may not be used as well.
|
||||
public func set(boldStyle value: Any) {
|
||||
let attribute: CFString = kCMTextMarkupAttribute_BoldStyle
|
||||
set(attribute: attribute, value: value)
|
||||
}
|
||||
|
||||
/// Value must be a CFBoolean. The default is kCFBooleanFalse. If this attribute is kCFBooleanTrue, the text will be rendered with an italic style. Other styles such as bold may or may not be used as well.
|
||||
public func set(italicStyle value: Any) {
|
||||
let attribute: CFString = kCMTextMarkupAttribute_ItalicStyle
|
||||
set(attribute: attribute, value: value)
|
||||
}
|
||||
|
||||
/// Value must be a CFString holding the family name of an installed font (for example, "Helvetica") that is used to render and/or measure text.
|
||||
/// When vended by legible output, an attributed string will have at most one of kCMTextMarkupAttribute_FontFamilyName or kCMTextMarkupAttribute_GenericFontFamilyName associated with each character.
|
||||
public func set(fontFamilyName value: Any) {
|
||||
let attribute: CFString = kCMTextMarkupAttribute_FontFamilyName
|
||||
set(attribute: attribute, value: value)
|
||||
}
|
||||
|
||||
/// Value must be a CFBoolean. The default is kCFBooleanFalse. If this attribute is kCFBooleanTrue, the text will be rendered with an underline. Other styles such as bold may or may not be used as well.
|
||||
public func set(underlineStyle value: Any) {
|
||||
let attribute: CFString = kCMTextMarkupAttribute_UnderlineStyle
|
||||
set(attribute: attribute, value: value)
|
||||
}
|
||||
|
||||
/// Value must be one of the CFString constants in Vertical Layout Constants indicating the progression direction for new vertical lines of text. If this attribute is present, it indicates the writing direction is vertical. The attribute value indicates whether new vertical text lines are added from left to right or from right to left. If this attribute is missing, the writing direction is horizontal.
|
||||
/// If used, this attribute must be applied to the entire attributed string.
|
||||
public func set(verticalLayout value: Any) {
|
||||
let attribute: CFString = kCMTextMarkupAttribute_VerticalLayout
|
||||
set(attribute: attribute, value: value)
|
||||
}
|
||||
|
||||
/// Value must be a non-negative CFNumber. This is a number holding a percentage of the size of the calculated default font size. A value of 120 indicates 20% larger than the default font size. A value of 80 indicates 80% of the default font size. The default value of 100 indicates no size difference.
|
||||
public func set(relativeFontSize value: Any) {
|
||||
let attribute: CFString = kCMTextMarkupAttribute_RelativeFontSize
|
||||
set(attribute: attribute, value: value)
|
||||
}
|
||||
|
||||
/// Value must be one of the CFString constants in Character Edge Style Constants that control the shape of the edges of drawn characters. The default value is kCMTextMarkupCharacterEdgeStyle_None.
|
||||
public func set(characterEdgeStyle value: Any) {
|
||||
let attribute: CFString = kCMTextMarkupAttribute_CharacterEdgeStyle
|
||||
set(attribute: attribute, value: value)
|
||||
}
|
||||
|
||||
/// Value must be a CFArray of 4 CFNumbers representing alpha, red, green, and blue fields with values between 0.0 and 1.0. The red, green and blue components are interpreted in the sRGB color space. The alpha indicates the opacity from 0.0 for transparent to 1.0 for 100% opaque.
|
||||
/// The color applies to the geometry (for example, a box) containing the text. The container's background color may have an alpha of 0 so it is not displayed even though the text is displayed. The color behind individual characters is optionally controllable with the kCMTextMarkupAttribute_CharacterBackgroundColorARGB attribute.
|
||||
/// If used, this attribute must be applied to the entire attributed string.
|
||||
public func set(backgroundColorARGB value: Any) {
|
||||
let attribute: CFString = kCMTextMarkupAttribute_BackgroundColorARGB
|
||||
set(attribute: attribute, value: value)
|
||||
}
|
||||
|
||||
/// Value must be a CFArray of 4 CFNumbers representing alpha, red, green, and blue fields with values between 0.0 and 1.0. The red, green and blue components are interpreted in the sRGB color space. The alpha indicates the opacity from 0.0 for transparent to 1.0 for 100% opaque.
|
||||
public func set(foregroundColorARGB value: Any) {
|
||||
let attribute: CFString = kCMTextMarkupAttribute_ForegroundColorARGB
|
||||
set(attribute: attribute, value: value)
|
||||
}
|
||||
|
||||
/// Value must be one of the CFString constants in Generic Font Names. Generic fonts must be mapped to the family name of an installed font before rendering and/or measuring text (see Media Accessibility Function).
|
||||
/// When vended by legible output, an attributed string will have at most one of kCMTextMarkupAttribute_FontFamilyName or kCMTextMarkupAttribute_GenericFontFamilyName associated with each character.
|
||||
public func set(genericFontFamilyName value: Any) {
|
||||
let attribute: CFString = kCMTextMarkupAttribute_GenericFontFamilyName
|
||||
set(attribute: attribute, value: value)
|
||||
}
|
||||
|
||||
/// Value must be a CFArray of 4 CFNumbers representing alpha, red, green, and blue fields with values between 0.0 and 1.0. The red, green and blue components are interpreted in the sRGB color space. The alpha indicates the opacity from 0.0 for transparent to 1.0 for 100% opaque.
|
||||
public func set(characterBackgroundColorARGB value: Any) {
|
||||
let attribute: CFString = kCMTextMarkupAttribute_CharacterBackgroundColorARGB
|
||||
set(attribute: attribute, value: value)
|
||||
}
|
||||
|
||||
/// Value must be a non-negative CFNumber. This is a number expressing the width of the bounding box for text layout as a percentage of the video frame's dimension in the writing direction. For a horizontal writing direction, it is the width. For a vertical writing direction, it is the height.
|
||||
/// If used, this attribute must be applied to the entire attributed string.
|
||||
public func set(writingDirectionSizePercentage value: Any) {
|
||||
let attribute: CFString = kCMTextMarkupAttribute_WritingDirectionSizePercentage
|
||||
set(attribute: attribute, value: value)
|
||||
}
|
||||
|
||||
/// Value must be a non-negative CFNumber. This is a number holding a percentage of the height of the video frame. For example, a value of 5 indicates that the base font size should be 5% of the height of the video.
|
||||
public func set(baseFontSizePercentageRelativeToVideoHeight value: Any) {
|
||||
let attribute: CFString = kCMTextMarkupAttribute_BaseFontSizePercentageRelativeToVideoHeight
|
||||
set(attribute: attribute, value: value)
|
||||
}
|
||||
|
||||
/// Value must be a non-negative CFNumber. This is a number expressing the position of the center of the cue relative to the writing direction. The line position is orthogonal (or perpendicular) to the writing direction (that is, for a horizontal writing direction, it is vertical and for a vertical writing direction, is is horizontal). This attribute expresses the line position as a percentage of the dimensions of the video frame in the relevant direction. For example, 0% is the top of the video frame and 100% is the bottom of the video frame for horizontal writing layout.
|
||||
/// If used, this attribute must be applied to the entire attributed string.
|
||||
public func set(orthogonalLinePositionPercentageRelativeToWritingDirection value: Any) {
|
||||
let attribute: CFString = kCMTextMarkupAttribute_OrthogonalLinePositionPercentageRelativeToWritingDirection
|
||||
set(attribute: attribute, value: value)
|
||||
}
|
||||
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
//
|
||||
// VPlayerItem.swift
|
||||
// VersaPlayer Demo
|
||||
//
|
||||
// Created by Jose Quintero on 10/11/18.
|
||||
// Copyright © 2018 Quasar. All rights reserved.
|
||||
//
|
||||
|
||||
import AVFoundation
|
||||
|
||||
open class VersaPlayerItem: AVPlayerItem {
|
||||
|
||||
/// whether content passed through the asset is encrypted and should be decrypted
|
||||
public var isEncrypted: Bool = false
|
||||
|
||||
public var audioTracks: [VersaPlayerMediaTrack] {
|
||||
return tracks(for: .audible)
|
||||
}
|
||||
|
||||
public var videoTracks: [VersaPlayerMediaTrack] {
|
||||
return tracks(for: .visual)
|
||||
}
|
||||
|
||||
public var captionTracks: [VersaPlayerMediaTrack] {
|
||||
return tracks(for: .legible)
|
||||
}
|
||||
|
||||
private func tracks(for characteristic: AVMediaCharacteristic) -> [VersaPlayerMediaTrack] {
|
||||
guard let group = asset.mediaSelectionGroup(forMediaCharacteristic: characteristic) else {
|
||||
return []
|
||||
}
|
||||
let options = group.options
|
||||
let tracks = options.map { (option) -> VersaPlayerMediaTrack in
|
||||
let title = option.displayName
|
||||
let language = option.extendedLanguageTag ?? "none"
|
||||
return VersaPlayerMediaTrack(option: option, group: group, name: title, language: language)
|
||||
}
|
||||
return tracks
|
||||
}
|
||||
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// VersaPlayerMediaTrack.swift
|
||||
// VersaPlayer
|
||||
//
|
||||
// Created by Jose Quintero on 10/30/18.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import AVFoundation
|
||||
|
||||
public struct VersaPlayerMediaTrack {
|
||||
public var option: AVMediaSelectionOption
|
||||
public var group: AVMediaSelectionGroup
|
||||
public var name: String
|
||||
public var language: String
|
||||
|
||||
public func select(for player: VersaPlayer) {
|
||||
player.currentItem?.select(option, in: group)
|
||||
}
|
||||
}
|
||||
Generated
+14
@@ -0,0 +1,14 @@
|
||||
//
|
||||
// VersaPlayerDecryptionDelegate.swift
|
||||
// VersaPlayer
|
||||
//
|
||||
// Created by Jose Quintero on 10/23/18.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public protocol VersaPlayerDecryptionDelegate {
|
||||
func urlFor(player: VersaPlayer) -> URL
|
||||
func contentIdFor(player: VersaPlayer) -> String
|
||||
func contentKeyContextURLFor(player: VersaPlayer) -> URL
|
||||
}
|
||||
+2
-2
@@ -11,9 +11,9 @@ import Foundation
|
||||
open class VersaPlayerExtension: NSObject {
|
||||
|
||||
/// VersaPlayer instance being used
|
||||
open var player: VersaPlayer
|
||||
open var player: VersaPlayerView
|
||||
|
||||
public init(with player: VersaPlayer) {
|
||||
public init(with player: VersaPlayerView) {
|
||||
self.player = player
|
||||
}
|
||||
|
||||
|
||||
Generated
+24
-24
@@ -14,64 +14,64 @@ public protocol VersaPlayerPlaybackDelegate {
|
||||
/// Notifies when playback time changes
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - player: VPlayer being used
|
||||
/// - player: VersaPlayer being used
|
||||
/// - time: Current time
|
||||
func timeDidChange(forPlayer player: VPlayer, to time: CMTime)
|
||||
func timeDidChange(player: VersaPlayer, to time: CMTime)
|
||||
|
||||
/// Whether if playback should begin on specified player
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - player: VPlayer being used
|
||||
/// - player: VersaPlayer being used
|
||||
///
|
||||
/// - Returns: Boolean to validate if should play
|
||||
func playbackShouldBegin(forPlayer player: VPlayer) -> Bool
|
||||
func playbackShouldBegin(player: VersaPlayer) -> Bool
|
||||
|
||||
/// Whether if playback is skipping frames
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - player: VPlayer being used
|
||||
func playbackDidJump(forPlayer player: VPlayer)
|
||||
/// - player: VersaPlayer being used
|
||||
func playbackDidJump(player: VersaPlayer)
|
||||
|
||||
/// Notifies when player will begin playback
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - player: VPlayer being used
|
||||
func playbackWillBegin(forPlayer player: VPlayer)
|
||||
/// - player: VersaPlayer being used
|
||||
func playbackWillBegin(player: VersaPlayer)
|
||||
|
||||
/// Notifies when playback is ready to play
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - player: VPlayer being used
|
||||
func playbackReady(forPlayer player: VPlayer)
|
||||
/// - player: VersaPlayer being used
|
||||
func playbackReady(player: VersaPlayer)
|
||||
|
||||
/// Notifies when playback did begin
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - player: VPlayer being used
|
||||
func playbackDidBegin(forPlayer player: VPlayer)
|
||||
/// - player: VersaPlayer being used
|
||||
func playbackDidBegin(player: VersaPlayer)
|
||||
|
||||
/// Notifies when player ended playback
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - player: VPlayer being used
|
||||
func playbackDidEnd(forPlayer player: VPlayer)
|
||||
|
||||
/// Notifies when player failed to start playback
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - player: VPlayer being used
|
||||
func playerDidFailToStart(forPlayer player: VPlayer)
|
||||
/// - player: VersaPlayer being used
|
||||
func playbackDidEnd(player: VersaPlayer)
|
||||
|
||||
/// Notifies when player starts buffering
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - player: VPlayer being used
|
||||
func startBuffering(forPlayer: VPlayer)
|
||||
/// - player: VersaPlayer being used
|
||||
func startBuffering(layer: VersaPlayer)
|
||||
|
||||
/// Notifies when player ends buffering
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - player: VPlayer being used
|
||||
func endBuffering(forPlayer: VPlayer)
|
||||
/// - player: VersaPlayer being used
|
||||
func endBuffering(player: VersaPlayer)
|
||||
|
||||
/// Notifies when playback fails with an error
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - error: playback error
|
||||
func playbackDidFailed(with error: VersaPlayerPlaybackError)
|
||||
|
||||
}
|
||||
|
||||
+4
-3
@@ -9,13 +9,13 @@
|
||||
import AVFoundation
|
||||
import AVKit
|
||||
|
||||
open class VPlayerLayer: CALayer {
|
||||
open class VersaPlayerLayer: CALayer {
|
||||
|
||||
/// Player Layer to be used
|
||||
public var playerLayer: AVPlayerLayer!
|
||||
|
||||
/// VersaPlayer instance being rendered
|
||||
public var handler: VersaPlayer!
|
||||
public var handler: VersaPlayerView!
|
||||
|
||||
override public init(layer: Any) {
|
||||
super.init(layer: layer)
|
||||
@@ -25,12 +25,13 @@ open class VPlayerLayer: CALayer {
|
||||
super.init()
|
||||
}
|
||||
|
||||
public convenience init(with player: VersaPlayer) {
|
||||
public convenience init(with player: VersaPlayerView) {
|
||||
self.init()
|
||||
playerLayer = AVPlayerLayer.init(player: player.player)
|
||||
let controller = AVPictureInPictureController(playerLayer: playerLayer)
|
||||
controller?.delegate = player
|
||||
player.pipController = controller
|
||||
|
||||
addSublayer(playerLayer)
|
||||
}
|
||||
|
||||
+5
-5
@@ -9,19 +9,19 @@
|
||||
import UIKit
|
||||
import AVKit
|
||||
|
||||
open class VPlayerRenderingView: UIView {
|
||||
open class VersaPlayerRenderingView: UIView {
|
||||
|
||||
/// VPlayerLayer instance used to render player content
|
||||
public var renderingLayer: VPlayerLayer!
|
||||
public var renderingLayer: VersaPlayerLayer!
|
||||
|
||||
/// VersaPlayer instance being rendered by renderingLayer
|
||||
public var player: VersaPlayer!
|
||||
public var player: VersaPlayerView!
|
||||
|
||||
/// Constructor
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - player: VersaPlayer instance to render.
|
||||
public init(with player: VersaPlayer) {
|
||||
public init(with player: VersaPlayerView) {
|
||||
super.init(frame: CGRect.zero)
|
||||
self.player = player
|
||||
}
|
||||
@@ -33,7 +33,7 @@ open class VPlayerRenderingView: UIView {
|
||||
override open func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
if renderingLayer == nil {
|
||||
renderingLayer = VPlayerLayer.init(with: player)
|
||||
renderingLayer = VersaPlayerLayer.init(with: player)
|
||||
layer.addSublayer(renderingLayer.playerLayer)
|
||||
}
|
||||
|
||||
Generated
+1
-1
@@ -18,7 +18,7 @@ open class VersaStatefulButton: UIButton {
|
||||
}
|
||||
}
|
||||
|
||||
public func set(active: Bool) {
|
||||
open func set(active: Bool) {
|
||||
if active {
|
||||
setImage(activeImage, for: .normal)
|
||||
}else {
|
||||
|
||||
Generated
+1
-1
@@ -12,7 +12,7 @@ open class VersaTimeLabel: UILabel {
|
||||
|
||||
public var timeFormat: String = "HH:mm:ss"
|
||||
|
||||
public func update(toTime: TimeInterval) {
|
||||
open func update(toTime: TimeInterval) {
|
||||
let date = Date(timeIntervalSince1970: toTime)
|
||||
let formatter = DateFormatter()
|
||||
formatter.timeZone = TimeZone.init(secondsFromGMT: 0)
|
||||
|
||||
+5
-5
@@ -50,7 +50,7 @@ open class VersaPlayerControlsBehaviour {
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - time: TimeInterval to check whether to update controls.
|
||||
public func update(with time: TimeInterval) {
|
||||
open func update(with time: TimeInterval) {
|
||||
elapsedTime = time
|
||||
if showingControls && shouldHideControls && !controls.handler.player.isBuffering && !controls.handler.isSeeking {
|
||||
let timediff = elapsedTime - activationTime
|
||||
@@ -61,7 +61,7 @@ open class VersaPlayerControlsBehaviour {
|
||||
}
|
||||
|
||||
/// Default activation block
|
||||
public func defaultActivationBlock() {
|
||||
open func defaultActivationBlock() {
|
||||
controls.isHidden = false
|
||||
UIView.animate(withDuration: 0.3, animations: {
|
||||
self.controls.alpha = 1
|
||||
@@ -69,7 +69,7 @@ open class VersaPlayerControlsBehaviour {
|
||||
}
|
||||
|
||||
/// Default deactivation block
|
||||
public func defaultDeactivationBlock() {
|
||||
open func defaultDeactivationBlock() {
|
||||
UIView.animate(withDuration: 0.3, animations: {
|
||||
self.controls.alpha = 0
|
||||
}, completion: {
|
||||
@@ -80,7 +80,7 @@ open class VersaPlayerControlsBehaviour {
|
||||
}
|
||||
|
||||
/// Hide the controls
|
||||
public func hide() {
|
||||
open func hide() {
|
||||
if deactivationBlock != nil {
|
||||
deactivationBlock!(controls)
|
||||
}else {
|
||||
@@ -90,7 +90,7 @@ open class VersaPlayerControlsBehaviour {
|
||||
}
|
||||
|
||||
/// Show the controls
|
||||
public func show() {
|
||||
open func show() {
|
||||
if !shouldShowControls {
|
||||
return
|
||||
}
|
||||
|
||||
+20
-6
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// VersaPlayerGestureRecieverView.swift
|
||||
// VersaPlayer Demo
|
||||
// VersaPlayerView Demo
|
||||
//
|
||||
// Created by Jose Quintero on 10/11/18.
|
||||
// Copyright © 2018 Quasar. All rights reserved.
|
||||
@@ -13,9 +13,12 @@ open class VersaPlayerGestureRecieverView: UIView {
|
||||
/// VersaPlayerGestureRecieverViewDelegate instance
|
||||
public var delegate: VersaPlayerGestureRecieverViewDelegate? = nil
|
||||
|
||||
/// UITapGestureRecognizer
|
||||
/// Single tap UITapGestureRecognizer
|
||||
public var tapGesture: UITapGestureRecognizer? = nil
|
||||
|
||||
/// Double tap UITapGestureRecognizer
|
||||
public var doubleTapGesture: UITapGestureRecognizer? = nil
|
||||
|
||||
/// UIPanGestureRecognizer
|
||||
public var panGesture: UIPanGestureRecognizer? = nil
|
||||
|
||||
@@ -43,32 +46,43 @@ open class VersaPlayerGestureRecieverView: UIView {
|
||||
}
|
||||
|
||||
/// Prepare the view gesture recognizers
|
||||
public func prepare() {
|
||||
open func prepare() {
|
||||
ready = true
|
||||
isUserInteractionEnabled = true
|
||||
tapGesture = UITapGestureRecognizer(target: self, action: #selector(tapHandler(with:)))
|
||||
tapGesture?.numberOfTapsRequired = 1
|
||||
|
||||
doubleTapGesture = UITapGestureRecognizer(target: self, action: #selector(doubleTapHandler(with:)))
|
||||
doubleTapGesture?.numberOfTapsRequired = 2
|
||||
|
||||
tapGesture?.require(toFail: doubleTapGesture!)
|
||||
|
||||
pinchGesture = UIPinchGestureRecognizer(target: self, action: #selector(pinchHandler(with:)))
|
||||
panGesture = UIPanGestureRecognizer(target: self, action: #selector(panHandler(with:)))
|
||||
panGesture?.minimumNumberOfTouches = 1
|
||||
|
||||
addGestureRecognizer(tapGesture!)
|
||||
addGestureRecognizer(doubleTapGesture!)
|
||||
addGestureRecognizer(panGesture!)
|
||||
addGestureRecognizer(pinchGesture!)
|
||||
}
|
||||
|
||||
|
||||
@objc public func tapHandler(with sender: UITapGestureRecognizer) {
|
||||
@objc open func tapHandler(with sender: UITapGestureRecognizer) {
|
||||
delegate?.didTap(at: sender.location(in: self))
|
||||
}
|
||||
|
||||
@objc public func pinchHandler(with sender: UIPinchGestureRecognizer) {
|
||||
@objc open func doubleTapHandler(with sender: UITapGestureRecognizer) {
|
||||
delegate?.didDoubleTap(at: sender.location(in: self))
|
||||
}
|
||||
|
||||
@objc open func pinchHandler(with sender: UIPinchGestureRecognizer) {
|
||||
if sender.state == .ended {
|
||||
delegate?.didPinch(with: sender.scale)
|
||||
}
|
||||
}
|
||||
|
||||
@objc public func panHandler(with sender: UIPanGestureRecognizer) {
|
||||
@objc open func panHandler(with sender: UIPanGestureRecognizer) {
|
||||
if sender.state == .began {
|
||||
panGestureInitialPoint = sender.location(in: self)
|
||||
}
|
||||
|
||||
+8
-2
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// VersaPlayerGestureRecieverViewDelegate.swift
|
||||
// VersaPlayer Demo
|
||||
// VersaPlayerView Demo
|
||||
//
|
||||
// Created by Jose Quintero on 10/11/18.
|
||||
// Copyright © 2018 Quasar. All rights reserved.
|
||||
@@ -20,9 +20,15 @@ public protocol VersaPlayerGestureRecieverViewDelegate {
|
||||
/// Tap was recognized
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - scale: CGPoin at wich touch was recognized
|
||||
/// - point: CGPoint at wich touch was recognized
|
||||
func didTap(at point: CGPoint)
|
||||
|
||||
/// Double tap was recognized
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - point: CGPoint at wich touch was recognized
|
||||
func didDoubleTap(at point: CGPoint)
|
||||
|
||||
/// Pan was recognized
|
||||
///
|
||||
/// - Parameters:
|
||||
|
||||
-48
@@ -1,48 +0,0 @@
|
||||
//
|
||||
// VersaPlayerControlsExtension.swift
|
||||
// VersaPlayer Demo
|
||||
//
|
||||
// Created by Jose Quintero on 10/11/18.
|
||||
// Copyright © 2018 Quasar. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreMedia
|
||||
|
||||
public extension VersaPlayer {
|
||||
|
||||
private var versaPlayerControlsTag: Int { return 2000 }
|
||||
|
||||
/// VersaPlayerControls instance being used to display controls
|
||||
public var controls: VersaPlayerControls? {
|
||||
get {
|
||||
return viewWithTag(versaPlayerControlsTag) as? VersaPlayerControls
|
||||
}
|
||||
}
|
||||
|
||||
/// VersaPlayerControls instance to display controls in player, using VersaPlayerGestureRecieverView instance
|
||||
/// to handle gestures
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - controls: VersaPlayerControls instance used to display controls
|
||||
/// - gestureReciever: Optional gesture reciever view to be used to recieve gestures
|
||||
public func use(controls: VersaPlayerControls, with gestureReciever: VersaPlayerGestureRecieverView? = nil) {
|
||||
let coordinator = VersaPlayerControlsCoordinator()
|
||||
coordinator.player = self
|
||||
coordinator.controls = controls
|
||||
coordinator.gestureReciever = gestureReciever
|
||||
controls.controlsCoordinator = coordinator
|
||||
addSubview(coordinator)
|
||||
controls.tag = versaPlayerControlsTag
|
||||
bringSubview(toFront: controls)
|
||||
}
|
||||
|
||||
/// Update controls to specified time
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - time: Time to be updated to
|
||||
public func updateControls(toTime time: CMTime) {
|
||||
controls?.timeDidChange(toTime: time)
|
||||
}
|
||||
|
||||
}
|
||||
Generated
+32
-32
@@ -13,7 +13,7 @@ import AVKit
|
||||
open class VersaPlayerControls: UIView {
|
||||
|
||||
/// VersaPlayer intance being controlled
|
||||
public var handler: VersaPlayer!
|
||||
public var handler: VersaPlayerView!
|
||||
|
||||
/// VersaPlayerControlsBehaviour being used to validate ui
|
||||
public var behaviour: VersaPlayerControlsBehaviour!
|
||||
@@ -62,11 +62,11 @@ open class VersaPlayerControls: UIView {
|
||||
public var skipSize: Double = 30
|
||||
|
||||
deinit {
|
||||
NotificationCenter.default.removeObserver(self, name: VPlayer.VPlayerNotificationName.timeChanged.notification, object: nil)
|
||||
NotificationCenter.default.removeObserver(self, name: VPlayer.VPlayerNotificationName.play.notification, object: nil)
|
||||
NotificationCenter.default.removeObserver(self, name: VPlayer.VPlayerNotificationName.pause.notification, object: nil)
|
||||
NotificationCenter.default.removeObserver(self, name: VPlayer.VPlayerNotificationName.buffering.notification, object: nil)
|
||||
NotificationCenter.default.removeObserver(self, name: VPlayer.VPlayerNotificationName.endBuffering.notification, object: nil)
|
||||
NotificationCenter.default.removeObserver(self, name: VersaPlayer.VPlayerNotificationName.timeChanged.notification, object: nil)
|
||||
NotificationCenter.default.removeObserver(self, name: VersaPlayer.VPlayerNotificationName.play.notification, object: nil)
|
||||
NotificationCenter.default.removeObserver(self, name: VersaPlayer.VPlayerNotificationName.pause.notification, object: nil)
|
||||
NotificationCenter.default.removeObserver(self, name: VersaPlayer.VPlayerNotificationName.buffering.notification, object: nil)
|
||||
NotificationCenter.default.removeObserver(self, name: VersaPlayer.VPlayerNotificationName.endBuffering.notification, object: nil)
|
||||
}
|
||||
|
||||
override open func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
|
||||
@@ -88,7 +88,7 @@ open class VersaPlayerControls: UIView {
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - time: CMTime representation of the current playback time
|
||||
public func timeDidChange(toTime time: CMTime) {
|
||||
open func timeDidChange(toTime time: CMTime) {
|
||||
currentTimeLabel?.update(toTime: time.seconds)
|
||||
totalTimeLabel?.update(toTime: handler.player.endTime().seconds)
|
||||
seekbarSlider?.minimumValue = Float(handler.player.startTime().seconds)
|
||||
@@ -101,12 +101,12 @@ open class VersaPlayerControls: UIView {
|
||||
}
|
||||
|
||||
/// Remove coordinator from player
|
||||
public func removeFromPlayer() {
|
||||
open func removeFromPlayer() {
|
||||
controlsCoordinator.removeFromSuperview()
|
||||
}
|
||||
|
||||
/// Prepare controls targets and notification listeners
|
||||
public func prepare() {
|
||||
open func prepare() {
|
||||
layout()
|
||||
|
||||
playPauseButton?.addTarget(self, action: #selector(togglePlayback), for: .touchUpInside)
|
||||
@@ -137,7 +137,7 @@ open class VersaPlayerControls: UIView {
|
||||
}
|
||||
|
||||
/// Layout in parent view
|
||||
public func layout() {
|
||||
open func layout() {
|
||||
translatesAutoresizingMaskIntoConstraints = false
|
||||
if let parent = superview {
|
||||
topAnchor.constraint(equalTo: parent.topAnchor).isActive = true
|
||||
@@ -148,60 +148,60 @@ open class VersaPlayerControls: UIView {
|
||||
}
|
||||
|
||||
/// Prepares the notification observers/listeners
|
||||
public func prepareNotificationListener() {
|
||||
NotificationCenter.default.addObserver(forName: VPlayer.VPlayerNotificationName.timeChanged.notification, object: nil, queue: OperationQueue.main) { (notification) in
|
||||
if let time = notification.userInfo?[VPlayer.VPlayerNotificationInfoKey.time.rawValue] as? CMTime {
|
||||
open func prepareNotificationListener() {
|
||||
NotificationCenter.default.addObserver(forName: VersaPlayer.VPlayerNotificationName.timeChanged.notification, object: nil, queue: OperationQueue.main) { (notification) in
|
||||
if let time = notification.userInfo?[VersaPlayer.VPlayerNotificationInfoKey.time.rawValue] as? CMTime {
|
||||
self.timeDidChange(toTime: time)
|
||||
}
|
||||
}
|
||||
NotificationCenter.default.addObserver(forName: VPlayer.VPlayerNotificationName.didEnd.notification, object: nil, queue: OperationQueue.main) { (notification) in
|
||||
NotificationCenter.default.addObserver(forName: VersaPlayer.VPlayerNotificationName.didEnd.notification, object: nil, queue: OperationQueue.main) { (notification) in
|
||||
self.playPauseButton?.set(active: false)
|
||||
}
|
||||
NotificationCenter.default.addObserver(forName: VPlayer.VPlayerNotificationName.play.notification, object: nil, queue: OperationQueue.main) { (notification) in
|
||||
NotificationCenter.default.addObserver(forName: VersaPlayer.VPlayerNotificationName.play.notification, object: nil, queue: OperationQueue.main) { (notification) in
|
||||
self.playPauseButton?.set(active: true)
|
||||
}
|
||||
NotificationCenter.default.addObserver(forName: VPlayer.VPlayerNotificationName.pause.notification, object: nil, queue: OperationQueue.main) { (notification) in
|
||||
NotificationCenter.default.addObserver(forName: VersaPlayer.VPlayerNotificationName.pause.notification, object: nil, queue: OperationQueue.main) { (notification) in
|
||||
self.playPauseButton?.set(active: false)
|
||||
}
|
||||
NotificationCenter.default.addObserver(forName: VPlayer.VPlayerNotificationName.endBuffering.notification, object: nil, queue: OperationQueue.main) { (notification) in
|
||||
NotificationCenter.default.addObserver(forName: VersaPlayer.VPlayerNotificationName.endBuffering.notification, object: nil, queue: OperationQueue.main) { (notification) in
|
||||
self.hideBuffering()
|
||||
}
|
||||
NotificationCenter.default.addObserver(forName: VPlayer.VPlayerNotificationName.buffering.notification, object: nil, queue: OperationQueue.main) { (notification) in
|
||||
NotificationCenter.default.addObserver(forName: VersaPlayer.VPlayerNotificationName.buffering.notification, object: nil, queue: OperationQueue.main) { (notification) in
|
||||
self.showBuffering()
|
||||
}
|
||||
}
|
||||
|
||||
/// Prepare the seekbar values
|
||||
public func prepareSeekbar() {
|
||||
open func prepareSeekbar() {
|
||||
seekbarSlider?.value = Float(handler.player.currentTime().seconds)
|
||||
seekbarSlider?.minimumValue = Float(handler.player.startTime().seconds)
|
||||
seekbarSlider?.maximumValue = Float(handler.player.endTime().seconds)
|
||||
}
|
||||
|
||||
/// Show buffering view
|
||||
public func showBuffering() {
|
||||
open func showBuffering() {
|
||||
bufferingView?.isHidden = false
|
||||
}
|
||||
|
||||
/// Hide buffering view
|
||||
public func hideBuffering() {
|
||||
open func hideBuffering() {
|
||||
bufferingView?.isHidden = true
|
||||
}
|
||||
|
||||
/// Skip forward (n) seconds in time
|
||||
@IBAction public func skipForward() {
|
||||
@IBAction open func skipForward() {
|
||||
let time = handler.player.currentTime() + CMTime(seconds: skipSize, preferredTimescale: CMTimeScale(NSEC_PER_SEC))
|
||||
handler.player.seek(to: time)
|
||||
}
|
||||
|
||||
/// Skip backward (n) seconds in time
|
||||
@IBAction public func skipBackward() {
|
||||
@IBAction open func skipBackward() {
|
||||
let time = handler.player.currentTime() - CMTime(seconds: skipSize, preferredTimescale: CMTimeScale(NSEC_PER_SEC))
|
||||
handler.player.seek(to: time)
|
||||
}
|
||||
|
||||
/// End seeking
|
||||
@IBAction public func seekingEnd() {
|
||||
@IBAction open func seekingEnd() {
|
||||
handler.isSeeking = false
|
||||
if wasPlayingBeforeSeeking {
|
||||
handler.play()
|
||||
@@ -209,7 +209,7 @@ open class VersaPlayerControls: UIView {
|
||||
}
|
||||
|
||||
/// Start Seeking
|
||||
@IBAction public func seekingStart() {
|
||||
@IBAction open func seekingStart() {
|
||||
wasPlayingBeforeSeeking = handler.isPlaying
|
||||
handler.isSeeking = true
|
||||
handler.pause()
|
||||
@@ -219,7 +219,7 @@ open class VersaPlayerControls: UIView {
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - sender: UISlider that updated
|
||||
@IBAction public func playheadChanged(with sender: UISlider) {
|
||||
@IBAction open func playheadChanged(with sender: UISlider) {
|
||||
let value = Double(sender.value)
|
||||
let time = CMTime(seconds: value, preferredTimescale: CMTimeScale(NSEC_PER_SEC))
|
||||
handler.player.seek(to: time)
|
||||
@@ -227,18 +227,18 @@ open class VersaPlayerControls: UIView {
|
||||
}
|
||||
|
||||
/// Toggle PIP mode
|
||||
@IBAction public func togglePip() {
|
||||
@IBAction open func togglePip() {
|
||||
handler.setNativePip(enabled: !handler.isPipModeEnabled)
|
||||
}
|
||||
|
||||
/// Toggle fullscreen mode
|
||||
@IBAction public func toggleFullscreen() {
|
||||
@IBAction open func toggleFullscreen() {
|
||||
fullscreenButton?.set(active: !handler.isFullscreenModeEnabled)
|
||||
handler.setFullscreen(enabled: !handler.isFullscreenModeEnabled)
|
||||
}
|
||||
|
||||
/// Toggle playback
|
||||
@IBAction public func togglePlayback() {
|
||||
@IBAction open func togglePlayback() {
|
||||
if handler.isRewinding || handler.isForwarding {
|
||||
handler.player.rate = 1
|
||||
playPauseButton?.set(active: true)
|
||||
@@ -248,7 +248,7 @@ open class VersaPlayerControls: UIView {
|
||||
playPauseButton?.set(active: false)
|
||||
handler.pause()
|
||||
}else {
|
||||
if handler.playbackDelegate?.playbackShouldBegin(forPlayer: handler.player) ?? true {
|
||||
if handler.playbackDelegate?.playbackShouldBegin(player: handler.player) ?? true {
|
||||
playPauseButton?.set(active: true)
|
||||
handler.play()
|
||||
}
|
||||
@@ -256,7 +256,7 @@ open class VersaPlayerControls: UIView {
|
||||
}
|
||||
|
||||
/// Toggle rewind
|
||||
@IBAction public func rewindToggle() {
|
||||
@IBAction open func rewindToggle() {
|
||||
if handler.player.currentItem?.canPlayFastReverse ?? false {
|
||||
if handler.isRewinding {
|
||||
rewindButton?.set(active: false)
|
||||
@@ -279,7 +279,7 @@ open class VersaPlayerControls: UIView {
|
||||
}
|
||||
|
||||
/// Forward toggle
|
||||
@IBAction public func forwardToggle() {
|
||||
@IBAction open func forwardToggle() {
|
||||
if handler.player.currentItem?.canPlayFastForward ?? false {
|
||||
if handler.isForwarding {
|
||||
forwardButton?.set(active: false)
|
||||
|
||||
+22
-14
@@ -13,17 +13,17 @@ import AVFoundation
|
||||
open class VersaPlayerControlsCoordinator: UIView, VersaPlayerGestureRecieverViewDelegate {
|
||||
|
||||
/// VersaPlayer instance being used
|
||||
var player: VersaPlayer!
|
||||
var player: VersaPlayerView!
|
||||
|
||||
/// VersaPlayerControls instance being used
|
||||
var controls: VersaPlayerControls!
|
||||
public var controls: VersaPlayerControls!
|
||||
|
||||
/// VersaPlayerGestureRecieverView instance being used
|
||||
var gestureReciever: VersaPlayerGestureRecieverView!
|
||||
public var gestureReciever: VersaPlayerGestureRecieverView!
|
||||
|
||||
override open func didMoveToSuperview() {
|
||||
super.didMoveToSuperview()
|
||||
if let h = superview as? VersaPlayer {
|
||||
if let h = superview as? VersaPlayerView {
|
||||
player = h
|
||||
if controls != nil {
|
||||
addSubview(controls)
|
||||
@@ -38,7 +38,7 @@ open class VersaPlayerControlsCoordinator: UIView, VersaPlayerGestureRecieverVie
|
||||
}
|
||||
}
|
||||
|
||||
public func layout() {
|
||||
open func layout() {
|
||||
translatesAutoresizingMaskIntoConstraints = false
|
||||
if let parent = superview {
|
||||
topAnchor.constraint(equalTo: parent.topAnchor).isActive = true
|
||||
@@ -52,11 +52,19 @@ open class VersaPlayerControlsCoordinator: UIView, VersaPlayerGestureRecieverVie
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - scale: CGFloat value
|
||||
public func didPinch(with scale: CGFloat) {
|
||||
if player.renderingView.renderingLayer.playerLayer.videoGravity == AVLayerVideoGravity.resizeAspect {
|
||||
player.renderingView.renderingLayer.playerLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill
|
||||
open func didPinch(with scale: CGFloat) {
|
||||
|
||||
}
|
||||
|
||||
/// Notifies when tap was recognized
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - point: CGPoint at which tap was recognized
|
||||
open func didTap(at point: CGPoint) {
|
||||
if controls.behaviour.showingControls {
|
||||
controls.behaviour.hide()
|
||||
}else {
|
||||
player.renderingView.renderingLayer.playerLayer.videoGravity = AVLayerVideoGravity.resizeAspect
|
||||
controls.behaviour.show()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,11 +72,11 @@ open class VersaPlayerControlsCoordinator: UIView, VersaPlayerGestureRecieverVie
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - point: CGPoint at which tap was recognized
|
||||
public func didTap(at point: CGPoint) {
|
||||
if controls.behaviour.showingControls {
|
||||
controls.behaviour.hide()
|
||||
open func didDoubleTap(at point: CGPoint) {
|
||||
if player.renderingView.renderingLayer.playerLayer.videoGravity == AVLayerVideoGravity.resizeAspect {
|
||||
player.renderingView.renderingLayer.playerLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill
|
||||
}else {
|
||||
controls.behaviour.show()
|
||||
player.renderingView.renderingLayer.playerLayer.videoGravity = AVLayerVideoGravity.resizeAspect
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +85,7 @@ open class VersaPlayerControlsCoordinator: UIView, VersaPlayerGestureRecieverVie
|
||||
/// - Parameters:
|
||||
/// - translation: translation of pan in CGPoint representation
|
||||
/// - at: initial point recognized
|
||||
public func didPan(with translation: CGPoint, initially at: CGPoint) {
|
||||
open func didPan(with translation: CGPoint, initially at: CGPoint) {
|
||||
let percentageTranslation: Double = Double(translation.x / gestureReciever.bounds.width)
|
||||
player.player.seek(to:
|
||||
CMTime.init(
|
||||
|
||||
+57
-28
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// VersaPlayer.swift
|
||||
// VersaPlayer Demo
|
||||
// VersaPlayerView.swift
|
||||
// VersaPlayerView Demo
|
||||
//
|
||||
// Created by Jose Quintero on 10/11/18.
|
||||
// Copyright © 2018 Quasar. All rights reserved.
|
||||
@@ -11,20 +11,26 @@ import CoreMedia
|
||||
import AVFoundation
|
||||
import AVKit
|
||||
|
||||
open class VersaPlayer: UIView, AVPictureInPictureControllerDelegate {
|
||||
open class VersaPlayerView: UIView, AVPictureInPictureControllerDelegate {
|
||||
|
||||
/// VersaPlayer extension dictionary
|
||||
public var extensions: [String: VersaPlayerExtension] = [:]
|
||||
|
||||
/// AVPlayer used in VersaPlayer implementation
|
||||
public var player: VPlayer!
|
||||
public var player: VersaPlayer!
|
||||
|
||||
/// VersaPlayerControls instance being used to display controls
|
||||
public var controls: VersaPlayerControls? = nil
|
||||
|
||||
/// VPlayerRenderingView instance
|
||||
public var renderingView: VPlayerRenderingView!
|
||||
public var renderingView: VersaPlayerRenderingView!
|
||||
|
||||
/// VersaPlayerPlaybackDelegate instance
|
||||
public var playbackDelegate: VersaPlayerPlaybackDelegate? = nil
|
||||
|
||||
/// VersaPlayerDecryptionDelegate instance to be used only when a VPlayer item with isEncrypted = true is passed
|
||||
public var decryptionDelegate: VersaPlayerDecryptionDelegate? = nil
|
||||
|
||||
/// VersaPlayer initial container
|
||||
private var nonFullscreenContainer: UIView!
|
||||
|
||||
@@ -74,7 +80,7 @@ open class VersaPlayer: UIView, AVPictureInPictureControllerDelegate {
|
||||
/// - Parameters:
|
||||
/// - ext: The instance of the extension.
|
||||
/// - name: The name of the extension.
|
||||
public func addExtension(extension ext: VersaPlayerExtension, with name: String) {
|
||||
open func addExtension(extension ext: VersaPlayerExtension, with name: String) {
|
||||
ext.player = self
|
||||
ext.prepare()
|
||||
extensions[name] = ext
|
||||
@@ -84,17 +90,17 @@ open class VersaPlayer: UIView, AVPictureInPictureControllerDelegate {
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - name: The name of the extension.
|
||||
public func getExtension(with name: String) -> VersaPlayerExtension? {
|
||||
open func getExtension(with name: String) -> VersaPlayerExtension? {
|
||||
return extensions[name]
|
||||
}
|
||||
|
||||
/// Prepares the player to play
|
||||
public func prepare() {
|
||||
open func prepare() {
|
||||
ready = true
|
||||
player = VPlayer()
|
||||
player = VersaPlayer()
|
||||
player.handler = self
|
||||
player.preparePlayerPlaybackDelegate()
|
||||
renderingView = VPlayerRenderingView(with: self)
|
||||
renderingView = VersaPlayerRenderingView(with: self)
|
||||
layout(view: renderingView, into: self)
|
||||
}
|
||||
|
||||
@@ -103,7 +109,7 @@ open class VersaPlayer: UIView, AVPictureInPictureControllerDelegate {
|
||||
/// - Parameters:
|
||||
/// - view: The view to layout.
|
||||
/// - into: The container view.
|
||||
public func layout(view: UIView, into: UIView) {
|
||||
open func layout(view: UIView, into: UIView) {
|
||||
into.addSubview(view)
|
||||
view.translatesAutoresizingMaskIntoConstraints = false
|
||||
view.topAnchor.constraint(equalTo: into.topAnchor).isActive = true
|
||||
@@ -116,7 +122,7 @@ open class VersaPlayer: UIView, AVPictureInPictureControllerDelegate {
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - enabled: Whether or not to enable
|
||||
public func setNativePip(enabled: Bool) {
|
||||
open func setNativePip(enabled: Bool) {
|
||||
if enabled {
|
||||
pipController?.startPictureInPicture()
|
||||
}else {
|
||||
@@ -128,22 +134,19 @@ open class VersaPlayer: UIView, AVPictureInPictureControllerDelegate {
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - enabled: Whether or not to enable
|
||||
public func setFullscreen(enabled: Bool) {
|
||||
open func setFullscreen(enabled: Bool) {
|
||||
if enabled == isFullscreenModeEnabled {
|
||||
return
|
||||
}
|
||||
if enabled {
|
||||
if let window = UIApplication.shared.keyWindow {
|
||||
nonFullscreenContainer = superview
|
||||
removeFromSuperview()
|
||||
layout(view: self, into: window)
|
||||
let value = UIInterfaceOrientation.landscapeLeft.rawValue
|
||||
UIDevice.current.setValue(value, forKey: "orientation")
|
||||
UIViewController.attemptRotationToDeviceOrientation()
|
||||
}
|
||||
}else {
|
||||
removeFromSuperview()
|
||||
layout(view: self, into: nonFullscreenContainer)
|
||||
let value = UIInterfaceOrientation.portrait.rawValue
|
||||
UIDevice.current.setValue(value, forKey: "orientation")
|
||||
UIViewController.attemptRotationToDeviceOrientation()
|
||||
}
|
||||
|
||||
isFullscreenModeEnabled = enabled
|
||||
@@ -153,7 +156,7 @@ open class VersaPlayer: UIView, AVPictureInPictureControllerDelegate {
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - item: The VPlayerItem instance to add to player.
|
||||
public func set(item: VPlayerItem?) {
|
||||
open func set(item: VersaPlayerItem?) {
|
||||
if !ready {
|
||||
prepare()
|
||||
}
|
||||
@@ -164,22 +167,48 @@ open class VersaPlayer: UIView, AVPictureInPictureControllerDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
/// VersaPlayerControls instance to display controls in player, using VersaPlayerGestureRecieverView instance
|
||||
/// to handle gestures
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - controls: VersaPlayerControls instance used to display controls
|
||||
/// - gestureReciever: Optional gesture reciever view to be used to recieve gestures
|
||||
public func use(controls: VersaPlayerControls, with gestureReciever: VersaPlayerGestureRecieverView? = nil) {
|
||||
let coordinator = VersaPlayerControlsCoordinator()
|
||||
coordinator.player = self
|
||||
coordinator.controls = controls
|
||||
coordinator.gestureReciever = gestureReciever
|
||||
controls.controlsCoordinator = coordinator
|
||||
addSubview(coordinator)
|
||||
bringSubview(toFront: controls)
|
||||
|
||||
self.controls = controls
|
||||
}
|
||||
|
||||
/// Update controls to specified time
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - time: Time to be updated to
|
||||
public func updateControls(toTime time: CMTime) {
|
||||
controls?.timeDidChange(toTime: time)
|
||||
}
|
||||
|
||||
/// Play
|
||||
@IBAction public func play() {
|
||||
if playbackDelegate?.playbackShouldBegin(forPlayer: player) ?? true {
|
||||
@IBAction open func play() {
|
||||
if playbackDelegate?.playbackShouldBegin(player: player) ?? true {
|
||||
player.play()
|
||||
isPlaying = true
|
||||
}
|
||||
}
|
||||
|
||||
/// Pause
|
||||
@IBAction public func pause() {
|
||||
@IBAction open func pause() {
|
||||
player.pause()
|
||||
isPlaying = false
|
||||
}
|
||||
|
||||
/// Toggle Playback
|
||||
@IBAction public func togglePlayback() {
|
||||
@IBAction open func togglePlayback() {
|
||||
if isPlaying {
|
||||
pause()
|
||||
}else {
|
||||
@@ -187,20 +216,20 @@ open class VersaPlayer: UIView, AVPictureInPictureControllerDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
public func pictureInPictureControllerDidStopPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {
|
||||
open func pictureInPictureControllerDidStopPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {
|
||||
//hide fallback
|
||||
}
|
||||
|
||||
public func pictureInPictureControllerDidStartPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {
|
||||
open func pictureInPictureControllerDidStartPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {
|
||||
//show fallback
|
||||
}
|
||||
|
||||
public func pictureInPictureControllerWillStopPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {
|
||||
open func pictureInPictureControllerWillStopPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {
|
||||
isPipModeEnabled = false
|
||||
controls?.controlsCoordinator.isHidden = false
|
||||
}
|
||||
|
||||
public func pictureInPictureControllerWillStartPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {
|
||||
open func pictureInPictureControllerWillStartPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {
|
||||
controls?.controlsCoordinator.isHidden = true
|
||||
isPipModeEnabled = true
|
||||
}
|
||||
@@ -12,13 +12,11 @@
|
||||
607FACDB1AFB9204008FA782 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 607FACD91AFB9204008FA782 /* Main.storyboard */; };
|
||||
607FACDD1AFB9204008FA782 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 607FACDC1AFB9204008FA782 /* Images.xcassets */; };
|
||||
607FACE01AFB9204008FA782 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 607FACDE1AFB9204008FA782 /* LaunchScreen.xib */; };
|
||||
CDBBEBBB3284BA03C1AF1F36 /* Pods_VersaPlayerOverlayContentExtension_Example.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 422C3B66293A75759E15CB2C /* Pods_VersaPlayerOverlayContentExtension_Example.framework */; };
|
||||
AF579BC80FE04C7BA0483B09 /* Pods_VersaPlayerOverlayContentExtension_Example.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C8AD8344BF34E94201CFCAB8 /* Pods_VersaPlayerOverlayContentExtension_Example.framework */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
19BE7522841DB1F31244CEDB /* Pods-VersaPlayerOverlayContentExtension_Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-VersaPlayerOverlayContentExtension_Tests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-VersaPlayerOverlayContentExtension_Tests/Pods-VersaPlayerOverlayContentExtension_Tests.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
3B3EA70D344F87BE2B6F7342 /* VersaPlayerOverlayContentExtension.podspec */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = VersaPlayerOverlayContentExtension.podspec; path = ../VersaPlayerOverlayContentExtension.podspec; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.ruby; };
|
||||
422C3B66293A75759E15CB2C /* Pods_VersaPlayerOverlayContentExtension_Example.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_VersaPlayerOverlayContentExtension_Example.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
607FACD01AFB9204008FA782 /* VersaPlayerOverlayContentExtension_Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = VersaPlayerOverlayContentExtension_Example.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
607FACD41AFB9204008FA782 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
607FACD51AFB9204008FA782 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
@@ -26,12 +24,11 @@
|
||||
607FACDA1AFB9204008FA782 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||
607FACDC1AFB9204008FA782 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
|
||||
607FACDF1AFB9204008FA782 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = "<group>"; };
|
||||
8AB68C5D5DC86028B26EE610 /* Pods-VersaPlayerOverlayContentExtension_Tests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-VersaPlayerOverlayContentExtension_Tests.release.xcconfig"; path = "Pods/Target Support Files/Pods-VersaPlayerOverlayContentExtension_Tests/Pods-VersaPlayerOverlayContentExtension_Tests.release.xcconfig"; sourceTree = "<group>"; };
|
||||
8DF3ADA7A282FBE752C02BA3 /* Pods-VersaPlayerOverlayContentExtension_Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-VersaPlayerOverlayContentExtension_Example.release.xcconfig"; path = "Pods/Target Support Files/Pods-VersaPlayerOverlayContentExtension_Example/Pods-VersaPlayerOverlayContentExtension_Example.release.xcconfig"; sourceTree = "<group>"; };
|
||||
A47852AA004508EC7061BF9F /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = "<group>"; };
|
||||
CBC7206BE453D3298C595B8E /* Pods_VersaPlayerOverlayContentExtension_Tests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_VersaPlayerOverlayContentExtension_Tests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
D54DE5A68FCD4E2CC17A5AF5 /* Pods-VersaPlayerOverlayContentExtension_Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-VersaPlayerOverlayContentExtension_Example.debug.xcconfig"; path = "Pods/Target Support Files/Pods-VersaPlayerOverlayContentExtension_Example/Pods-VersaPlayerOverlayContentExtension_Example.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
A78291A316916BFCD146B57E /* Pods-VersaPlayerOverlayContentExtension_Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-VersaPlayerOverlayContentExtension_Example.debug.xcconfig"; path = "Pods/Target Support Files/Pods-VersaPlayerOverlayContentExtension_Example/Pods-VersaPlayerOverlayContentExtension_Example.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
C8AD8344BF34E94201CFCAB8 /* Pods_VersaPlayerOverlayContentExtension_Example.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_VersaPlayerOverlayContentExtension_Example.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
E81456EB946137D4E22D9878 /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = LICENSE; path = ../LICENSE; sourceTree = "<group>"; };
|
||||
FC67324BDD318674F712789A /* Pods-VersaPlayerOverlayContentExtension_Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-VersaPlayerOverlayContentExtension_Example.release.xcconfig"; path = "Pods/Target Support Files/Pods-VersaPlayerOverlayContentExtension_Example/Pods-VersaPlayerOverlayContentExtension_Example.release.xcconfig"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -39,41 +36,21 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
CDBBEBBB3284BA03C1AF1F36 /* Pods_VersaPlayerOverlayContentExtension_Example.framework in Frameworks */,
|
||||
AF579BC80FE04C7BA0483B09 /* Pods_VersaPlayerOverlayContentExtension_Example.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
18BB4E7223638CB36E042CA5 /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D54DE5A68FCD4E2CC17A5AF5 /* Pods-VersaPlayerOverlayContentExtension_Example.debug.xcconfig */,
|
||||
FC67324BDD318674F712789A /* Pods-VersaPlayerOverlayContentExtension_Example.release.xcconfig */,
|
||||
19BE7522841DB1F31244CEDB /* Pods-VersaPlayerOverlayContentExtension_Tests.debug.xcconfig */,
|
||||
8AB68C5D5DC86028B26EE610 /* Pods-VersaPlayerOverlayContentExtension_Tests.release.xcconfig */,
|
||||
);
|
||||
name = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
418B1EAF417DFF9C011FD6F9 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
422C3B66293A75759E15CB2C /* Pods_VersaPlayerOverlayContentExtension_Example.framework */,
|
||||
CBC7206BE453D3298C595B8E /* Pods_VersaPlayerOverlayContentExtension_Tests.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
607FACC71AFB9204008FA782 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
607FACF51AFB993E008FA782 /* Podspec Metadata */,
|
||||
607FACD21AFB9204008FA782 /* Example for VersaPlayerOverlayContentExtension */,
|
||||
607FACD11AFB9204008FA782 /* Products */,
|
||||
18BB4E7223638CB36E042CA5 /* Pods */,
|
||||
418B1EAF417DFF9C011FD6F9 /* Frameworks */,
|
||||
AB9BE6C9C6CDAB1AC7982BB5 /* Pods */,
|
||||
873570A6E894640F9971E155 /* Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
@@ -117,6 +94,23 @@
|
||||
name = "Podspec Metadata";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
873570A6E894640F9971E155 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C8AD8344BF34E94201CFCAB8 /* Pods_VersaPlayerOverlayContentExtension_Example.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
AB9BE6C9C6CDAB1AC7982BB5 /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A78291A316916BFCD146B57E /* Pods-VersaPlayerOverlayContentExtension_Example.debug.xcconfig */,
|
||||
8DF3ADA7A282FBE752C02BA3 /* Pods-VersaPlayerOverlayContentExtension_Example.release.xcconfig */,
|
||||
);
|
||||
name = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
@@ -124,11 +118,11 @@
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 607FACEF1AFB9204008FA782 /* Build configuration list for PBXNativeTarget "VersaPlayerOverlayContentExtension_Example" */;
|
||||
buildPhases = (
|
||||
B4833FEAB1898CDA522A7AF5 /* [CP] Check Pods Manifest.lock */,
|
||||
8EF19E4A669871A5C1CF906F /* [CP] Check Pods Manifest.lock */,
|
||||
607FACCC1AFB9204008FA782 /* Sources */,
|
||||
607FACCD1AFB9204008FA782 /* Frameworks */,
|
||||
607FACCE1AFB9204008FA782 /* Resources */,
|
||||
027689DE2F87B89C090B497A /* [CP] Embed Pods Frameworks */,
|
||||
0D2C85268D21D00E38E1D8A7 /* [CP] Embed Pods Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@@ -187,18 +181,24 @@
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
027689DE2F87B89C090B497A /* [CP] Embed Pods Frameworks */ = {
|
||||
0D2C85268D21D00E38E1D8A7 /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${SRCROOT}/Pods/Target Support Files/Pods-VersaPlayerOverlayContentExtension_Example/Pods-VersaPlayerOverlayContentExtension_Example-frameworks.sh",
|
||||
"${BUILT_PRODUCTS_DIR}/FBSnapshotTestCase/FBSnapshotTestCase.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/VersaPlayer/VersaPlayer.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/VersaPlayerOverlayContentExtension/VersaPlayerOverlayContentExtension.framework",
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FBSnapshotTestCase.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/VersaPlayer.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/VersaPlayerOverlayContentExtension.framework",
|
||||
);
|
||||
@@ -207,16 +207,20 @@
|
||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-VersaPlayerOverlayContentExtension_Example/Pods-VersaPlayerOverlayContentExtension_Example-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
B4833FEAB1898CDA522A7AF5 /* [CP] Check Pods Manifest.lock */ = {
|
||||
8EF19E4A669871A5C1CF906F /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||
"${PODS_ROOT}/Manifest.lock",
|
||||
);
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
"$(DERIVED_FILE_DIR)/Pods-VersaPlayerOverlayContentExtension_Example-checkManifestLockResult.txt",
|
||||
);
|
||||
@@ -360,7 +364,7 @@
|
||||
};
|
||||
607FACF01AFB9204008FA782 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = D54DE5A68FCD4E2CC17A5AF5 /* Pods-VersaPlayerOverlayContentExtension_Example.debug.xcconfig */;
|
||||
baseConfigurationReference = A78291A316916BFCD146B57E /* Pods-VersaPlayerOverlayContentExtension_Example.debug.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
INFOPLIST_FILE = VersaPlayerOverlayContentExtension/Info.plist;
|
||||
@@ -375,7 +379,7 @@
|
||||
};
|
||||
607FACF11AFB9204008FA782 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = FC67324BDD318674F712789A /* Pods-VersaPlayerOverlayContentExtension_Example.release.xcconfig */;
|
||||
baseConfigurationReference = 8DF3ADA7A282FBE752C02BA3 /* Pods-VersaPlayerOverlayContentExtension_Example.release.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
INFOPLIST_FILE = VersaPlayerOverlayContentExtension/Info.plist;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14113" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="vXZ-lx-hvc">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14313.18" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="vXZ-lx-hvc">
|
||||
<device id="retina4_7" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14283.14"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
@@ -21,7 +21,7 @@
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="bMZ-HI-RVE" customClass="VersaPlayer" customModule="VersaPlayer">
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="bMZ-HI-RVE" customClass="VersaPlayerView" customModule="VersaPlayer">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<color key="backgroundColor" cocoaTouchSystemColor="viewFlipsideBackgroundColor"/>
|
||||
</view>
|
||||
|
||||
@@ -12,14 +12,14 @@ import VersaPlayerOverlayContentExtension
|
||||
|
||||
class ViewController: UIViewController {
|
||||
|
||||
@IBOutlet weak var player: VersaPlayer!
|
||||
@IBOutlet weak var player: VersaPlayerView!
|
||||
@IBOutlet weak var pauseOverlay: VersaPlayerOverlayContent!
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
player.useOverlayContent(manager: VersaPlayerOverlayContentManager.init(with: player, and: self))
|
||||
if let url = URL.init(string: "http://rmcdn.2mdn.net/Demo/html5/output.mp4") {
|
||||
let item = VPlayerItem(url: url)
|
||||
let item = VersaPlayerItem(url: url)
|
||||
player.set(item: item)
|
||||
}
|
||||
}
|
||||
@@ -36,7 +36,7 @@ extension ViewController: VersaPlayerOverlayContentManagerDelegate {
|
||||
content.bottomAnchor.constraint(equalTo: container.bottomAnchor).isActive = true
|
||||
}
|
||||
|
||||
func shouldShowOverlayContentForPlayer(player: VersaPlayer, status: VersaPlayerOverlayContentManagerPlayerStatus) -> Bool {
|
||||
func shouldShowOverlayContentForPlayer(player: VersaPlayerView, status: VersaPlayerOverlayContentManagerPlayerStatus) -> Bool {
|
||||
switch status {
|
||||
case .assetLoaded:
|
||||
return true
|
||||
@@ -51,16 +51,16 @@ extension ViewController: VersaPlayerOverlayContentManagerDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
func viewForOverlayContentIn(player: VersaPlayer, status: VersaPlayerOverlayContentManagerPlayerStatus) -> VersaPlayerOverlayContent {
|
||||
func viewForOverlayContentIn(player: VersaPlayerView, status: VersaPlayerOverlayContentManagerPlayerStatus) -> VersaPlayerOverlayContent {
|
||||
pauseOverlay.shouldPausePlayerOnShow = true
|
||||
return pauseOverlay
|
||||
}
|
||||
|
||||
func willDisplayOverlayContentIn(player: VersaPlayer, content: VersaPlayerOverlayContent, status: VersaPlayerOverlayContentManagerPlayerStatus) {
|
||||
func willDisplayOverlayContentIn(player: VersaPlayerView, content: VersaPlayerOverlayContent, status: VersaPlayerOverlayContentManagerPlayerStatus) {
|
||||
|
||||
}
|
||||
|
||||
func willRemoveOverlayContentIn(player: VersaPlayer, content: VersaPlayerOverlayContent, status: VersaPlayerOverlayContentManagerPlayerStatus) {
|
||||
func willRemoveOverlayContentIn(player: VersaPlayerView, content: VersaPlayerOverlayContent, status: VersaPlayerOverlayContentManagerPlayerStatus) {
|
||||
player.play()
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
Pod::Spec.new do |s|
|
||||
s.name = 'VersaPlayerOverlayContentExtension'
|
||||
s.version = '0.1.3'
|
||||
s.version = '0.2.0'
|
||||
s.summary = 'VersaPlayer extension to enable overlay content.'
|
||||
s.description = 'VersaPlayer extension to enable overlay content functionality.'
|
||||
s.homepage = 'https://github.com/josejuanqm/VersaPlayerOverlayContentExtension'
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ import Foundation
|
||||
import UIKit
|
||||
import VersaPlayer
|
||||
|
||||
public extension VersaPlayer {
|
||||
public extension VersaPlayerView {
|
||||
|
||||
public var overlayContentManager: VersaPlayerOverlayContentManager? {
|
||||
let overlayContentManager = getExtension(with: "overlayContentManager") as? VersaPlayerOverlayContentManager
|
||||
|
||||
+4
-4
@@ -12,8 +12,8 @@ import VersaPlayer
|
||||
|
||||
public protocol VersaPlayerOverlayContentManagerDelegate {
|
||||
func positionIn(container: UIView, forContent content: VersaPlayerOverlayContent)
|
||||
func shouldShowOverlayContentForPlayer(player: VersaPlayer, status: VersaPlayerOverlayContentManagerPlayerStatus) -> Bool
|
||||
func viewForOverlayContentIn(player: VersaPlayer, status: VersaPlayerOverlayContentManagerPlayerStatus) -> VersaPlayerOverlayContent
|
||||
func willDisplayOverlayContentIn(player: VersaPlayer, content: VersaPlayerOverlayContent, status: VersaPlayerOverlayContentManagerPlayerStatus)
|
||||
func willRemoveOverlayContentIn(player: VersaPlayer, content: VersaPlayerOverlayContent, status: VersaPlayerOverlayContentManagerPlayerStatus)
|
||||
func shouldShowOverlayContentForPlayer(player: VersaPlayerView, status: VersaPlayerOverlayContentManagerPlayerStatus) -> Bool
|
||||
func viewForOverlayContentIn(player: VersaPlayerView, status: VersaPlayerOverlayContentManagerPlayerStatus) -> VersaPlayerOverlayContent
|
||||
func willDisplayOverlayContentIn(player: VersaPlayerView, content: VersaPlayerOverlayContent, status: VersaPlayerOverlayContentManagerPlayerStatus)
|
||||
func willRemoveOverlayContentIn(player: VersaPlayerView, content: VersaPlayerOverlayContent, status: VersaPlayerOverlayContentManagerPlayerStatus)
|
||||
}
|
||||
|
||||
+4
-2
@@ -11,7 +11,7 @@ import VersaPlayer
|
||||
|
||||
open class VersaPlayerOverlayContent: UIView {
|
||||
|
||||
public var player: VersaPlayer!
|
||||
public var player: VersaPlayerView!
|
||||
public var shown: Bool = false
|
||||
public var shouldPausePlayerOnShow: Bool = true
|
||||
|
||||
@@ -24,19 +24,21 @@ open class VersaPlayerOverlayContent: UIView {
|
||||
|
||||
public func show(with status: VersaPlayerOverlayContentManagerPlayerStatus) {
|
||||
if shown { return } else { shown = true }
|
||||
if shouldPausePlayerOnShow { player.pause() }
|
||||
if shouldPausePlayerOnShow && player.isPlaying { player.pause() }
|
||||
player.overlayContentManager?.delegate?.willDisplayOverlayContentIn(player: player, content: self, status: status)
|
||||
player.controls?.behaviour.hide()
|
||||
player.showOverlay(content: self)
|
||||
}
|
||||
|
||||
public func hide(with status: VersaPlayerOverlayContentManagerPlayerStatus) {
|
||||
player.overlayContentManager?.isShowing = false
|
||||
player.overlayContentManager?.delegate?.willRemoveOverlayContentIn(player: player, content: self, status: status)
|
||||
player.controls?.behaviour.show()
|
||||
player.hideOverlay(content: self)
|
||||
}
|
||||
|
||||
@IBAction public func hide() {
|
||||
player.overlayContentManager?.isShowing = false
|
||||
player.overlayContentManager?.delegate?.willRemoveOverlayContentIn(player: player, content: self, status: player.overlayContentManager?.status ?? .none)
|
||||
player.controls?.behaviour.show()
|
||||
player.hideOverlay(content: self)
|
||||
|
||||
+12
-7
@@ -16,42 +16,47 @@ open class VersaPlayerOverlayContentManager: VersaPlayerExtension {
|
||||
|
||||
public var delegate: VersaPlayerOverlayContentManagerDelegate? = nil
|
||||
public var status: VersaPlayerOverlayContentManagerPlayerStatus? = nil
|
||||
internal var isShowing: Bool = false
|
||||
|
||||
public init(with player: VersaPlayer, and delegate: VersaPlayerOverlayContentManagerDelegate) {
|
||||
public init(with player: VersaPlayerView, and delegate: VersaPlayerOverlayContentManagerDelegate) {
|
||||
super.init(with: player)
|
||||
self.delegate = delegate
|
||||
}
|
||||
|
||||
open override func prepare() {
|
||||
NotificationCenter.default.addObserver(forName: VPlayer.VPlayerNotificationName.assetLoaded.notification, object: nil, queue: OperationQueue.main) { (notification) in
|
||||
NotificationCenter.default.addObserver(forName: VersaPlayer.VPlayerNotificationName.assetLoaded.notification, object: nil, queue: OperationQueue.main) { (notification) in
|
||||
self.status = VersaPlayerOverlayContentManagerPlayerStatus.assetLoaded
|
||||
self.showIfNeededWith(status: self.status!)
|
||||
}
|
||||
NotificationCenter.default.addObserver(forName: VPlayer.VPlayerNotificationName.timeChanged.notification, object: nil, queue: OperationQueue.main) { (notification) in
|
||||
if let time = notification.userInfo?[VPlayer.VPlayerNotificationInfoKey.time.rawValue] as? CMTime {
|
||||
NotificationCenter.default.addObserver(forName: VersaPlayer.VPlayerNotificationName.timeChanged.notification, object: nil, queue: OperationQueue.main) { (notification) in
|
||||
if let time = notification.userInfo?[VersaPlayer.VPlayerNotificationInfoKey.time.rawValue] as? CMTime {
|
||||
self.status = VersaPlayerOverlayContentManagerPlayerStatus.timeChanged(round(time.seconds))
|
||||
self.showIfNeededWith(status: self.status!)
|
||||
}
|
||||
}
|
||||
NotificationCenter.default.addObserver(forName: VPlayer.VPlayerNotificationName.didEnd.notification, object: nil, queue: OperationQueue.main) { (notification) in
|
||||
NotificationCenter.default.addObserver(forName: VersaPlayer.VPlayerNotificationName.didEnd.notification, object: nil, queue: OperationQueue.main) { (notification) in
|
||||
self.status = VersaPlayerOverlayContentManagerPlayerStatus.didEnd
|
||||
self.showIfNeededWith(status: self.status!)
|
||||
}
|
||||
NotificationCenter.default.addObserver(forName: VPlayer.VPlayerNotificationName.play.notification, object: nil, queue: OperationQueue.main) { (notification) in
|
||||
NotificationCenter.default.addObserver(forName: VersaPlayer.VPlayerNotificationName.play.notification, object: nil, queue: OperationQueue.main) { (notification) in
|
||||
self.status = VersaPlayerOverlayContentManagerPlayerStatus.didPlay
|
||||
self.showIfNeededWith(status: self.status!)
|
||||
}
|
||||
NotificationCenter.default.addObserver(forName: VPlayer.VPlayerNotificationName.pause.notification, object: nil, queue: OperationQueue.main) { (notification) in
|
||||
NotificationCenter.default.addObserver(forName: VersaPlayer.VPlayerNotificationName.pause.notification, object: nil, queue: OperationQueue.main) { (notification) in
|
||||
self.status = VersaPlayerOverlayContentManagerPlayerStatus.didPause
|
||||
self.showIfNeededWith(status: self.status!)
|
||||
}
|
||||
}
|
||||
|
||||
public func showIfNeededWith(status: VersaPlayerOverlayContentManagerPlayerStatus) {
|
||||
if isShowing {
|
||||
return
|
||||
}
|
||||
if (delegate?.shouldShowOverlayContentForPlayer(player: player, status: status) ?? false) {
|
||||
if let view = delegate?.viewForOverlayContentIn(player: player, status: status) {
|
||||
view.player = player
|
||||
delegate?.willDisplayOverlayContentIn(player: player, content: view, status: status)
|
||||
isShowing = true
|
||||
view.show(with: status)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user