diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7dd4b89..a4e5040 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -5,29 +5,29 @@ on: [push] jobs: build-swift: name: Build with swift - runs-on: macos-12 + runs-on: macos-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: xcode version uses: maxim-lobanov/setup-xcode@v1 with: - xcode-version: '13.4.1' + xcode-version: latest-stable - name: Build Package with swift run: swift build build-xcodebuild: name: Build with xcodebuild - runs-on: macos-12 + runs-on: macos-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: xcode version uses: maxim-lobanov/setup-xcode@v1 with: - xcode-version: '13.4.1' + xcode-version: latest-stable - name: Set Default Scheme run: | scheme_list=$(xcodebuild -list -json | tr -d "\n") @@ -50,14 +50,14 @@ jobs: cocoapods: name: Verify cocopods podspec needs: [ build-xcodebuild ] - runs-on: macos-12 + runs-on: macos-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: xcode version uses: maxim-lobanov/setup-xcode@v1 with: - xcode-version: '13.4.1' + xcode-version: latest-stable - name: Verify cocoapods run: pod lib lint --allow-warnings diff --git a/.github/workflows/create-release-from-changelog.yml b/.github/workflows/create-release-from-changelog.yml index 7de02c0..a1ac0db 100644 --- a/.github/workflows/create-release-from-changelog.yml +++ b/.github/workflows/create-release-from-changelog.yml @@ -9,7 +9,7 @@ jobs: update-documentation: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Create draft release if needed uses: apivideo/api.video-release-from-changelog-action@main with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0f158ca..8305544 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -6,7 +6,7 @@ jobs: deploy: runs-on: macos-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Install Cocoapods run: gem install cocoapods diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index faf49fa..953f78d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -4,7 +4,7 @@ jobs: test: runs-on: macos-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set API key run: | sed -i -e "s/INTEGRATION_TESTS_API_KEY/${INTEGRATION_TESTS_API_KEY}/" ./Tests/ApiVideoClient/Integration/Parameters.swift diff --git a/Example/Example.xcodeproj/Example.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Example/Example.xcodeproj/Example.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 0000000..925ac27 --- /dev/null +++ b/Example/Example.xcodeproj/Example.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,25 @@ +{ + "object": { + "pins": [ + { + "package": "Alamofire", + "repositoryURL": "https://github.com/Alamofire/Alamofire", + "state": { + "branch": null, + "revision": "78424be314842833c04bc3bef5b72e85fff99204", + "version": "5.6.4" + } + }, + { + "package": "AnyCodable", + "repositoryURL": "https://github.com/Flight-School/AnyCodable", + "state": { + "branch": null, + "revision": "862808b2070cd908cb04f9aafe7de83d35f81b05", + "version": "0.6.7" + } + } + ] + }, + "version": 1 +} diff --git a/Example/Example.xcodeproj/project.pbxproj b/Example/Example.xcodeproj/project.pbxproj index 0ae6198..e371607 100644 --- a/Example/Example.xcodeproj/project.pbxproj +++ b/Example/Example.xcodeproj/project.pbxproj @@ -7,33 +7,46 @@ objects = { /* Begin PBXBuildFile section */ + 210D99FE2B0230FF00D568B1 /* InAppSettingsKit in Frameworks */ = {isa = PBXBuildFile; productRef = 210D99FD2B0230FF00D568B1 /* InAppSettingsKit */; }; + 210D9A002B02314000D568B1 /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 210D99FF2B02314000D568B1 /* Settings.bundle */; }; + 210D9A022B02437200D568B1 /* SettingsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 210D9A012B02437200D568B1 /* SettingsManager.swift */; }; + 211834CE29CDBAB2002F2CCD /* AsyncApiUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 211834CD29CDBAB2002F2CCD /* AsyncApiUtils.swift */; }; + 211834DB29CDEFF8002F2CCD /* Contents.json in Resources */ = {isa = PBXBuildFile; fileRef = 211834D829CDEFF8002F2CCD /* Contents.json */; }; + 211834E129CDF08F002F2CCD /* ClientAppError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 211834DE29CDF08F002F2CCD /* ClientAppError.swift */; }; + 211834E229CDF08F002F2CCD /* CancellableApiTask.swift in Sources */ = {isa = PBXBuildFile; fileRef = 211834DF29CDF08F002F2CCD /* CancellableApiTask.swift */; }; + 211834E829CDF0A8002F2CCD /* AlertUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 211834E629CDF0A8002F2CCD /* AlertUtils.swift */; }; 2136DD4A274B9E74007B9FC9 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2136DD49274B9E74007B9FC9 /* AppDelegate.swift */; }; 2136DD4C274B9E74007B9FC9 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2136DD4B274B9E74007B9FC9 /* SceneDelegate.swift */; }; - 2136DD4E274B9E74007B9FC9 /* VideosViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2136DD4D274B9E74007B9FC9 /* VideosViewController.swift */; }; 2136DD51274B9E74007B9FC9 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2136DD4F274B9E74007B9FC9 /* Main.storyboard */; }; 2136DD53274B9E77007B9FC9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2136DD52274B9E77007B9FC9 /* Assets.xcassets */; }; 2136DD56274B9E77007B9FC9 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2136DD54274B9E77007B9FC9 /* LaunchScreen.storyboard */; }; + 21F366322B02695B00416B65 /* UIColorExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21F366312B02695B00416B65 /* UIColorExtensions.swift */; }; + 21F366342B027A6B00416B65 /* TaskManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21F366332B027A6B00416B65 /* TaskManager.swift */; }; C76439BC27A2F69F007FB307 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C76439BB27A2F69F007FB307 /* XCTest.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; C7BC280227A16604007406AB /* ApiVideoClient in Frameworks */ = {isa = PBXBuildFile; productRef = C7BC280127A16604007406AB /* ApiVideoClient */; }; - C7BC280427A17CD2007406AB /* UploaderViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7BC280327A17CD2007406AB /* UploaderViewController.swift */; }; - C7BC280727A17FEB007406AB /* VideoTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7BC280627A17FEB007406AB /* VideoTableViewCell.swift */; }; - C7BC280A27A18CC3007406AB /* ClientManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7BC280927A18CC3007406AB /* ClientManager.swift */; }; + C7BC280427A17CD2007406AB /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7BC280327A17CD2007406AB /* MainViewController.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 210D99FF2B02314000D568B1 /* Settings.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = Settings.bundle; sourceTree = ""; }; + 210D9A012B02437200D568B1 /* SettingsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsManager.swift; sourceTree = ""; }; + 211834CD29CDBAB2002F2CCD /* AsyncApiUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsyncApiUtils.swift; sourceTree = ""; }; + 211834D829CDEFF8002F2CCD /* Contents.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = Contents.json; path = Assets.xcassets/Contents.json; sourceTree = ""; }; + 211834DE29CDF08F002F2CCD /* ClientAppError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClientAppError.swift; sourceTree = ""; }; + 211834DF29CDF08F002F2CCD /* CancellableApiTask.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CancellableApiTask.swift; sourceTree = ""; }; + 211834E629CDF0A8002F2CCD /* AlertUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlertUtils.swift; sourceTree = ""; }; 2136DD46274B9E74007B9FC9 /* Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Example.app; sourceTree = BUILT_PRODUCTS_DIR; }; 2136DD49274B9E74007B9FC9 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 2136DD4B274B9E74007B9FC9 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; - 2136DD4D274B9E74007B9FC9 /* VideosViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideosViewController.swift; sourceTree = ""; }; 2136DD50274B9E74007B9FC9 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 2136DD52274B9E77007B9FC9 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 2136DD55274B9E77007B9FC9 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 2136DD57274B9E77007B9FC9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 2136DD5F274B9EED007B9FC9 /* swift5 */ = {isa = PBXFileReference; lastKnownFileType = folder; name = swift5; path = ..; sourceTree = ""; }; + 21F366312B02695B00416B65 /* UIColorExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIColorExtensions.swift; sourceTree = ""; }; + 21F366332B027A6B00416B65 /* TaskManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TaskManager.swift; sourceTree = ""; }; C76439BB27A2F69F007FB307 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Platforms/iPhoneOS.platform/Developer/Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; - C7BC280327A17CD2007406AB /* UploaderViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UploaderViewController.swift; sourceTree = ""; }; - C7BC280627A17FEB007406AB /* VideoTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoTableViewCell.swift; sourceTree = ""; }; - C7BC280927A18CC3007406AB /* ClientManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientManager.swift; sourceTree = ""; }; + C7BC280327A17CD2007406AB /* MainViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainViewController.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -42,6 +55,7 @@ buildActionMask = 2147483647; files = ( C76439BC27A2F69F007FB307 /* XCTest.framework in Frameworks */, + 210D99FE2B0230FF00D568B1 /* InAppSettingsKit in Frameworks */, C7BC280227A16604007406AB /* ApiVideoClient in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -49,6 +63,27 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 211834DD29CDF08F002F2CCD /* Models */ = { + isa = PBXGroup; + children = ( + 21F366332B027A6B00416B65 /* TaskManager.swift */, + 211834DE29CDF08F002F2CCD /* ClientAppError.swift */, + 211834DF29CDF08F002F2CCD /* CancellableApiTask.swift */, + ); + path = Models; + sourceTree = ""; + }; + 211834E429CDF0A8002F2CCD /* Utils */ = { + isa = PBXGroup; + children = ( + 211834CD29CDBAB2002F2CCD /* AsyncApiUtils.swift */, + 210D9A012B02437200D568B1 /* SettingsManager.swift */, + 211834E629CDF0A8002F2CCD /* AlertUtils.swift */, + 21F366312B02695B00416B65 /* UIColorExtensions.swift */, + ); + path = Utils; + sourceTree = ""; + }; 2136DD3D274B9E74007B9FC9 = { isa = PBXGroup; children = ( @@ -70,15 +105,17 @@ 2136DD48274B9E74007B9FC9 /* Example */ = { isa = PBXGroup; children = ( - C7BC280827A18111007406AB /* Controller */, - C7BC280527A17FD4007406AB /* Cell */, + C7BC280327A17CD2007406AB /* MainViewController.swift */, + 210D99FF2B02314000D568B1 /* Settings.bundle */, + 211834E429CDF0A8002F2CCD /* Utils */, + 211834DD29CDF08F002F2CCD /* Models */, + 211834D829CDEFF8002F2CCD /* Contents.json */, 2136DD49274B9E74007B9FC9 /* AppDelegate.swift */, 2136DD4B274B9E74007B9FC9 /* SceneDelegate.swift */, 2136DD4F274B9E74007B9FC9 /* Main.storyboard */, 2136DD52274B9E77007B9FC9 /* Assets.xcassets */, 2136DD54274B9E77007B9FC9 /* LaunchScreen.storyboard */, 2136DD57274B9E77007B9FC9 /* Info.plist */, - C7BC280927A18CC3007406AB /* ClientManager.swift */, ); path = Example; sourceTree = ""; @@ -99,23 +136,6 @@ name = Frameworks; sourceTree = ""; }; - C7BC280527A17FD4007406AB /* Cell */ = { - isa = PBXGroup; - children = ( - C7BC280627A17FEB007406AB /* VideoTableViewCell.swift */, - ); - path = Cell; - sourceTree = ""; - }; - C7BC280827A18111007406AB /* Controller */ = { - isa = PBXGroup; - children = ( - 2136DD4D274B9E74007B9FC9 /* VideosViewController.swift */, - C7BC280327A17CD2007406AB /* UploaderViewController.swift */, - ); - path = Controller; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -134,6 +154,7 @@ name = Example; packageProductDependencies = ( C7BC280127A16604007406AB /* ApiVideoClient */, + 210D99FD2B0230FF00D568B1 /* InAppSettingsKit */, ); productName = Example; productReference = 2136DD46274B9E74007B9FC9 /* Example.app */; @@ -163,6 +184,9 @@ Base, ); mainGroup = 2136DD3D274B9E74007B9FC9; + packageReferences = ( + 210D99FC2B0230FF00D568B1 /* XCRemoteSwiftPackageReference "InAppSettingsKit" */, + ); productRefGroup = 2136DD47274B9E74007B9FC9 /* Products */; projectDirPath = ""; projectRoot = ""; @@ -179,7 +203,9 @@ files = ( 2136DD56274B9E77007B9FC9 /* LaunchScreen.storyboard in Resources */, 2136DD53274B9E77007B9FC9 /* Assets.xcassets in Resources */, + 210D9A002B02314000D568B1 /* Settings.bundle in Resources */, 2136DD51274B9E74007B9FC9 /* Main.storyboard in Resources */, + 211834DB29CDEFF8002F2CCD /* Contents.json in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -190,12 +216,16 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 2136DD4E274B9E74007B9FC9 /* VideosViewController.swift in Sources */, + 211834E129CDF08F002F2CCD /* ClientAppError.swift in Sources */, + 211834CE29CDBAB2002F2CCD /* AsyncApiUtils.swift in Sources */, 2136DD4A274B9E74007B9FC9 /* AppDelegate.swift in Sources */, - C7BC280A27A18CC3007406AB /* ClientManager.swift in Sources */, - C7BC280427A17CD2007406AB /* UploaderViewController.swift in Sources */, + C7BC280427A17CD2007406AB /* MainViewController.swift in Sources */, + 21F366342B027A6B00416B65 /* TaskManager.swift in Sources */, + 211834E829CDF0A8002F2CCD /* AlertUtils.swift in Sources */, + 210D9A022B02437200D568B1 /* SettingsManager.swift in Sources */, 2136DD4C274B9E74007B9FC9 /* SceneDelegate.swift in Sources */, - C7BC280727A17FEB007406AB /* VideoTableViewCell.swift in Sources */, + 211834E229CDF08F002F2CCD /* CancellableApiTask.swift in Sources */, + 21F366322B02695B00416B65 /* UIColorExtensions.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -344,9 +374,10 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = VY3VXRC7P4; + DEVELOPMENT_TEAM = GBC36KP98K; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = Example/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = ApiVideoClient; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; INFOPLIST_KEY_UIMainStoryboardFile = Main; @@ -372,9 +403,10 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = VY3VXRC7P4; + DEVELOPMENT_TEAM = GBC36KP98K; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = Example/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = ApiVideoClient; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; INFOPLIST_KEY_UIMainStoryboardFile = Main; @@ -416,7 +448,23 @@ }; /* End XCConfigurationList section */ +/* Begin XCRemoteSwiftPackageReference section */ + 210D99FC2B0230FF00D568B1 /* XCRemoteSwiftPackageReference "InAppSettingsKit" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/futuretap/InAppSettingsKit.git"; + requirement = { + kind = exactVersion; + version = 3.4.2; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + /* Begin XCSwiftPackageProductDependency section */ + 210D99FD2B0230FF00D568B1 /* InAppSettingsKit */ = { + isa = XCSwiftPackageProductDependency; + package = 210D99FC2B0230FF00D568B1 /* XCRemoteSwiftPackageReference "InAppSettingsKit" */; + productName = InAppSettingsKit; + }; C7BC280127A16604007406AB /* ApiVideoClient */ = { isa = XCSwiftPackageProductDependency; productName = ApiVideoClient; diff --git a/Example/Example.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Example/Example.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 65f7c57..969e0eb 100644 --- a/Example/Example.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Example/Example.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,25 +1,32 @@ { - "object": { - "pins": [ - { - "package": "Alamofire", - "repositoryURL": "https://github.com/Alamofire/Alamofire", - "state": { - "branch": null, - "revision": "d120af1e8638c7da36c8481fd61a66c0c08dc4fc", - "version": "5.4.4" - } - }, - { - "package": "AnyCodable", - "repositoryURL": "https://github.com/Flight-School/AnyCodable", - "state": { - "branch": null, - "revision": "b1a7a8a6186f2fcb28f7bda67cfc545de48b3c80", - "version": "0.6.2" - } + "pins" : [ + { + "identity" : "alamofire", + "kind" : "remoteSourceControl", + "location" : "https://github.com/Alamofire/Alamofire", + "state" : { + "revision" : "d120af1e8638c7da36c8481fd61a66c0c08dc4fc", + "version" : "5.4.4" } - ] - }, - "version": 1 + }, + { + "identity" : "anycodable", + "kind" : "remoteSourceControl", + "location" : "https://github.com/Flight-School/AnyCodable", + "state" : { + "revision" : "b1a7a8a6186f2fcb28f7bda67cfc545de48b3c80", + "version" : "0.6.2" + } + }, + { + "identity" : "inappsettingskit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/futuretap/InAppSettingsKit.git", + "state" : { + "revision" : "08ab93cd15759eed534b821c2ea789d97a0fdca0", + "version" : "3.4.2" + } + } + ], + "version" : 2 } diff --git a/Example/Example/AppDelegate.swift b/Example/Example/AppDelegate.swift index 92ed19d..c0eb3b3 100644 --- a/Example/Example/AppDelegate.swift +++ b/Example/Example/AppDelegate.swift @@ -7,28 +7,22 @@ import UIKit @main class AppDelegate: UIResponder, UIApplicationDelegate { - - - - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + func application(_: UIApplication, didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. return true } // MARK: UISceneSession Lifecycle - func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { + func application(_: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options _: UIScene.ConnectionOptions) -> UISceneConfiguration { // Called when a new scene session is being created. // Use this method to select a configuration to create the new scene with. return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) } - func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { + func application(_: UIApplication, didDiscardSceneSessions _: Set) { // Called when the user discards a scene session. // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. // Use this method to release any resources that were specific to the discarded scenes, as they will not return. } - - } - diff --git a/Example/Example/Assets.xcassets/AppIcon.appiconset/1024.png b/Example/Example/Assets.xcassets/AppIcon.appiconset/1024.png new file mode 100644 index 0000000..3fff53b Binary files /dev/null and b/Example/Example/Assets.xcassets/AppIcon.appiconset/1024.png differ diff --git a/Example/Example/Assets.xcassets/AppIcon.appiconset/120 1.png b/Example/Example/Assets.xcassets/AppIcon.appiconset/120 1.png new file mode 100644 index 0000000..49405f4 Binary files /dev/null and b/Example/Example/Assets.xcassets/AppIcon.appiconset/120 1.png differ diff --git a/Example/Example/Assets.xcassets/AppIcon.appiconset/120 2.png b/Example/Example/Assets.xcassets/AppIcon.appiconset/120 2.png new file mode 100644 index 0000000..49405f4 Binary files /dev/null and b/Example/Example/Assets.xcassets/AppIcon.appiconset/120 2.png differ diff --git a/Example/Example/Assets.xcassets/AppIcon.appiconset/152.png b/Example/Example/Assets.xcassets/AppIcon.appiconset/152.png new file mode 100644 index 0000000..28adb6b Binary files /dev/null and b/Example/Example/Assets.xcassets/AppIcon.appiconset/152.png differ diff --git a/Example/Example/Assets.xcassets/AppIcon.appiconset/167.png b/Example/Example/Assets.xcassets/AppIcon.appiconset/167.png new file mode 100644 index 0000000..298d0c6 Binary files /dev/null and b/Example/Example/Assets.xcassets/AppIcon.appiconset/167.png differ diff --git a/Example/Example/Assets.xcassets/AppIcon.appiconset/180.png b/Example/Example/Assets.xcassets/AppIcon.appiconset/180.png new file mode 100644 index 0000000..ff08a37 Binary files /dev/null and b/Example/Example/Assets.xcassets/AppIcon.appiconset/180.png differ diff --git a/Example/Example/Assets.xcassets/AppIcon.appiconset/20.png b/Example/Example/Assets.xcassets/AppIcon.appiconset/20.png new file mode 100644 index 0000000..b88c87b Binary files /dev/null and b/Example/Example/Assets.xcassets/AppIcon.appiconset/20.png differ diff --git a/Example/Example/Assets.xcassets/AppIcon.appiconset/29.png b/Example/Example/Assets.xcassets/AppIcon.appiconset/29.png new file mode 100644 index 0000000..fbd42b9 Binary files /dev/null and b/Example/Example/Assets.xcassets/AppIcon.appiconset/29.png differ diff --git a/Example/Example/Assets.xcassets/AppIcon.appiconset/40 1.png b/Example/Example/Assets.xcassets/AppIcon.appiconset/40 1.png new file mode 100644 index 0000000..af2c141 Binary files /dev/null and b/Example/Example/Assets.xcassets/AppIcon.appiconset/40 1.png differ diff --git a/Example/Example/Assets.xcassets/AppIcon.appiconset/40 2.png b/Example/Example/Assets.xcassets/AppIcon.appiconset/40 2.png new file mode 100644 index 0000000..af2c141 Binary files /dev/null and b/Example/Example/Assets.xcassets/AppIcon.appiconset/40 2.png differ diff --git a/Example/Example/Assets.xcassets/AppIcon.appiconset/40.png b/Example/Example/Assets.xcassets/AppIcon.appiconset/40.png new file mode 100644 index 0000000..af2c141 Binary files /dev/null and b/Example/Example/Assets.xcassets/AppIcon.appiconset/40.png differ diff --git a/Example/Example/Assets.xcassets/AppIcon.appiconset/58 1.png b/Example/Example/Assets.xcassets/AppIcon.appiconset/58 1.png new file mode 100644 index 0000000..110dac7 Binary files /dev/null and b/Example/Example/Assets.xcassets/AppIcon.appiconset/58 1.png differ diff --git a/Example/Example/Assets.xcassets/AppIcon.appiconset/58.png b/Example/Example/Assets.xcassets/AppIcon.appiconset/58.png new file mode 100644 index 0000000..110dac7 Binary files /dev/null and b/Example/Example/Assets.xcassets/AppIcon.appiconset/58.png differ diff --git a/Example/Example/Assets.xcassets/AppIcon.appiconset/60.png b/Example/Example/Assets.xcassets/AppIcon.appiconset/60.png new file mode 100644 index 0000000..683adad Binary files /dev/null and b/Example/Example/Assets.xcassets/AppIcon.appiconset/60.png differ diff --git a/Example/Example/Assets.xcassets/AppIcon.appiconset/76.png b/Example/Example/Assets.xcassets/AppIcon.appiconset/76.png new file mode 100644 index 0000000..60f8825 Binary files /dev/null and b/Example/Example/Assets.xcassets/AppIcon.appiconset/76.png differ diff --git a/Example/Example/Assets.xcassets/AppIcon.appiconset/80 1.png b/Example/Example/Assets.xcassets/AppIcon.appiconset/80 1.png new file mode 100644 index 0000000..9dfb993 Binary files /dev/null and b/Example/Example/Assets.xcassets/AppIcon.appiconset/80 1.png differ diff --git a/Example/Example/Assets.xcassets/AppIcon.appiconset/80.png b/Example/Example/Assets.xcassets/AppIcon.appiconset/80.png new file mode 100644 index 0000000..9dfb993 Binary files /dev/null and b/Example/Example/Assets.xcassets/AppIcon.appiconset/80.png differ diff --git a/Example/Example/Assets.xcassets/AppIcon.appiconset/87.png b/Example/Example/Assets.xcassets/AppIcon.appiconset/87.png new file mode 100644 index 0000000..d564d5d Binary files /dev/null and b/Example/Example/Assets.xcassets/AppIcon.appiconset/87.png differ diff --git a/Example/Example/Assets.xcassets/AppIcon.appiconset/Contents.json b/Example/Example/Assets.xcassets/AppIcon.appiconset/Contents.json index 9221b9b..83e2c62 100644 --- a/Example/Example/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/Example/Example/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -1,91 +1,109 @@ { "images" : [ { + "filename" : "40.png", "idiom" : "iphone", "scale" : "2x", "size" : "20x20" }, { + "filename" : "60.png", "idiom" : "iphone", "scale" : "3x", "size" : "20x20" }, { + "filename" : "58 1.png", "idiom" : "iphone", "scale" : "2x", "size" : "29x29" }, { + "filename" : "87.png", "idiom" : "iphone", "scale" : "3x", "size" : "29x29" }, { + "filename" : "80 1.png", "idiom" : "iphone", "scale" : "2x", "size" : "40x40" }, { + "filename" : "120 2.png", "idiom" : "iphone", "scale" : "3x", "size" : "40x40" }, { + "filename" : "120 1.png", "idiom" : "iphone", "scale" : "2x", "size" : "60x60" }, { + "filename" : "180.png", "idiom" : "iphone", "scale" : "3x", "size" : "60x60" }, { + "filename" : "20.png", "idiom" : "ipad", "scale" : "1x", "size" : "20x20" }, { + "filename" : "40 1.png", "idiom" : "ipad", "scale" : "2x", "size" : "20x20" }, { + "filename" : "29.png", "idiom" : "ipad", "scale" : "1x", "size" : "29x29" }, { + "filename" : "58.png", "idiom" : "ipad", "scale" : "2x", "size" : "29x29" }, { + "filename" : "40 2.png", "idiom" : "ipad", "scale" : "1x", "size" : "40x40" }, { + "filename" : "80.png", "idiom" : "ipad", "scale" : "2x", "size" : "40x40" }, { + "filename" : "76.png", "idiom" : "ipad", "scale" : "1x", "size" : "76x76" }, { + "filename" : "152.png", "idiom" : "ipad", "scale" : "2x", "size" : "76x76" }, { + "filename" : "167.png", "idiom" : "ipad", "scale" : "2x", "size" : "83.5x83.5" }, { + "filename" : "1024.png", "idiom" : "ios-marketing", "scale" : "1x", "size" : "1024x1024" diff --git a/Example/Example/Base.lproj/Assets.xcassets/AccentColor.colorset/Contents.json b/Example/Example/Base.lproj/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 0000000..eb87897 --- /dev/null +++ b/Example/Example/Base.lproj/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Example/Example/Base.lproj/Assets.xcassets/AppIcon.appiconset/Contents.json b/Example/Example/Base.lproj/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..9221b9b --- /dev/null +++ b/Example/Example/Base.lproj/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,98 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "60x60" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "60x60" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "83.5x83.5" + }, + { + "idiom" : "ios-marketing", + "scale" : "1x", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Example/Example/Base.lproj/Assets.xcassets/Contents.json b/Example/Example/Base.lproj/Assets.xcassets/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/Example/Example/Base.lproj/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Example/Example/Base.lproj/Main.storyboard b/Example/Example/Base.lproj/Main.storyboard index a6c7b99..0f181a5 100644 --- a/Example/Example/Base.lproj/Main.storyboard +++ b/Example/Example/Base.lproj/Main.storyboard @@ -1,54 +1,18 @@ - + - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -59,39 +23,13 @@ - - - - - - - - - - - - - - - - - - - - - - - + - - - - diff --git a/Example/Example/Cell/VideoTableViewCell.swift b/Example/Example/Cell/VideoTableViewCell.swift deleted file mode 100644 index 58ff270..0000000 --- a/Example/Example/Cell/VideoTableViewCell.swift +++ /dev/null @@ -1,84 +0,0 @@ -// -// VideoTableViewCell.swift -// Example -// - -import UIKit - -class VideoTableViewCell: UITableViewCell { - - static let identifier = "VideoTableViewCell" - - private let title: UILabel = { - let label = UILabel() - label.numberOfLines = 1 - return label - }() - private let videoId: UILabel = { - let label = UILabel() - label.numberOfLines = 1 - return label - }() - - private let myImageView: UIImageView = { - let imageView = UIImageView() - return imageView - }() - - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - contentView.addSubview(title) - contentView.addSubview(videoId) - contentView.addSubview(myImageView) - myImageView.contentMode = .scaleAspectFit - myImageView.backgroundColor = .black - contentView.clipsToBounds = true - accessoryType = .none - } - - required init?(coder: NSCoder){ - fatalError() - } - - override func layoutSubviews() { - super.layoutSubviews() - myImageView.frame = CGRect( - x: 10, - y: 5, - width: contentView.frame.size.width - 20, - height: contentView.frame.size.height * 0.7 - ) - - title.frame = CGRect( - x: 20, - y: (myImageView.frame.height * 0.6) + 55, - width: contentView.frame.size.width, - height: contentView.frame.size.height * 0.4 - ) - videoId.frame = CGRect( - x: 20, - y: (myImageView.frame.height * 0.6) + 80, - width: contentView.frame.size.width, - height: contentView.frame.size.height * 0.4 - ) - videoId.textColor = .lightGray - videoId.font = videoId.font.withSize(10) - } - - override func prepareForReuse() { - super.prepareForReuse() - title.text = nil - videoId.text = nil - } - - public func configure(with model: VideosOption){ - title.text = model.title - videoId.text = model.videoId - - let myUrl = URL(string: model.thumbnail!) - let myData = try? Data(contentsOf: myUrl!) - myImageView.image = UIImage(data: myData!) - - } - -} diff --git a/Example/Example/ClientManager.swift b/Example/Example/ClientManager.swift deleted file mode 100644 index 97ac907..0000000 --- a/Example/Example/ClientManager.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// ClientManager.swift -// Example -// - -import Foundation -import ApiVideoClient - -class ClientManager{ - public static var apiKey: String = "" - public static var environment: Environment = Environment.sandbox - - public static func environmentToBool()-> Bool{ - var isOn = false - if(environment == Environment.production){ - isOn = true - } - return isOn - } - -} diff --git a/Example/Example/Controller/UploaderViewController.swift b/Example/Example/Controller/UploaderViewController.swift deleted file mode 100644 index 99864af..0000000 --- a/Example/Example/Controller/UploaderViewController.swift +++ /dev/null @@ -1,260 +0,0 @@ -// -// UploaderViewController.swift -// Example -// - -import UIKit -import AVKit -import ApiVideoClient -import SwiftUI - -class UploaderViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate, UITextFieldDelegate { - let imagePickerController = UIImagePickerController() - - let paramBackgroundView: UIView = { - let paramView = UIView() - return paramView - }() - let environmentTitleLabel: UILabel = { - let title = UILabel() - title.text = "Environment" - title.font = UIFont.systemFont(ofSize: 22, weight: .bold) - return title - }() - - let selectedEnvironmentLabel: UILabel = { - let title = UILabel() - title.text = "Production" - return title - }() - - let selectEnvironmentSwitch: UISwitch = { - let selectSwitch = UISwitch() - return selectSwitch - }() - - let uplaodButton: UIButton = { - let btn = UIButton(type: .system) - btn.setTitle("Upload", for: .normal) - return btn - }() - - let apiKeyLabel: UILabel = { - let api = UILabel() - api.text = "Your Api key :" - return api - }() - - let apiKeyTextField: UITextField = { - let api = UITextField() - return api - }() - - let titleSelectVideoLabel: UILabel = { - let titleLabel = UILabel() - titleLabel.text = "Choose your video :" - return titleLabel - }() - - let selectVideoButton: UIButton = { - let btn = UIButton(type: .system) - btn.setTitle("Select Video", for: .normal) - return btn - }() - - let thumbnailImageView: UIImageView = { - let thumbnail = UIImageView() - thumbnail.backgroundColor = .gray - return thumbnail - }() - - private var videoUrl: URL? - - override func viewDidLoad() { - super.viewDidLoad() - title = "Uploader" - view.addSubview(paramBackgroundView) - paramBackgroundView.backgroundColor = .darkGray - paramBackgroundView.layer.cornerRadius = 10 - paramBackgroundView.addSubview(environmentTitleLabel) - paramBackgroundView.addSubview(selectedEnvironmentLabel) - paramBackgroundView.addSubview(selectEnvironmentSwitch) - paramBackgroundView.addSubview(apiKeyLabel) - - paramBackgroundView.addSubview(apiKeyTextField) - apiKeyLabel.frame = CGRect(x: 0, y: 0, width: 105, height: 30) - view.addSubview(titleSelectVideoLabel) - view.addSubview(thumbnailImageView) - view.addSubview(selectVideoButton) - view.addSubview(uplaodButton) - - self.selectVideoButton.addTarget(self, action: #selector(selectVideo), for: .touchUpInside) - self.uplaodButton.addTarget(self, action: #selector(uploadVideo), for: .touchUpInside) - self.selectEnvironmentSwitch.addTarget(self, action: #selector(toggleSwitch), for: .touchUpInside) - - selectEnvironmentSwitch.isOn = ClientManager.environmentToBool() - if(!selectEnvironmentSwitch.isOn){ - selectedEnvironmentLabel.text = "Sandbox" - } - - apiKeyTextField.addTarget(self, action: #selector(UploaderViewController.textFieldDidChange(_:)), for: .editingChanged) - apiKeyTextField.delegate = self - apiKeyTextField.text = ClientManager.apiKey - - constraints() - } - - func constraints(){ - paramBackgroundView.translatesAutoresizingMaskIntoConstraints = false - uplaodButton.translatesAutoresizingMaskIntoConstraints = false - environmentTitleLabel.translatesAutoresizingMaskIntoConstraints = false - selectedEnvironmentLabel.translatesAutoresizingMaskIntoConstraints = false - selectEnvironmentSwitch.translatesAutoresizingMaskIntoConstraints = false - apiKeyLabel.translatesAutoresizingMaskIntoConstraints = false - apiKeyTextField.translatesAutoresizingMaskIntoConstraints = false - titleSelectVideoLabel.translatesAutoresizingMaskIntoConstraints = false - selectVideoButton.translatesAutoresizingMaskIntoConstraints = false - thumbnailImageView.translatesAutoresizingMaskIntoConstraints = false - - paramBackgroundView.widthAnchor.constraint(equalToConstant: view.frame.width - 20).isActive = true - paramBackgroundView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 30).isActive = true - paramBackgroundView.heightAnchor.constraint(equalToConstant: 150).isActive = true - paramBackgroundView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true - - environmentTitleLabel.centerXAnchor.constraint(equalTo: paramBackgroundView.centerXAnchor).isActive = true - environmentTitleLabel.topAnchor.constraint(equalTo: paramBackgroundView.topAnchor, constant: 10).isActive = true - - - selectedEnvironmentLabel.topAnchor.constraint(equalTo: paramBackgroundView.topAnchor, constant: 50).isActive = true - selectedEnvironmentLabel.leftAnchor.constraint(equalTo: paramBackgroundView.leftAnchor, constant: 20).isActive = true - selectedEnvironmentLabel.widthAnchor.constraint(equalToConstant: (view.frame.width - 20 )/2).isActive = true - - selectEnvironmentSwitch.centerYAnchor.constraint(equalTo: selectedEnvironmentLabel.centerYAnchor).isActive = true - selectEnvironmentSwitch.rightAnchor.constraint(equalTo: paramBackgroundView.rightAnchor, constant: -20).isActive = true - - - apiKeyLabel.topAnchor.constraint(equalTo: paramBackgroundView.topAnchor, constant: 80).isActive = true - apiKeyLabel.bottomAnchor.constraint(equalTo: paramBackgroundView.bottomAnchor).isActive = true - apiKeyLabel.leftAnchor.constraint(equalTo: paramBackgroundView.leftAnchor, constant: 20).isActive = true - - apiKeyTextField.centerYAnchor.constraint(equalTo: apiKeyLabel.centerYAnchor).isActive = true - apiKeyTextField.topAnchor.constraint(equalTo: paramBackgroundView.topAnchor, constant: 80).isActive = true - apiKeyTextField.bottomAnchor.constraint(equalTo: paramBackgroundView.bottomAnchor).isActive = true - apiKeyTextField.rightAnchor.constraint(equalTo: paramBackgroundView.rightAnchor, constant: -20).isActive = true - apiKeyTextField.widthAnchor.constraint(equalToConstant: 250).isActive = true - - titleSelectVideoLabel.topAnchor.constraint(equalTo: paramBackgroundView.bottomAnchor, constant: 30).isActive = true - titleSelectVideoLabel.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 30).isActive = true - - thumbnailImageView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true - thumbnailImageView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 20).isActive = true - thumbnailImageView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -20).isActive = true - thumbnailImageView.heightAnchor.constraint(equalToConstant: 220).isActive = true - thumbnailImageView.topAnchor.constraint(equalTo: titleSelectVideoLabel.bottomAnchor, constant: 20).isActive = true - - - selectVideoButton.widthAnchor.constraint(equalToConstant: 110).isActive = true - selectVideoButton.heightAnchor.constraint(equalToConstant: 40).isActive = true - - selectVideoButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true - selectVideoButton.topAnchor.constraint(equalTo: thumbnailImageView.bottomAnchor, constant: 10).isActive = true - - uplaodButton.widthAnchor.constraint(equalToConstant: 70).isActive = true - uplaodButton.heightAnchor.constraint(equalToConstant: 40).isActive = true - uplaodButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true - uplaodButton.topAnchor.constraint(equalTo: selectVideoButton.bottomAnchor, constant: 20).isActive = true - - // uplaodButton.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 40).isActive = true - - } - - @objc func selectVideo() { - imagePickerController.sourceType = .photoLibrary - imagePickerController.delegate = self - imagePickerController.mediaTypes = ["public.movie"] - imagePickerController.allowsEditing = false - imagePickerController.videoQuality = .typeHigh - - // for IOS 11 and more - if #available(iOS 11.0, *) { - //desable video compressing to get the highest video quality - imagePickerController.videoExportPreset = AVAssetExportPresetPassthrough - } - - present(imagePickerController, animated: true, completion: nil) - } - - func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { - let url = info[.mediaURL] as! URL - videoUrl = url - thumbnailImageView.image = getThumbnailImage(forUrl: url) - imagePickerController.dismiss(animated: true, completion: nil) - } - - func upload(url: URL) { - VideosAPI.create(videoCreationPayload: VideoCreationPayload(title: "my video")) { video, error in - if let video = video { - do { - try VideosAPI.upload( - videoId: video.videoId, - file: url, - onProgressReady: { progress in - print("Progress: \(progress)") - }) { video, error in - if video != nil { - self.thumbnailImageView.image = nil - } - if let error = error { - print("Upload error: \(error)") - } - } - } catch { - print("Upload error: \(error)") - } - } - if let error = error { - print("Create error: \(error)") - } - } - } - - @objc func uploadVideo(){ - if(videoUrl != nil){ - upload(url: videoUrl!) - }else{ - print("error video") - } - - } - - @objc func toggleSwitch(){ - if(selectEnvironmentSwitch.isOn){ - ClientManager.environment = Environment.production - selectedEnvironmentLabel.text = "Production" - - }else{ - ClientManager.environment = Environment.sandbox - selectedEnvironmentLabel.text = "Sandbox" - } - } - - - func getThumbnailImage(forUrl url: URL) -> UIImage? { - let asset: AVAsset = AVAsset(url: url) - let imageGenerator = AVAssetImageGenerator(asset: asset) - - do { - let thumbnailImage = try imageGenerator.copyCGImage(at: CMTimeMake(value: 1, timescale: 60), actualTime: nil) - return UIImage(cgImage: thumbnailImage) - } catch let error { - print(error) - } - - return nil - } - - @objc func textFieldDidChange(_ textField: UITextField) { - ClientManager.apiKey = textField.text! - } - -} diff --git a/Example/Example/Controller/VideosViewController.swift b/Example/Example/Controller/VideosViewController.swift deleted file mode 100644 index 7293429..0000000 --- a/Example/Example/Controller/VideosViewController.swift +++ /dev/null @@ -1,85 +0,0 @@ -// -// ViewController.swift -// Example -// - -import UIKit -import ApiVideoClient - -struct VideosOption{ - let title:String - let videoId: String - let thumbnail: String? - let handler: (()->Void) -} - -class VideosViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { - var models = [VideosOption]() - - private func configure(){ - - ApiVideoClient.apiKey = ClientManager.apiKey - ApiVideoClient.basePath = ClientManager.environment.rawValue - - VideosAPI.list(title: nil, tags: nil, metadata: nil, description: nil, liveStreamId: nil, sortBy: nil, sortOrder: nil, currentPage: nil, pageSize: nil) { (response, error) in - guard error == nil else { - print(error ?? "error") - return - } - - if ((response) != nil) { - for item in response!.data { - self.models.append(VideosOption(title: item.title ?? "error title", videoId: item.videoId, thumbnail: item.assets?.thumbnail){ - - }) - self.tableView.reloadData() - } - } - } - } - - func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { - let headerView = UIView() - headerView.backgroundColor = UIColor.clear - return headerView - } - - func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return models.count - } - - func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let model = models[indexPath.row] - - - guard let cell = tableView.dequeueReusableCell(withIdentifier: VideoTableViewCell.identifier, for: indexPath) as? VideoTableViewCell else{ - return UITableViewCell() - } - cell.layer.cornerRadius = 8 - cell.configure(with: model) - return cell - } - - - private let tableView: UITableView = { - let table = UITableView(frame: .zero, style: .grouped) - table.register(VideoTableViewCell.self, forCellReuseIdentifier: VideoTableViewCell.identifier) - return table - }() - - override func viewDidLoad() { - super.viewDidLoad() - configure() - title = "Videos" - view.addSubview(tableView) - tableView.delegate = self - tableView.dataSource = self - tableView.frame = view.bounds - tableView.rowHeight = 310.0 - } - - - - -} - diff --git a/Example/Example/MainViewController.swift b/Example/Example/MainViewController.swift new file mode 100644 index 0000000..039e594 --- /dev/null +++ b/Example/Example/MainViewController.swift @@ -0,0 +1,164 @@ +// +// UploaderViewController.swift +// Example +// + +import ApiVideoClient +import AVKit +import InAppSettingsKit +import SwiftUI +import UIKit + +class MainViewController: UIViewController { + let imagePickerController = UIImagePickerController() + + /// Handle multiple upload tasks to cancel them easily + /// It also runs them sequentially. We upload the file sequentially to simplify the upload progress bar. + let taskManager = TaskManager() + + /// Manage configuration + let iaskViewController: IASKAppSettingsViewController = { + let iaskViewController = IASKAppSettingsViewController() + iaskViewController.showCreditsFooter = false + iaskViewController.view.tintColor = UIColor.orange + return iaskViewController + }() + + let videoPickerButton: UIButton = { + let btn = UIButton(type: .system) + btn.setTitle("Pick a video", for: .normal) + btn.tintColor = UIColor.orange + return btn + }() + + let progressView: UIProgressView = { + let view = UIProgressView() + view.progressTintColor = UIColor.orange + view.isHidden = true + return view + }() + + let cancelButton: UIButton = { + let btn = UIButton(type: .system) + btn.setTitle("Cancel all uploads", for: .normal) + btn.tintColor = UIColor.orange + btn.isHidden = true + return btn + }() + + override func viewDidLoad() { + super.viewDidLoad() + + title = "Uploader" + // Increasing timeout to 120s + ApiVideoClient.timeout = 120 + + addChild(iaskViewController) + view.addSubview(iaskViewController.view) + + view.addSubview(videoPickerButton) + view.addSubview(progressView) + view.addSubview(cancelButton) + + videoPickerButton.addTarget(self, action: #selector(pickVideo), for: .touchUpInside) + cancelButton.addTarget(self, action: #selector(cleanUploadQueue), for: .touchUpInside) + + constraints() + } + + func constraints() { + iaskViewController.view.translatesAutoresizingMaskIntoConstraints = false + videoPickerButton.translatesAutoresizingMaskIntoConstraints = false + progressView.translatesAutoresizingMaskIntoConstraints = false + cancelButton.translatesAutoresizingMaskIntoConstraints = false + + iaskViewController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true + iaskViewController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true + iaskViewController.view.heightAnchor.constraint(equalToConstant: 300).isActive = true + iaskViewController.view.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true + iaskViewController.view.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 10).isActive = true + + videoPickerButton.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true + videoPickerButton.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true + videoPickerButton.heightAnchor.constraint(equalToConstant: 40).isActive = true + videoPickerButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true + videoPickerButton.topAnchor.constraint(equalTo: iaskViewController.view.bottomAnchor, constant: 20).isActive = true + + progressView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true + progressView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true + progressView.heightAnchor.constraint(equalToConstant: 10).isActive = true + progressView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true + progressView.topAnchor.constraint(equalTo: videoPickerButton.bottomAnchor, constant: 10).isActive = true + + cancelButton.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true + cancelButton.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true + cancelButton.heightAnchor.constraint(equalToConstant: 40).isActive = true + cancelButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true + cancelButton.topAnchor.constraint(equalTo: progressView.bottomAnchor, constant: 10).isActive = true + } + + @objc func cleanUploadQueue() { + taskManager.cancelAll() + } + + @objc func pickVideo() { + imagePickerController.sourceType = .photoLibrary + imagePickerController.delegate = self + imagePickerController.mediaTypes = ["public.movie"] + imagePickerController.allowsEditing = false + imagePickerController.videoQuality = .typeHigh + + // for IOS 11 and more + if #available(iOS 11.0, *) { + // disable video compressing to get the highest video quality + imagePickerController.videoExportPreset = AVAssetExportPresetPassthrough + } + + present(imagePickerController, animated: true, completion: nil) + } + + /// Adds the upload task to the ``TaskManager`` + func addToUploadQueue(videoUrl: URL) { + taskManager.add { + do { + return try await self.upload(fileUrl: videoUrl, progress: { progress in + print("Progress: \(progress.fractionCompleted)") + self.progressView.progress = Float(progress.fractionCompleted) + }) + } catch { + print("Upload error: \(error)") + AlertUtils.show(error.localizedDescription, title: "Error", vc: self) + throw error + } + } + } + + /// Creates and uploads a video with async/await + private func upload(fileUrl: URL, progress: ((Progress) -> Void)? = nil) async throws { + let video = try await AsyncApiUtils.createVideo() + let uploadedVideo = try await AsyncApiUtils.uploadVideo(videoId: video.videoId, url: fileUrl, progress: progress) + + print("Video uploaded: \(uploadedVideo)") + AlertUtils.show("File has been successfully uploaded at video ID: \(video.videoId)", title: "Success", vc: self) + } +} + +extension MainViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate { + func imagePickerController(_: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) { + guard let url = info[.mediaURL] as? URL else { + AlertUtils.show("No video selected", vc: self) + return + } + + imagePickerController.dismiss(animated: true, completion: nil) + cancelButton.isHidden = false + progressView.isHidden = false + + // Set client configuration + ApiVideoClient.apiKey = SettingsManager.apiKey + ApiVideoClient.basePath = SettingsManager.environment.rawValue + + // Upload + addToUploadQueue(videoUrl: url) + } +} diff --git a/Example/Example/Models/CancellableApiTask.swift b/Example/Example/Models/CancellableApiTask.swift new file mode 100644 index 0000000..c4a7cfc --- /dev/null +++ b/Example/Example/Models/CancellableApiTask.swift @@ -0,0 +1,99 @@ +import ApiVideoClient +import Foundation + +/// A wrapper around ``RequestTask`` to make it cancellable +class CancellableTask { + internal var task: RequestTask? + + /// Execute the task + func execute() async throws -> T { + fatalError("Not implemented") + } + + /// Cancel the task + func cancel() { + task?.cancel() + } +} + +/// An async/await wrapper around ``VideosAPI.upload`` to make it cancellable +class CancellableUploadVideoTask: CancellableTask