Friday Commit
This commit is contained in:
@@ -233,6 +233,7 @@
|
||||
9C834ED72C1C1F9200B29A9C /* Exo2-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 9C56E8332BDBC3EF00E4CA14 /* Exo2-Regular.ttf */; };
|
||||
9C834ED82C1C1F9200B29A9C /* Exo2-Thin.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 9C56E8312BDBC3EF00E4CA14 /* Exo2-Thin.ttf */; };
|
||||
9C834EDC2C1C26CD00B29A9C /* HtmlText.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C834EDB2C1C26CD00B29A9C /* HtmlText.swift */; };
|
||||
9C8446872C40FC6E003E3E53 /* AVPlayerTesting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C8446862C40FC6E003E3E53 /* AVPlayerTesting.swift */; };
|
||||
9C8C4FAE2C1315410017DD3B /* WebViewVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C8C4FAD2C1315410017DD3B /* WebViewVC.swift */; };
|
||||
9C8C4FB02C1328060017DD3B /* Disclaimer.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 9C8C4FAF2C1328060017DD3B /* Disclaimer.rtf */; };
|
||||
9C9BEEC72BEE1BBF004ECC2F /* CollectionViewCenteredFlowLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C9BEEC62BEE1BBF004ECC2F /* CollectionViewCenteredFlowLayout.swift */; };
|
||||
@@ -505,6 +506,7 @@
|
||||
9C834EC52C1C1D9500B29A9C /* BlogDetailsVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlogDetailsVC.swift; sourceTree = "<group>"; };
|
||||
9C834ED92C1C20EC00B29A9C /* WOKA.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = WOKA.entitlements; sourceTree = "<group>"; };
|
||||
9C834EDB2C1C26CD00B29A9C /* HtmlText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HtmlText.swift; sourceTree = "<group>"; };
|
||||
9C8446862C40FC6E003E3E53 /* AVPlayerTesting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AVPlayerTesting.swift; sourceTree = "<group>"; };
|
||||
9C8C4FAD2C1315410017DD3B /* WebViewVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebViewVC.swift; sourceTree = "<group>"; };
|
||||
9C8C4FAF2C1328060017DD3B /* Disclaimer.rtf */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; path = Disclaimer.rtf; sourceTree = "<group>"; };
|
||||
9C9BEEC62BEE1BBF004ECC2F /* CollectionViewCenteredFlowLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CollectionViewCenteredFlowLayout.swift; sourceTree = "<group>"; };
|
||||
@@ -1391,6 +1393,7 @@
|
||||
52F4E8652C3D123B00778FBC /* JWKaraokePlayerVC.swift */,
|
||||
525FC61C2C3D3DC30049145D /* AVAssetMods.swift */,
|
||||
525FC65C2C3D57D80049145D /* TestingKaraokeVC.swift */,
|
||||
9C8446862C40FC6E003E3E53 /* AVPlayerTesting.swift */,
|
||||
);
|
||||
path = Controller;
|
||||
sourceTree = "<group>";
|
||||
@@ -1764,6 +1767,7 @@
|
||||
52BC3BF02C1701F8002FACA6 /* BlogDM.swift in Sources */,
|
||||
525954192BE8CC3400191286 /* ConstantString.swift in Sources */,
|
||||
52D774EB2BDFC0BF001D87DE /* OTPVC.swift in Sources */,
|
||||
9C8446872C40FC6E003E3E53 /* AVPlayerTesting.swift in Sources */,
|
||||
52AF71F42C36C40B00BC5972 /* GamesWebViewVC.swift in Sources */,
|
||||
9C007F202C255DF200F798C2 /* SeasonEpisodeListingDM.swift in Sources */,
|
||||
52D2F3D82C24043D009E52FF /* ShimmerEffectView.swift in Sources */,
|
||||
|
||||
22
WOKA/Karaoke/Controller/AVPlayerTesting.swift
Normal file
22
WOKA/Karaoke/Controller/AVPlayerTesting.swift
Normal file
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// AVPlayerTesting.swift
|
||||
// WOKA
|
||||
//
|
||||
// Created by Bilal on 12/07/2024.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import AVKit
|
||||
|
||||
class AVPlayerTesting: AVPlayerViewController {
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
let videoURL = URL(string: "https://content.jwplatform.com/videos/699dmCGz-Ysj2G4DQ.mp4")!
|
||||
let player = AVPlayer(url: videoURL)
|
||||
self.player = player
|
||||
player.play()
|
||||
// Do any additional setup after loading the view.
|
||||
}
|
||||
|
||||
}
|
||||
@@ -12,56 +12,65 @@ import AVFoundation
|
||||
|
||||
class JWKaraokePlayerVC: JWPlayerViewController, JWPlayerViewControllerDelegate {
|
||||
|
||||
@IBOutlet weak var outerStack: UIStackView!
|
||||
@IBOutlet weak var backButton: UIButton!
|
||||
@IBOutlet weak var startRecordBtn: LocalisedElementsButton!
|
||||
@IBOutlet weak var playBtn: LocalisedElementsButton!
|
||||
@IBOutlet weak var downloadRecordingBtn: LocalisedElementsButton!
|
||||
@IBOutlet weak var karaokeStack: UIStackView!
|
||||
@IBOutlet weak var karaokeLoading: UIActivityIndicatorView!
|
||||
@IBOutlet weak var startStopRecordingStack: UIStackView!
|
||||
@IBOutlet weak var outerStack : UIStackView!
|
||||
|
||||
var config: JWPlayerConfiguration!
|
||||
var dismissTapped: (() -> Void)?
|
||||
var videoIndex : Int?
|
||||
var documentAudioUrl : URL?
|
||||
|
||||
var audioURLFromMP4 : URL?
|
||||
var recordedAudioURL: URL?
|
||||
var audioRecorder: AVAudioRecorder?
|
||||
var videoTitle : String?
|
||||
var videoUrl : String?
|
||||
|
||||
var mixedAudioURL: URL?
|
||||
var isRecording = false
|
||||
var playerAV : AVAudioPlayer?
|
||||
var isPlaying = false
|
||||
|
||||
var mixedAudioURL: URL? {
|
||||
didSet{
|
||||
do{
|
||||
let sPlayer = try AVAudioPlayer(contentsOf: self.mixedAudioURL!)
|
||||
self.playerAV = sPlayer
|
||||
self.playerAV?.prepareToPlay()
|
||||
// self.playerAV?.play()
|
||||
}catch{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
var startTime : TimeInterval?
|
||||
var endTime : TimeInterval?
|
||||
|
||||
var audioPlayer = AVPlayer()
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
player.configurePlayer(with: config)
|
||||
|
||||
self.delegate = self
|
||||
|
||||
//Disable Picture in Picture
|
||||
playerView.allowsPictureInPicturePlayback = false
|
||||
playerView.captionStyle = .none
|
||||
|
||||
self.view.bringSubviewToFront(outerStack)
|
||||
self.view.bringSubviewToFront(backButton)
|
||||
setupRecorder()
|
||||
setupKaraoke()
|
||||
}
|
||||
|
||||
func setupRecorder(){
|
||||
// MARK: - AudioRecording
|
||||
|
||||
func setupAudio() {
|
||||
// FileManager.default.clearTmpDirectory()
|
||||
|
||||
let audioSession = AVAudioSession.sharedInstance()
|
||||
do {
|
||||
try audioSession.setCategory(.playAndRecord, mode: .default,options: .defaultToSpeaker)
|
||||
try audioSession.setActive(true)
|
||||
|
||||
// // URL of the downloaded M4A file
|
||||
// guard let audioURL = Bundle.main.url(forResource: "Sample_audio", withExtension: "m4a") else {
|
||||
// print("Audio file not found.")
|
||||
// return
|
||||
// }
|
||||
|
||||
// Initialize AVAudioPlayer with the downloaded M4A file
|
||||
// player = try AVAudioPlayer(contentsOf: audioURLFromMP4!)
|
||||
// player?.prepareToPlay()
|
||||
|
||||
// Define settings for the audio recorder
|
||||
let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
|
||||
@@ -83,63 +92,148 @@ class JWKaraokePlayerVC: JWPlayerViewController, JWPlayerViewControllerDelegate
|
||||
}
|
||||
|
||||
func startRecording() {
|
||||
guard let player = player, let audioRecorder = audioRecorder else { return }
|
||||
player.play()
|
||||
startTime = self.player.time.position.round(to: 1)
|
||||
self.interfaceBehavior = .hidden
|
||||
guard let audioRecorder = audioRecorder else { return }
|
||||
audioRecorder.record()
|
||||
|
||||
}
|
||||
|
||||
func stopRecording() {
|
||||
guard let player = player, let audioRecorder = audioRecorder else { return }
|
||||
player.pause() // Pause playback instead of stopping it
|
||||
endTime = self.player.time.position.round(to: 1)
|
||||
self.interfaceBehavior = .normal
|
||||
guard let audioRecorder = audioRecorder else { return }
|
||||
audioRecorder.stop()
|
||||
|
||||
self.player.pause()
|
||||
// Mix the recorded audio with the downloaded M4A file
|
||||
mixAudio()
|
||||
guard let startTime , let endTime else{return}
|
||||
mixAudio(start: startTime, stop: endTime)
|
||||
}
|
||||
|
||||
func mixAudio() {
|
||||
|
||||
func mixAudio(start : TimeInterval, stop : TimeInterval) {
|
||||
let totalTime = stop - start
|
||||
guard let recordedAudioURL = recordedAudioURL else { return }
|
||||
// guard let playerURL = Bundle.main.url(forResource: "Sample_audio", withExtension: "m4a") else { return }
|
||||
guard let playerURL = documentAudioUrl else{return}
|
||||
guard let playerURL = audioURLFromMP4 else { return }
|
||||
Utilities.startProgressHUD(msg: "Mixing Audio")
|
||||
let composition = AVMutableComposition()
|
||||
let compositionDuration = CMTime(seconds: totalTime, preferredTimescale: 1)
|
||||
|
||||
// Add the recorded audio
|
||||
// Add the recorded audio from 0 to 10 seconds
|
||||
let recordedAudioAsset = AVURLAsset(url: recordedAudioURL)
|
||||
let recordedAudioTrack = composition.addMutableTrack(withMediaType: .audio, preferredTrackID: kCMPersistentTrackID_Invalid)
|
||||
|
||||
do {
|
||||
try recordedAudioTrack?.insertTimeRange(CMTimeRangeMake(start: CMTime.zero, duration: recordedAudioAsset.duration), of: recordedAudioAsset.tracks(withMediaType: .audio)[0], at: CMTime.zero)
|
||||
try recordedAudioTrack?.insertTimeRange(CMTimeRangeMake(start: CMTime.zero, duration: compositionDuration), of: recordedAudioAsset.tracks(withMediaType: .audio)[0], at: CMTime.zero)
|
||||
} catch {
|
||||
Utilities.dismissProgressHUD()
|
||||
print("Error adding recorded audio track: \(error.localizedDescription)")
|
||||
}
|
||||
|
||||
// Add the downloaded M4A file
|
||||
// Add the downloaded M4A file from 10 to 20 seconds
|
||||
let playerAsset = AVURLAsset(url: playerURL)
|
||||
let playerTrack = composition.addMutableTrack(withMediaType: .audio, preferredTrackID: kCMPersistentTrackID_Invalid)
|
||||
|
||||
do {
|
||||
try playerTrack?.insertTimeRange(CMTimeRangeMake(start: CMTime.zero, duration: playerAsset.duration), of: playerAsset.tracks(withMediaType: .audio)[0], at: CMTime.zero)
|
||||
try playerTrack?.insertTimeRange(CMTimeRangeMake(start: CMTime(seconds: start, preferredTimescale: 1), duration: compositionDuration), of: playerAsset.tracks(withMediaType: .audio)[0], at: CMTime.zero)
|
||||
} catch {
|
||||
Utilities.dismissProgressHUD()
|
||||
print("Error adding player audio track: \(error.localizedDescription)")
|
||||
}
|
||||
|
||||
// Example usage:
|
||||
|
||||
|
||||
// Export the mixed audio
|
||||
let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
|
||||
mixedAudioURL = documentsDirectory.appendingPathComponent("mixedAudio.m4a")
|
||||
let filePath = documentsDirectory.appendingPathComponent("mixedAudio.m4a")
|
||||
deleteFileIfExist(at: filePath)
|
||||
|
||||
mixedAudioURL = filePath
|
||||
// mixedAudioURL = documentsDirectory.appendingPathComponent("mixedAudio.m4a")
|
||||
|
||||
guard let exportSession = AVAssetExportSession(asset: composition, presetName: AVAssetExportPresetAppleM4A) else { return }
|
||||
exportSession.outputURL = mixedAudioURL
|
||||
exportSession.outputFileType = .m4a
|
||||
|
||||
exportSession.exportAsynchronously {
|
||||
if exportSession.status == .completed {
|
||||
print("Mixing audio completed.")
|
||||
Utilities.dismissProgressHUD()
|
||||
DispatchQueue.main.async {
|
||||
self.playBtn.isEnabled = true
|
||||
}
|
||||
|
||||
|
||||
self.saveToFilesApp()
|
||||
// Play the mixed audio if needed
|
||||
} else if exportSession.status == .failed {
|
||||
print("Mixing audio failed.")
|
||||
print("Mixing audio failed.", exportSession.error?.localizedDescription)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func deleteFileIfExist(at url: URL) {
|
||||
let fileManager = FileManager.default
|
||||
|
||||
do {
|
||||
// Check if the file exists
|
||||
if fileManager.fileExists(atPath: url.path) {
|
||||
// Attempt to delete the file
|
||||
try fileManager.removeItem(at: url)
|
||||
print("File deleted successfully.")
|
||||
} else {
|
||||
print("File does not exist at path: \(url.path)")
|
||||
}
|
||||
} catch {
|
||||
print("Error deleting file: \(error.localizedDescription)")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// func mixAudio() {
|
||||
// guard let recordedAudioURL = recordedAudioURL else { return }
|
||||
// guard let playerURL = audioURLFromMP4 else{return}
|
||||
// let composition = AVMutableComposition()
|
||||
//
|
||||
// // Add the recorded audio
|
||||
// let recordedAudioAsset = AVURLAsset(url: recordedAudioURL)
|
||||
// let recordedAudioTrack = composition.addMutableTrack(withMediaType: .audio, preferredTrackID: kCMPersistentTrackID_Invalid)
|
||||
// do {
|
||||
// try recordedAudioTrack?.insertTimeRange(CMTimeRangeMake(start: CMTime.zero, duration: recordedAudioAsset.duration), of: recordedAudioAsset.tracks(withMediaType: .audio)[0], at: CMTime.zero)
|
||||
// } catch {
|
||||
// print("Error adding recorded audio track: \(error.localizedDescription)")
|
||||
// }
|
||||
//
|
||||
// // Add the downloaded M4A file
|
||||
// let playerAsset = AVURLAsset(url: playerURL)
|
||||
// let playerTrack = composition.addMutableTrack(withMediaType: .audio, preferredTrackID: kCMPersistentTrackID_Invalid)
|
||||
//
|
||||
// do {
|
||||
// try playerTrack?.insertTimeRange(CMTimeRangeMake(start: CMTime.zero, duration: playerAsset.duration), of: playerAsset.tracks(withMediaType: .audio)[0], at: CMTime.zero)
|
||||
// } catch {
|
||||
// print("Error adding player audio track: \(error.localizedDescription)")
|
||||
// }
|
||||
//
|
||||
// // Export the mixed audio
|
||||
// let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
|
||||
// mixedAudioURL = documentsDirectory.appendingPathComponent("mixedAudio.m4a")
|
||||
// guard let exportSession = AVAssetExportSession(asset: composition, presetName: AVAssetExportPresetAppleM4A) else { return }
|
||||
// exportSession.outputURL = mixedAudioURL
|
||||
// exportSession.outputFileType = .m4a
|
||||
// exportSession.exportAsynchronously {
|
||||
// if exportSession.status == .completed {
|
||||
// print("Mixing audio completed.")
|
||||
//
|
||||
// self.saveToFilesApp()
|
||||
// // Play the mixed audio if needed
|
||||
//
|
||||
//
|
||||
// } else if exportSession.status == .failed {
|
||||
// print("Mixing audio failed.")
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
func saveToFilesApp() {
|
||||
guard let mixedAudioURL = mixedAudioURL else { return }
|
||||
DispatchQueue.main.async {
|
||||
@@ -149,6 +243,40 @@ class JWKaraokePlayerVC: JWPlayerViewController, JWPlayerViewControllerDelegate
|
||||
}
|
||||
}
|
||||
|
||||
func setupKaraoke(){
|
||||
guard let videoUrl else{return}
|
||||
let avURL = URL(string: videoUrl)!
|
||||
let asset = AVAsset(url: avURL)
|
||||
hideShowKaraoke(isLoading: true)
|
||||
let outputURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("\(videoTitle?.trimmingCharacters(in: .whitespaces) ?? "extractedAudio").m4a")
|
||||
FileManager.default.clearTmpDirectory()
|
||||
asset.writeAudioTrackToURL(outputURL) { [weak self] isDone, error,url in
|
||||
guard let self else{return}
|
||||
print(isDone, error , url)
|
||||
if error == nil{
|
||||
hideShowKaraoke(isLoading: false)
|
||||
self.audioURLFromMP4 = url
|
||||
self.setupAudio()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func hideShowKaraoke(isLoading : Bool){
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
guard let self else{return}
|
||||
if isLoading{
|
||||
karaokeLoading.startAnimating()
|
||||
karaokeStack.isHidden = false
|
||||
startStopRecordingStack.isHidden = true
|
||||
}else{
|
||||
karaokeLoading.stopAnimating()
|
||||
karaokeLoading.hidesWhenStopped = true
|
||||
karaokeStack.isHidden = true
|
||||
startStopRecordingStack.isHidden = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
// self.navigationController?.isNavigationBarHidden = true
|
||||
@@ -160,20 +288,13 @@ class JWKaraokePlayerVC: JWPlayerViewController, JWPlayerViewControllerDelegate
|
||||
}
|
||||
|
||||
@IBAction func startRecordingBtnTapped(_ sender: LocalisedElementsButton) {
|
||||
// if sender.titleLabel?.text?.lowercased() == "start recording"{
|
||||
// guard let audioRecorder else { return }
|
||||
// startRecordBtn.setTitle("Stop Recording", for: .normal)
|
||||
// audioRecorder.record()
|
||||
// }else{
|
||||
// guard let audioRecorder else { return }
|
||||
// startRecordBtn.setTitle("Stop Recording", for: .normal)
|
||||
// audioRecorder.record()
|
||||
// }
|
||||
|
||||
self.playBtn.isEnabled = false
|
||||
if isRecording {
|
||||
stopRecording()
|
||||
self.interfaceBehavior = .normal
|
||||
sender.setTitle("Start Recording", for: .normal)
|
||||
} else {
|
||||
self.interfaceBehavior = .hidden
|
||||
startRecording()
|
||||
sender.setTitle("Stop Recording", for: .normal)
|
||||
}
|
||||
@@ -181,12 +302,57 @@ class JWKaraokePlayerVC: JWPlayerViewController, JWPlayerViewControllerDelegate
|
||||
}
|
||||
|
||||
@IBAction func playBtnTapped(_ sender: LocalisedElementsButton) {
|
||||
playerAV?.play()
|
||||
if !isPlaying {
|
||||
playMixedAudio()
|
||||
self.interfaceBehavior = .normal
|
||||
self.interfaceBehavior = .hidden
|
||||
sender.setTitle("Pause", for: .normal)
|
||||
} else {
|
||||
self.interfaceBehavior = .normal
|
||||
sender.setTitle("Play", for: .normal)
|
||||
}
|
||||
|
||||
isPlaying.toggle()
|
||||
|
||||
self.player.pause()
|
||||
print("Play")
|
||||
}
|
||||
func playMixedAudio() {
|
||||
guard let mixedAudioURL = mixedAudioURL else { return }
|
||||
|
||||
do {
|
||||
|
||||
let documentsDirectoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
|
||||
|
||||
let destinationURL = documentsDirectoryURL.appendingPathComponent("xyze.m4a")
|
||||
|
||||
do {
|
||||
|
||||
try FileManager.default.copyItem(at: mixedAudioURL, to: destinationURL)
|
||||
|
||||
} catch
|
||||
let error as NSError { print(error.localizedDescription)}
|
||||
|
||||
let playerKAraoke = AVPlayer(url: destinationURL)
|
||||
playerKAraoke.volume = 1.0
|
||||
playerKAraoke.play()
|
||||
|
||||
// // Configure the audio session
|
||||
// let audioSession = AVAudioSession.sharedInstance()
|
||||
// try audioSession.setCategory(.playAndRecord, mode: .default, options: [.defaultToSpeaker])
|
||||
// try audioSession.setActive(true)
|
||||
//
|
||||
// let audioPlayer = try AVAudioPlayer(contentsOf: mixedAudioURL)
|
||||
// audioPlayer.volume = 1.0
|
||||
// audioPlayer.play()
|
||||
} catch {
|
||||
print("Error playing mixed audio: \(error.localizedDescription)")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@IBAction func downloadRecording(_ sender: LocalisedElementsButton) {
|
||||
print("DownloadRecording")
|
||||
self.saveToFilesApp()
|
||||
}
|
||||
@IBAction func backBtnTapped(_ sender: UIButton) {
|
||||
self.player.stop()
|
||||
@@ -259,8 +425,29 @@ class JWKaraokePlayerVC: JWPlayerViewController, JWPlayerViewControllerDelegate
|
||||
}
|
||||
|
||||
extension JWKaraokePlayerVC: UIDocumentPickerDelegate {
|
||||
|
||||
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
|
||||
// Handle document picking completion if needed
|
||||
deleteTemporaryFile()
|
||||
|
||||
// guard let selectedURL = urls.first else { return }
|
||||
// do {
|
||||
// try FileManager.default.moveItem(at: fileURL, to: selectedURL)
|
||||
// } catch {
|
||||
// print("Error saving file to Files app: \(error)")
|
||||
// }
|
||||
}
|
||||
// Method to delete the temporary file
|
||||
func deleteTemporaryFile() {
|
||||
let tempFileURL = audioURLFromMP4!
|
||||
do {
|
||||
try FileManager.default.removeItem(at: tempFileURL)
|
||||
print("Temporary file deleted successfully.")
|
||||
} catch {
|
||||
print("Error deleting temporary file: \(error.localizedDescription)")
|
||||
}
|
||||
}
|
||||
func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) {
|
||||
print("Document picker was cancelled")
|
||||
}
|
||||
}
|
||||
// MARK: - Full Screen Handling
|
||||
@@ -350,3 +537,96 @@ extension JWKaraokePlayerVC {
|
||||
print("Item ", item)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//OLD Code
|
||||
//private var audioEngine: AVAudioEngine!
|
||||
// private var audioFile: AVAudioFile!
|
||||
// private var audioPlayerNode: AVAudioPlayerNode!
|
||||
// private var recordedAudioFile: AVAudioFile!
|
||||
//private var recordingURL: URL!
|
||||
//
|
||||
//private func setupAudioEngine() {
|
||||
// audioEngine = AVAudioEngine()
|
||||
// audioPlayerNode = AVAudioPlayerNode()
|
||||
//
|
||||
// audioEngine.attach(audioPlayerNode)
|
||||
// let format = audioEngine.mainMixerNode.outputFormat(forBus: 0)
|
||||
// audioEngine.connect(audioPlayerNode, to: audioEngine.mainMixerNode, format: format)
|
||||
//}
|
||||
//
|
||||
//private func startRecording() {
|
||||
// let format = audioEngine.mainMixerNode.outputFormat(forBus: 0)
|
||||
// let outputFileURL = FileManager.default.temporaryDirectory.appendingPathComponent("savedRecordedAudio.m4a")
|
||||
// recordingURL = outputFileURL
|
||||
//
|
||||
// do {
|
||||
// recordedAudioFile = try AVAudioFile(forWriting: outputFileURL, settings: format.settings)
|
||||
// } catch {
|
||||
// print("Error creating audio file for recording: \(error)")
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// audioEngine.mainMixerNode.installTap(onBus: 0, bufferSize: 1024, format: format) { (buffer, time) in
|
||||
// do {
|
||||
// try self.recordedAudioFile?.write(from: buffer)
|
||||
// } catch {
|
||||
// print("Error writing audio buffer: \(error)")
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// do {
|
||||
// try audioEngine.start()
|
||||
// } catch {
|
||||
// print("Error starting audio engine: \(error)")
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// audioPlayerNode.play()
|
||||
//}
|
||||
//
|
||||
//private func stopRecording() {
|
||||
// audioEngine.mainMixerNode.removeTap(onBus: 0)
|
||||
// audioPlayerNode.stop()
|
||||
// audioEngine.stop()
|
||||
// guard let mixedAudioURL = recordingURL else { return }
|
||||
// playAudio(at: mixedAudioURL)
|
||||
//// presentDocumentPicker()
|
||||
// }
|
||||
//
|
||||
//private func playAudio(at url: URL) {
|
||||
// do {
|
||||
// let audioPlayer = try AVAudioPlayer(contentsOf: url)
|
||||
// audioPlayer.play()
|
||||
// } catch {
|
||||
// print("Error playing audio: \(error)")
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//private func getDocumentsDirectory() -> URL {
|
||||
// return FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
|
||||
//}
|
||||
//
|
||||
//private func presentDocumentPicker() {
|
||||
// guard let mixedAudioURL = recordingURL else { return }
|
||||
// DispatchQueue.main.async {
|
||||
// let documentPicker = UIDocumentPickerViewController(url: mixedAudioURL, in: .exportToService)
|
||||
// documentPicker.delegate = self
|
||||
// self.present(documentPicker, animated: true, completion: nil)
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//private func saveRecordingToFile() {
|
||||
// let fileManager = FileManager.default
|
||||
// let documentsURL = getDocumentsDirectory().appendingPathComponent("savedRecordedAudio.m4a")
|
||||
//
|
||||
// do {
|
||||
// if fileManager.fileExists(atPath: documentsURL.path) {
|
||||
// try fileManager.removeItem(at: documentsURL)
|
||||
// }
|
||||
// try fileManager.moveItem(at: recordingURL, to: documentsURL)
|
||||
// print("Recording saved to: \(documentsURL)")
|
||||
// } catch {
|
||||
// print("Error saving recording: \(error)")
|
||||
// }
|
||||
//}
|
||||
|
||||
@@ -161,9 +161,10 @@ class KaraokeDetailsVC: UIViewController {
|
||||
@IBAction func playNowBtnTapped(_ sender: LocalisedElementsButton) {
|
||||
|
||||
// let sb = UIStoryboard(name: K.StoryBoard.Karaoke, bundle: nil)
|
||||
// let vcPush = sb.instantiateViewController(withIdentifier: "TestingKaraokeVC") as! TestingKaraokeVC
|
||||
// let vcPush = sb.instantiateViewController(withIdentifier: "AVPlayerTesting") as! AVPlayerTesting
|
||||
// self.present(vcPush, animated: true)
|
||||
// return
|
||||
|
||||
var itemBuild = JwPlayerItemCreate(url: "")
|
||||
|
||||
if AuthFunc.shareInstance.getDefaultLanguage() == .english{
|
||||
@@ -181,16 +182,56 @@ class KaraokeDetailsVC: UIViewController {
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
guard let self else{return}
|
||||
Utilities.startProgressHUD()
|
||||
FileManager.default.clearTmpDirectory()
|
||||
let sb = UIStoryboard(name: K.StoryBoard.Karaoke, bundle: nil)
|
||||
let vc = sb.instantiateViewController(withIdentifier: K.StoryBoardID.Karaoke.aVPlayerVC) as! AVPlayerVC
|
||||
vc.videoURL = itemBuild.url
|
||||
vc.titleVideo = itemBuild.titles
|
||||
vc.modalPresentationStyle = .fullScreen
|
||||
self.present(vc, animated: true)
|
||||
let vc = sb.instantiateViewController(withIdentifier: K.StoryBoardID.Karaoke.jwKaraokePlayerVC) as! JWKaraokePlayerVC
|
||||
do {
|
||||
|
||||
// Create a JWPlayerItem
|
||||
let item = try JWPlayerItemBuilder()
|
||||
.file(URL(string: itemBuild.url)!)
|
||||
.posterImage(URL(string: itemBuild.poster ?? "")!)
|
||||
.title(itemBuild.titles ?? "Karaoke")
|
||||
.build()
|
||||
|
||||
// Create a JWPlayerConfiguration
|
||||
let config = try JWPlayerConfigurationBuilder()
|
||||
.playlist(items: [item])
|
||||
.autostart(true)
|
||||
.build()
|
||||
|
||||
vc.config = config
|
||||
vc.videoTitle = itemBuild.titles
|
||||
vc.videoUrl = itemBuild.url
|
||||
|
||||
vc.modalPresentationStyle = .overFullScreen
|
||||
vc.modalTransitionStyle = .crossDissolve
|
||||
// vc.documentAudioUrl = url
|
||||
Utilities.dismissProgressHUD()
|
||||
// Present the PlayerVC
|
||||
self.present(vc, animated: true)
|
||||
} catch {
|
||||
print("Error creating JWPlayer configuration: \(error)")
|
||||
Utilities.dismissProgressHUD()
|
||||
}
|
||||
|
||||
// Dismiss the progress HUD after the view controller presentation
|
||||
Utilities.dismissProgressHUD()
|
||||
|
||||
}
|
||||
// DispatchQueue.main.async { [weak self] in
|
||||
// guard let self else{return}
|
||||
// Utilities.startProgressHUD()
|
||||
// let sb = UIStoryboard(name: K.StoryBoard.Karaoke, bundle: nil)
|
||||
// let vc = sb.instantiateViewController(withIdentifier: K.StoryBoardID.Karaoke.aVPlayerVC) as! AVPlayerVC
|
||||
// vc.videoURL = itemBuild.url
|
||||
// vc.titleVideo = itemBuild.titles
|
||||
// vc.modalPresentationStyle = .fullScreen
|
||||
// self.present(vc, animated: true)
|
||||
// // Dismiss the progress HUD after the view controller presentation
|
||||
// Utilities.dismissProgressHUD()
|
||||
//
|
||||
// }
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -21,6 +21,14 @@
|
||||
</array>
|
||||
</customFonts>
|
||||
<scenes>
|
||||
<!--AV Player View Controller-->
|
||||
<scene sceneID="Oht-rx-zQN">
|
||||
<objects>
|
||||
<avPlayerViewController storyboardIdentifier="AVPlayerTesting" videoGravity="AVLayerVideoGravityResizeAspect" id="NnH-Ku-2UG" customClass="AVPlayerTesting" customModule="WOKA" customModuleProvider="target" sceneMemberID="viewController"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="xvM-Nd-gV7" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="-606" y="-27"/>
|
||||
</scene>
|
||||
<!--Karaoke ListingVC-->
|
||||
<scene sceneID="s0d-6b-0kx">
|
||||
<objects>
|
||||
@@ -602,7 +610,7 @@
|
||||
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" toolTip="Slide" minValue="0.0" maxValue="1" translatesAutoresizingMaskIntoConstraints="NO" id="VKq-Xn-4Nn">
|
||||
<slider toolTip="Slide" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" minValue="0.0" maxValue="1" translatesAutoresizingMaskIntoConstraints="NO" id="VKq-Xn-4Nn">
|
||||
<rect key="frame" x="54" y="0.0" width="296" height="31"/>
|
||||
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<color key="minimumTrackTintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
@@ -825,7 +833,7 @@
|
||||
</button>
|
||||
</subviews>
|
||||
</stackView>
|
||||
<button opaque="NO" contentMode="scaleToFill" enabled="NO" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="tailTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="k45-7s-jnN" customClass="LocalisedElementsButton" customModule="WOKA" customModuleProvider="target">
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="tailTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="k45-7s-jnN" customClass="LocalisedElementsButton" customModule="WOKA" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="65" width="364" height="21"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<fontDescription key="fontDescription" name=".AppleSystemUIFont" family=".AppleSystemUIFont" pointSize="16"/>
|
||||
@@ -892,78 +900,6 @@
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="15" translatesAutoresizingMaskIntoConstraints="NO" id="lIa-J9-DOG">
|
||||
<rect key="frame" x="20" y="606.5" width="374" height="97"/>
|
||||
<subviews>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" spacing="20" translatesAutoresizingMaskIntoConstraints="NO" id="hIr-xj-FN5">
|
||||
<rect key="frame" x="0.0" y="0.0" width="374" height="50"/>
|
||||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" enabled="NO" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="tailTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="yv1-I1-YGZ" customClass="LocalisedElementsButton" customModule="WOKA" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="0.0" width="177" height="50"/>
|
||||
<color key="backgroundColor" red="1" green="0.044904738164268321" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="displayP3"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="50" id="N39-39-T3E"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" name="Exo2-Bold" family="Exo 2" pointSize="14"/>
|
||||
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<inset key="titleEdgeInsets" minX="5" minY="0.0" maxX="0.0" maxY="0.0"/>
|
||||
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="5" maxY="0.0"/>
|
||||
<state key="normal" title="Start Recording" image="Microphone"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
|
||||
<integer key="value" value="25"/>
|
||||
</userDefinedRuntimeAttribute>
|
||||
</userDefinedRuntimeAttributes>
|
||||
<connections>
|
||||
<action selector="playNowBtnTapped:" destination="fax-bi-Mb9" eventType="touchUpInside" id="Ruq-Xc-nQi"/>
|
||||
<action selector="startRecordingBtnTapped:" destination="9gy-Qq-XHU" eventType="touchUpInside" id="SOw-KK-zIp"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="249" enabled="NO" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="tailTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="mHM-7B-XXx" customClass="LocalisedElementsButton" customModule="WOKA" customModuleProvider="target">
|
||||
<rect key="frame" x="197" y="0.0" width="177" height="50"/>
|
||||
<color key="backgroundColor" name="TextDarkBlue"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="50" id="nIb-2q-pnZ"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" name="Exo2-Bold" family="Exo 2" pointSize="16"/>
|
||||
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<inset key="titleEdgeInsets" minX="5" minY="0.0" maxX="0.0" maxY="0.0"/>
|
||||
<inset key="imageEdgeInsets" minX="-10" minY="0.0" maxX="10" maxY="0.0"/>
|
||||
<state key="normal" title="Play" image="PlayButtonSmall"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
|
||||
<integer key="value" value="25"/>
|
||||
</userDefinedRuntimeAttribute>
|
||||
</userDefinedRuntimeAttributes>
|
||||
<connections>
|
||||
<action selector="playBtnTapped:" destination="9gy-Qq-XHU" eventType="touchUpInside" id="tLm-vf-dht"/>
|
||||
<action selector="playNowBtnTapped:" destination="fax-bi-Mb9" eventType="touchUpInside" id="VzV-ZD-BbA"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
</stackView>
|
||||
<button opaque="NO" contentMode="scaleToFill" enabled="NO" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="tailTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="3hw-ks-w1o" customClass="LocalisedElementsButton" customModule="WOKA" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="65" width="374" height="32"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<fontDescription key="fontDescription" name="Exo2-Regular" family="Exo 2" pointSize="16"/>
|
||||
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<inset key="titleEdgeInsets" minX="5" minY="0.0" maxX="0.0" maxY="0.0"/>
|
||||
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="5" maxY="0.0"/>
|
||||
<state key="normal" title="Download Recording">
|
||||
<color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</state>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
|
||||
<integer key="value" value="25"/>
|
||||
</userDefinedRuntimeAttribute>
|
||||
</userDefinedRuntimeAttributes>
|
||||
<connections>
|
||||
<action selector="downloadRecording:" destination="9gy-Qq-XHU" eventType="touchUpInside" id="dRc-xY-3VG"/>
|
||||
<action selector="playNowBtnTapped:" destination="fax-bi-Mb9" eventType="touchUpInside" id="abN-kZ-2DQ"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
</stackView>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Nuf-TE-5LZ">
|
||||
<rect key="frame" x="10" y="63" width="45" height="45"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
@@ -978,23 +914,118 @@
|
||||
<action selector="backBtnTapped:" destination="9gy-Qq-XHU" eventType="touchUpInside" id="oPW-n3-xjb"/>
|
||||
</connections>
|
||||
</button>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="15" translatesAutoresizingMaskIntoConstraints="NO" id="yek-VM-Cus">
|
||||
<rect key="frame" x="20" y="612" width="374" height="86"/>
|
||||
<subviews>
|
||||
<stackView hidden="YES" opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="Oj2-hr-beY">
|
||||
<rect key="frame" x="0.0" y="0.0" width="374" height="10"/>
|
||||
<subviews>
|
||||
<activityIndicatorView hidden="YES" opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" style="medium" translatesAutoresizingMaskIntoConstraints="NO" id="Vsm-wu-cKE">
|
||||
<rect key="frame" x="0.0" y="0.0" width="374" height="0.0"/>
|
||||
<color key="color" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</activityIndicatorView>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Loading Karaoke..." textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="4h3-oT-6Fg">
|
||||
<rect key="frame" x="0.0" y="10" width="374" height="0.0"/>
|
||||
<fontDescription key="fontDescription" name="Exo2-Bold" family="Exo 2" pointSize="15"/>
|
||||
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
</stackView>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="15" translatesAutoresizingMaskIntoConstraints="NO" id="7RJ-zB-bI1">
|
||||
<rect key="frame" x="0.0" y="0.0" width="374" height="86"/>
|
||||
<subviews>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" spacing="20" translatesAutoresizingMaskIntoConstraints="NO" id="fCQ-xT-zM8">
|
||||
<rect key="frame" x="0.0" y="0.0" width="374" height="50"/>
|
||||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="tailTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="vbj-gW-VZl" customClass="LocalisedElementsButton" customModule="WOKA" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="0.0" width="177" height="50"/>
|
||||
<color key="backgroundColor" red="1" green="0.23137254900000001" blue="0.18823529410000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="50" id="ASM-xe-c9a"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" name="Exo2-Bold" family="Exo 2" pointSize="14"/>
|
||||
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<inset key="titleEdgeInsets" minX="5" minY="0.0" maxX="0.0" maxY="0.0"/>
|
||||
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="5" maxY="0.0"/>
|
||||
<state key="normal" title="Start Recording" image="Microphone"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
|
||||
<integer key="value" value="25"/>
|
||||
</userDefinedRuntimeAttribute>
|
||||
</userDefinedRuntimeAttributes>
|
||||
<connections>
|
||||
<action selector="playNowBtnTapped:" destination="fax-bi-Mb9" eventType="touchUpInside" id="ru7-Wv-EJr"/>
|
||||
<action selector="startRecordingBtnTapped:" destination="9gy-Qq-XHU" eventType="touchUpInside" id="2bh-Cr-Joy"/>
|
||||
<action selector="startStopRecording:" destination="kQu-aO-Siv" eventType="touchUpInside" id="7pG-pk-Hk5"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="249" enabled="NO" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="tailTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="4rT-nK-Wb6" customClass="LocalisedElementsButton" customModule="WOKA" customModuleProvider="target">
|
||||
<rect key="frame" x="197" y="0.0" width="177" height="50"/>
|
||||
<color key="backgroundColor" name="TextDarkBlue"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="50" id="zTv-rH-ydT"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" name="Exo2-Bold" family="Exo 2" pointSize="16"/>
|
||||
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<inset key="titleEdgeInsets" minX="5" minY="0.0" maxX="0.0" maxY="0.0"/>
|
||||
<inset key="imageEdgeInsets" minX="-10" minY="0.0" maxX="10" maxY="0.0"/>
|
||||
<state key="normal" title="Play" image="PlayButtonSmall"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
|
||||
<integer key="value" value="25"/>
|
||||
</userDefinedRuntimeAttribute>
|
||||
</userDefinedRuntimeAttributes>
|
||||
<connections>
|
||||
<action selector="playBtnTapped:" destination="9gy-Qq-XHU" eventType="touchUpInside" id="WZm-M9-WLE"/>
|
||||
<action selector="playNowBtnTapped:" destination="fax-bi-Mb9" eventType="touchUpInside" id="NX9-0v-D3v"/>
|
||||
<action selector="playPauseBtn:" destination="kQu-aO-Siv" eventType="touchUpInside" id="bpF-JM-8Dq"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
</stackView>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="tailTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="3Ui-AF-Hlc" customClass="LocalisedElementsButton" customModule="WOKA" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="65" width="374" height="21"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<fontDescription key="fontDescription" name=".AppleSystemUIFont" family=".AppleSystemUIFont" pointSize="16"/>
|
||||
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<inset key="titleEdgeInsets" minX="5" minY="0.0" maxX="0.0" maxY="0.0"/>
|
||||
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="5" maxY="0.0"/>
|
||||
<state key="normal" title="Download Recording" image="icloud.and.arrow.down.fill" catalog="system"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
|
||||
<integer key="value" value="25"/>
|
||||
</userDefinedRuntimeAttribute>
|
||||
</userDefinedRuntimeAttributes>
|
||||
<connections>
|
||||
<action selector="downloadRecording:" destination="9gy-Qq-XHU" eventType="touchUpInside" id="kED-rq-2EY"/>
|
||||
<action selector="playNowBtnTapped:" destination="fax-bi-Mb9" eventType="touchUpInside" id="Smw-Oi-Xnt"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
</stackView>
|
||||
</subviews>
|
||||
</stackView>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="fhs-yV-fEZ"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstItem="lIa-J9-DOG" firstAttribute="centerY" secondItem="fhs-yV-fEZ" secondAttribute="centerY" constant="200" id="2hX-z2-lum"/>
|
||||
<constraint firstAttribute="trailing" secondItem="lIa-J9-DOG" secondAttribute="trailing" constant="20" id="7WR-NN-0zd"/>
|
||||
<constraint firstItem="yek-VM-Cus" firstAttribute="centerY" secondItem="fhs-yV-fEZ" secondAttribute="centerY" constant="200" id="0CQ-IK-CSM"/>
|
||||
<constraint firstItem="yek-VM-Cus" firstAttribute="leading" secondItem="fhs-yV-fEZ" secondAttribute="leading" constant="20" id="0qJ-R4-ZTb"/>
|
||||
<constraint firstItem="Nuf-TE-5LZ" firstAttribute="top" secondItem="fhs-yV-fEZ" secondAttribute="top" constant="15" id="7jB-UT-Xqq"/>
|
||||
<constraint firstItem="fhs-yV-fEZ" firstAttribute="trailing" secondItem="yek-VM-Cus" secondAttribute="trailing" constant="20" id="Omt-Ig-58p"/>
|
||||
<constraint firstItem="Nuf-TE-5LZ" firstAttribute="leading" secondItem="fhs-yV-fEZ" secondAttribute="leading" constant="10" id="Tcl-yf-D2V"/>
|
||||
<constraint firstItem="lIa-J9-DOG" firstAttribute="leading" secondItem="fhs-yV-fEZ" secondAttribute="leading" constant="20" id="yH2-iw-QCt"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="backButton" destination="Nuf-TE-5LZ" id="syG-po-xEv"/>
|
||||
<outlet property="downloadRecordingBtn" destination="3hw-ks-w1o" id="bWR-kY-K1G"/>
|
||||
<outlet property="outerStack" destination="lIa-J9-DOG" id="uBJ-C7-rCI"/>
|
||||
<outlet property="playBtn" destination="mHM-7B-XXx" id="qso-dg-U5b"/>
|
||||
<outlet property="startRecordBtn" destination="yv1-I1-YGZ" id="Xf6-hb-4Qd"/>
|
||||
<outlet property="downloadRecordingBtn" destination="3Ui-AF-Hlc" id="9TA-QY-4xw"/>
|
||||
<outlet property="karaokeLoading" destination="Vsm-wu-cKE" id="GBV-UM-lT7"/>
|
||||
<outlet property="karaokeStack" destination="Oj2-hr-beY" id="apD-yP-Yfh"/>
|
||||
<outlet property="outerStack" destination="yek-VM-Cus" id="nRc-sO-HjJ"/>
|
||||
<outlet property="playBtn" destination="4rT-nK-Wb6" id="XLE-Da-4YA"/>
|
||||
<outlet property="startRecordBtn" destination="vbj-gW-VZl" id="QV4-c3-Fub"/>
|
||||
<outlet property="startStopRecordingStack" destination="7RJ-zB-bI1" id="LeT-d7-eoh"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="s0j-fC-RFe" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
|
||||
|
||||
Reference in New Issue
Block a user