diff --git a/WOKA/Assets/Assets.xcassets/Karaoke/KaraokePause.imageset/Contents.json b/WOKA/Assets/Assets.xcassets/Karaoke/KaraokePause.imageset/Contents.json new file mode 100644 index 0000000..15b72ef --- /dev/null +++ b/WOKA/Assets/Assets.xcassets/Karaoke/KaraokePause.imageset/Contents.json @@ -0,0 +1,26 @@ +{ + "images" : [ + { + "filename" : "Pause.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Pause@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Pause@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "template" + } +} diff --git a/WOKA/Assets/Assets.xcassets/Karaoke/KaraokePause.imageset/pause.png b/WOKA/Assets/Assets.xcassets/Karaoke/KaraokePause.imageset/pause.png new file mode 100644 index 0000000..f5ced19 Binary files /dev/null and b/WOKA/Assets/Assets.xcassets/Karaoke/KaraokePause.imageset/pause.png differ diff --git a/WOKA/Assets/Assets.xcassets/Karaoke/KaraokePause.imageset/pause@2x.png b/WOKA/Assets/Assets.xcassets/Karaoke/KaraokePause.imageset/pause@2x.png new file mode 100644 index 0000000..25da482 Binary files /dev/null and b/WOKA/Assets/Assets.xcassets/Karaoke/KaraokePause.imageset/pause@2x.png differ diff --git a/WOKA/Assets/Assets.xcassets/Karaoke/KaraokePause.imageset/pause@3x.png b/WOKA/Assets/Assets.xcassets/Karaoke/KaraokePause.imageset/pause@3x.png new file mode 100644 index 0000000..7b1e72e Binary files /dev/null and b/WOKA/Assets/Assets.xcassets/Karaoke/KaraokePause.imageset/pause@3x.png differ diff --git a/WOKA/Audio Books/AudioBookDetailsVC.swift b/WOKA/Audio Books/AudioBookDetailsVC.swift index 7e68046..4a218e4 100644 --- a/WOKA/Audio Books/AudioBookDetailsVC.swift +++ b/WOKA/Audio Books/AudioBookDetailsVC.swift @@ -31,7 +31,7 @@ class AudioBookDetailsVC : UIViewController{ var audioData : ListenAudioListingDM.AudioDatum? - var continueAudioData : ContinueAudioListDM.ResultData? + var continueAudioData : ListenAudioListingDM.AudioDatum? override func viewDidLoad() { super.viewDidLoad() diff --git a/WOKA/Audio Books/AudioBookHomeVC.swift b/WOKA/Audio Books/AudioBookHomeVC.swift index f8cf55c..2b86148 100644 --- a/WOKA/Audio Books/AudioBookHomeVC.swift +++ b/WOKA/Audio Books/AudioBookHomeVC.swift @@ -73,7 +73,7 @@ class AudioBookHomeVC: UIViewController { } @IBAction func listenAudioBtnTapped(_ sender: LocalisedElementsButton) { - let data = vm.audioListData[vm.indexToLoad] + guard let data = vm.headerData else{return} var playerItems = [JwPlayerItemCreate]() if AuthFunc.shareInstance.getDefaultLanguage() == .english{ if let englishData = data.contentMoreDetails?.filter({$0.languageMasterID == 1}).first, let url = englishData.url{ @@ -148,13 +148,13 @@ extension AudioBookHomeVC : TableViewSRC{ } func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + let data = vm.audioListData[indexPath.row] + /* Updated the top header data */ - vm.indexToLoad = indexPath.row - vm.setInitialData() - - let data = vm.audioListData[indexPath.row] + vm.headerData = data + vm.setHeaderData() let sb = UIStoryboard(name: K.StoryBoard.audioBooks, bundle: nil) let vcPush = sb.instantiateViewController(withIdentifier: K.StoryBoardID.AudioBooks.audioBookDetailsVC) as! AudioBookDetailsVC @@ -187,11 +187,8 @@ extension AudioBookHomeVC : CollectionViewSRC{ func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { let data = vm.continueWatchingData[indexPath.row] - - if let audioListIndex = vm.audioListData.firstIndex(where:{$0.id == data.id}){ - vm.indexToLoad = audioListIndex - vm.setInitialData() - } + vm.headerData = data + vm.setHeaderData() let sb = UIStoryboard(name: K.StoryBoard.audioBooks, bundle: nil) let vcPush = sb.instantiateViewController(withIdentifier: K.StoryBoardID.AudioBooks.audioBookDetailsVC) as! AudioBookDetailsVC diff --git a/WOKA/Audio Books/AudioBookHomeVM.swift b/WOKA/Audio Books/AudioBookHomeVM.swift index 7bce370..9868463 100644 --- a/WOKA/Audio Books/AudioBookHomeVM.swift +++ b/WOKA/Audio Books/AudioBookHomeVM.swift @@ -11,9 +11,12 @@ import Alamofire class AudioBookHomeVM{ weak var vc : AudioBookHomeVC! - var continueWatchingData = [ContinueAudioListDM.ResultData]() + var continueWatchingData = [ListenAudioListingDM.AudioDatum]() var audioListData = [ListenAudioListingDM.AudioDatum]() - var indexToLoad = 0 + + var headerData : ListenAudioListingDM.AudioDatum? + +// var indexToLoad = 0 var pageNo = 0 func initView(){ @@ -34,21 +37,21 @@ class AudioBookHomeVM{ self.vc.tableHeight.constant = self.vc.audioListingTableView.contentSize.height } - func setInitialData(){ + func setHeaderData(){ // if indexToLoad > continueWatchingData.count { // return // } - let data = audioListData[indexToLoad] + guard let headerData else{return} - if let url = data.thumbnailPath{ + if let url = headerData.thumbnailPath{ self.vc.headerImage.imageURL(url, color: .white) } if AuthFunc.shareInstance.getDefaultLanguage() == .english{ - let englishData = data.contentMoreDetails?.filter({$0.languageMasterID == 1}).first + let englishData = headerData.contentMoreDetails?.filter({$0.languageMasterID == 1}).first vc.headerTitleLabel.text = englishData?.title }else{ - let hindiData = data.contentMoreDetails?.filter({$0.languageMasterID == 2}).first + let hindiData = headerData.contentMoreDetails?.filter({$0.languageMasterID == 2}).first vc.headerTitleLabel.text = hindiData?.title } } @@ -109,7 +112,7 @@ class AudioBookHomeVM{ } } - func getShowListing(){ + func getShowListing(isBtnClick : Bool = false){ // Utilities.startProgressHUD() let headers : HTTPHeaders = ["access-token" : AuthFunc.shareInstance.getAccessToken()] let params : Parameters = ["api_version" : "v2", @@ -137,8 +140,10 @@ class AudioBookHomeVM{ self.vc.tableHeight.constant = self.vc.audioListingTableView.contentSize.height + 100 self.vc.audioListingTableView.layoutIfNeeded() self.vc.tableHeight.constant = self.vc.audioListingTableView.contentSize.height - self.indexToLoad = 0 - self.setInitialData() + if !isBtnClick{ + self.headerData = self.audioListData.first + self.setHeaderData() + } self.stopShimmer() self.vc.loadMoreActivityIndicator.stopAnimating() diff --git a/WOKA/Audio Books/ContinueAudioCell.swift b/WOKA/Audio Books/ContinueAudioCell.swift index 8b266f3..8d04d28 100644 --- a/WOKA/Audio Books/ContinueAudioCell.swift +++ b/WOKA/Audio Books/ContinueAudioCell.swift @@ -32,7 +32,7 @@ class ContinueAudioCell: UICollectionViewCell { shimmerView.stopShimmer() } - func setAudioData(data: ContinueAudioListDM.ResultData){ + func setAudioData(data: ListenAudioListingDM.AudioDatum){ //heart.fill , heart , hand.thumbsup.fill , hand.thumbsup if AuthFunc.shareInstance.getDefaultLanguage() == .english{ audioBookTitle.text = data.contentMoreDetails?.filter({$0.languageMasterID == 1}).first?.title diff --git a/WOKA/Audio Books/ContinueAudioListDM.swift b/WOKA/Audio Books/ContinueAudioListDM.swift index e2e38f3..0839cf9 100644 --- a/WOKA/Audio Books/ContinueAudioListDM.swift +++ b/WOKA/Audio Books/ContinueAudioListDM.swift @@ -9,7 +9,7 @@ import Foundation // MARK: - ContinueAudioListDM struct ContinueAudioListDM: Codable { - let result: [ResultData]? + let result: [ListenAudioListingDM.AudioDatum]? let totalRecords: Int? enum CodingKeys: String, CodingKey { diff --git a/WOKA/Audio Books/ListenAudioListingDM.swift b/WOKA/Audio Books/ListenAudioListingDM.swift index b962ab6..8051fed 100644 --- a/WOKA/Audio Books/ListenAudioListingDM.swift +++ b/WOKA/Audio Books/ListenAudioListingDM.swift @@ -28,7 +28,7 @@ struct ListenAudioListingDM: Codable { let languageMasterID: Int? let genderMasterID, audioDuration, mediaID: String? let contentMoreDetails: [ContentMoreDetail]? -// let userVideoView: [JSONAny]? + let userVideoView: [UserVideoView]? let categoryData: [CategoryDatum]? // let ageRangeData, genderData: [JSONAny]? var markAsFavourite, isLiked: Bool? @@ -47,7 +47,7 @@ struct ListenAudioListingDM: Codable { case audioDuration = "audio_duration" case mediaID = "media_id" case contentMoreDetails = "content_more_details" -// case userVideoView = "user_video_view" + case userVideoView = "user_video_view" // case ageRangeData = "age_range_data" // case genderData = "gender_data" case categoryData = "category_data" @@ -59,6 +59,23 @@ struct ListenAudioListingDM: Codable { } } + // MARK: - UserVideoView + struct UserVideoView: Codable { + let id, userID, postID, postType: Int? + let totalWatchedDuration, lastWatchedLeft: String? + let categoryID: Int? + + enum CodingKeys: String, CodingKey { + case id + case userID = "user_id" + case postID = "post_id" + case postType = "post_type" + case totalWatchedDuration = "total_watched_duration" + case lastWatchedLeft = "last_watched_left" + case categoryID = "category_id" + } + } + // MARK: - CategoryDatum struct CategoryDatum: Codable { let id: Int? @@ -90,58 +107,4 @@ struct ListenAudioListingDM: Codable { case tagsKeywords = "tags_keywords" } } - } - -// -//{ -// "id": 6, -// "title": "DADAGIRI KI AISI KI TAISE", -// "description": "

Kalu and Chitta are the two big bullies of the school who don't stop at troubling anyone. They steal someone's food and bully someone. ADI and his friends can't take it all. They go to seek help from the wise sage, Piku Baba. What clever method did Piku Baba tell Kalu and Chitta to teach them a lesson? Has Kalu and Chitta's bullying come to an end? Can ADI and his crew stop them? Listen to this funny story to find out.

", -// "thumbnail_path": "https://wokaland.com/admin/storage/app/public/uploads/Listen/64b2bdf9d277d.png?d=1719904091", -// "audio_url": "https://content.jwplatform.com/videos/tUJ8m9W0-Ysj2G4DQ.mp4", -// "category_master_id": "11", -// "age_range_master_id": "0", -// "tags_keyword": "0", -// "release_date": "2023-07-15 00:00:00", -// "language_master_id": 1, -// "gender_master_id": "0", -// "audio_duration": "00:07:25", -// "media_id": "", -// "content_more_details": [ -// { -// "id": 831, -// "content_id": 6, -// "post_type": 7, -// "language_master_id": 1, -// "title": "DADAGIRI KI AISI KI TAISE", -// "description": "

Kalu and Chitta are the two big bullies of the school who don't stop at troubling anyone. They steal someone's food and bully someone. ADI and his friends can't take it all. They go to seek help from the wise sage, Piku Baba. What clever method did Piku Baba tell Kalu and Chitta to teach them a lesson? Has Kalu and Chitta's bullying come to an end? Can ADI and his crew stop them? Listen to this funny story to find out.

", -// "url": "https://content.jwplatform.com/videos/tUJ8m9W0-Ysj2G4DQ.mp4", -// "tags_keywords": "0" -// }, -// { -// "id": 832, -// "content_id": 6, -// "post_type": 7, -// "language_master_id": 2, -// "title": "दादागिरी की ऐसी की तैसी", -// "description": "

कालू और चिट्टा स्कूल के दो बड़े बदमाश हैं जो किसी को भी सताने से बाज़ नहीं आते। किसी का वे खाना चुरा लेते हैं और किसी के ऊपर दादागिरी जमाते रहते हैं। आदि और उसके दोस्त यह सब सहन नहीं कर पा रहे हैं। वे ज्ञानी साधु, पीकू बाबा से मदद माँगने जाते हैं। कालू और चिट्ठा को सबक सिखानेके लिए। पीकू बाबा ने उन्हें कौन सा खुफिया तरीका बताया? क्या कालू और चिट्टा की दादागिरी ख़त्म हुई? क्या आदि और उसका दल उन्हें रोक पाते हैं? पता लगाने के लिए यह मज़ेदार कहानी सुनो।

", -// "url": "https://content.jwplatform.com/videos/tUJ8m9W0-Ysj2G4DQ.mp4", -// "tags_keywords": "0" -// } -// ], -// "user_video_view": [], -// "category_data": [ -// { -// "id": 11, -// "category_name": "Audio" -// } -// ], -// "age_range_data": [], -// "gender_data": [], -// "mark_as_favourite": false, -// "is_liked": false, -// "views_count": 4763, -// "likes_count": 20, -// "bookmark_count": 15 -// } diff --git a/WOKA/Games/Controller/GamesListVC.swift b/WOKA/Games/Controller/GamesListVC.swift index d4e0ea7..fb3c70c 100644 --- a/WOKA/Games/Controller/GamesListVC.swift +++ b/WOKA/Games/Controller/GamesListVC.swift @@ -18,6 +18,9 @@ class GamesListVC: UIViewController { @IBOutlet weak var headerTitleLabel: UILabel! @IBOutlet weak var gamesLoadingView: ShimmerEffectView! + @IBOutlet weak var loadMoreBtn: LocalisedElementsButton! + @IBOutlet weak var loadMoreActivityIndicator: UIActivityIndicatorView! + var vm = GamesListVM() override func viewDidLoad() { @@ -51,6 +54,8 @@ class GamesListVC: UIViewController { vm.updateTableHeight() } + // MARK: - Tap Handler + @IBAction func gameBtnTapped(_ sender: LocalisedElementsButton) { let sb = UIStoryboard(name: K.StoryBoard.Games, bundle: nil) let vcPush = sb.instantiateViewController(withIdentifier: K.StoryBoardID.Games.gamesWebViewVC) as! GamesWebViewVC @@ -62,6 +67,13 @@ class GamesListVC: UIViewController { vcPush.modalPresentationStyle = .fullScreen self.present(vcPush, animated: true) } + + @IBAction func loadMoreBtnTapped(_ sender: LocalisedElementsButton) { + loadMoreBtn.isHidden = true + vm.pageNo += 1 + loadMoreActivityIndicator.startAnimating() + vm.getGamesListing(isBtnClick: true) + } } // MARK: - TableView DataSource , Delegates diff --git a/WOKA/Games/Games.storyboard b/WOKA/Games/Games.storyboard index 6da1737..f173a03 100644 --- a/WOKA/Games/Games.storyboard +++ b/WOKA/Games/Games.storyboard @@ -99,7 +99,7 @@ - + @@ -154,6 +196,8 @@ + + diff --git a/WOKA/Games/ViewModel/GamesListVM.swift b/WOKA/Games/ViewModel/GamesListVM.swift index 7c891a2..78519e1 100644 --- a/WOKA/Games/ViewModel/GamesListVM.swift +++ b/WOKA/Games/ViewModel/GamesListVM.swift @@ -14,6 +14,9 @@ class GamesListVM{ var gameData = [GamesListDM.GameDatum]() var indexToLoad = 0 + var pageNo = 0 + var stopFetch = false + func initView(){ setupCell() let color1 = #colorLiteral(red: 0.8, green: 0.6078431373, blue: 0.1098039216, alpha: 1) @@ -63,9 +66,13 @@ class GamesListVM{ // MARK: - Get Games Data - func getGamesListing(){ + func getGamesListing(isBtnClick : Bool = false){ let headers : HTTPHeaders = ["access-token" : AuthFunc.shareInstance.getAccessToken()] - NetworkManager.shareInstance.apiRequest(url: APIEndPoints.Games.game_listing, method: .post,headers: headers) { [weak self](result : Result, NetworkManager.APIError>) in + let params : Parameters = ["api_version" : "v2", + "start" : pageNo, + "limit": 5] + + NetworkManager.shareInstance.apiRequest(url: APIEndPoints.Games.game_listing, method: .post,parameters: params,headers: headers) { [weak self](result : Result, NetworkManager.APIError>) in switch result{ case .success(let data): guard let self else{ @@ -78,18 +85,34 @@ class GamesListVM{ Error */ Utilities.dismissProgressHUD() - vc.toast(msg: data.message ?? "Unrecognised error" , time: 2) + self.vc.loadMoreActivityIndicator.stopAnimating() + self.vc.loadMoreActivityIndicator.hidesWhenStopped = true +// vc.toast(msg: data.message ?? "Unrecognised error" , time: 2) case 1: Utilities.dismissProgressHUD() guard let data = data.data?.gameData else{return} - self.gameData.removeAll() - self.gameData = data + self.gameData.append(contentsOf: data) self.vc.gamesListingTableView.reloadData() self.vc.tableHeight.constant = self.vc.gamesListingTableView.contentSize.height + 100 self.vc.gamesListingTableView.layoutIfNeeded() self.vc.tableHeight.constant = self.vc.gamesListingTableView.contentSize.height - self.setHeaderData() + + if !isBtnClick{ + setHeaderData() + } + self.stopShimmer() + + self.vc.loadMoreActivityIndicator.stopAnimating() + self.vc.loadMoreActivityIndicator.hidesWhenStopped = true + + if self.gameData.count.isMultiple(of: 5) && !self.stopFetch{ + // if not multiple of 10, means more data can be there, show more btn + self.vc.loadMoreBtn.isHidden = false + }else{ + self.stopFetch = true + self.vc.loadMoreBtn.isHidden = true + } default: break } diff --git a/WOKA/Karaoke/Controller/JWKaraokePlayerVC.swift b/WOKA/Karaoke/Controller/JWKaraokePlayerVC.swift index 6fddab7..13b2e2e 100644 --- a/WOKA/Karaoke/Controller/JWKaraokePlayerVC.swift +++ b/WOKA/Karaoke/Controller/JWKaraokePlayerVC.swift @@ -46,7 +46,6 @@ class JWKaraokePlayerVC: JWPlayerViewController, JWPlayerViewControllerDelegate //Disable Picture in Picture playerView.allowsPictureInPicturePlayback = false playerView.captionStyle = .none - self.view.bringSubviewToFront(outerStack) self.view.bringSubviewToFront(backButton) setupKaraoke() @@ -96,7 +95,6 @@ class JWKaraokePlayerVC: JWPlayerViewController, JWPlayerViewControllerDelegate self.interfaceBehavior = .hidden guard let audioRecorder = audioRecorder else { return } audioRecorder.record() - } func stopRecording() { @@ -146,11 +144,11 @@ class JWKaraokePlayerVC: JWPlayerViewController, JWPlayerViewControllerDelegate // Export the mixed audio let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! - let filePath = documentsDirectory.appendingPathComponent("mixedAudio.m4a") + let fileName = "\((self.videoTitle?.replacingOccurrences(of: " ", with: "").replacingOccurrences(of: ".", with: "") ?? "Audio") + Date().timeIntervalSince1970.toString()).m4a" + let filePath = documentsDirectory.appendingPathComponent(fileName) deleteFileIfExist(at: filePath) mixedAudioURL = filePath -// mixedAudioURL = documentsDirectory.appendingPathComponent("mixedAudio.m4a") guard let exportSession = AVAssetExportSession(asset: composition, presetName: AVAssetExportPresetAppleM4A) else { return } exportSession.outputURL = mixedAudioURL @@ -162,6 +160,7 @@ class JWKaraokePlayerVC: JWPlayerViewController, JWPlayerViewControllerDelegate Utilities.dismissProgressHUD() DispatchQueue.main.async { self.playBtn.isEnabled = true + self.downloadRecordingBtn.isEnabled = true } @@ -304,12 +303,21 @@ class JWKaraokePlayerVC: JWPlayerViewController, JWPlayerViewControllerDelegate @IBAction func playBtnTapped(_ sender: LocalisedElementsButton) { if !isPlaying { playMixedAudio() - self.interfaceBehavior = .normal - self.interfaceBehavior = .hidden sender.setTitle("Pause", for: .normal) + sender.setImage(UIImage(named: "KaraokePause"), for: .normal) + + // Disable Recording while playing, hide controls for jwplayer + self.interfaceBehavior = .hidden + self.startRecordBtn.isEnabled = false + self.downloadRecordingBtn.isEnabled = false } else { - self.interfaceBehavior = .normal sender.setTitle("Play", for: .normal) + sender.setImage(UIImage(named: "PlayButtonSmall"), for: .normal) + + // Disable Recording while playing, hide controls for jwplayer + self.interfaceBehavior = .normal + self.startRecordBtn.isEnabled = true + self.downloadRecordingBtn.isEnabled = true } isPlaying.toggle() @@ -317,36 +325,55 @@ class JWKaraokePlayerVC: JWPlayerViewController, JWPlayerViewControllerDelegate self.player.pause() print("Play") } + func playMixedAudio() { guard let mixedAudioURL = mixedAudioURL else { return } - - do { - - let documentsDirectoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! + 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)} - + // Check if file already exists + if FileManager.default.fileExists(atPath: destinationURL.path) { + // Delete the existing file + try FileManager.default.removeItem(at: destinationURL) + } + + // Copy the new file + try FileManager.default.copyItem(at: mixedAudioURL, to: destinationURL) + + // Play the audio let playerKAraoke = AVPlayer(url: destinationURL) + + // Adding a completion handler to check if the player starts playing + let playerObserver = playerKAraoke.addPeriodicTimeObserver(forInterval: CMTime(seconds: 1, preferredTimescale: 1), queue: .main) { time in + print("Playing audio at time: \(time.seconds)") + } + + // Observing when playback finishes + NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: playerKAraoke.currentItem, queue: .main) { _ in + print("Audio finished playing") + // Remove observer + playerKAraoke.removeTimeObserver(playerObserver) + } + playerKAraoke.volume = 1.0 playerKAraoke.play() + print("Audio is playing...") + // Uncomment this block if you need to configure the audio session and play using AVAudioPlayer + /* + // 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() + */ -// // 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)") + print("Error: \(error.localizedDescription)") } } diff --git a/WOKA/Karaoke/Karaoke.storyboard b/WOKA/Karaoke/Karaoke.storyboard index dd80233..d6a16ba 100644 --- a/WOKA/Karaoke/Karaoke.storyboard +++ b/WOKA/Karaoke/Karaoke.storyboard @@ -833,7 +833,7 @@ - + + + + + + + + + + + + @@ -244,6 +286,8 @@ + +