diff --git a/WOKA.xcodeproj/project.pbxproj b/WOKA.xcodeproj/project.pbxproj index 4665eb2..70c0306 100644 --- a/WOKA.xcodeproj/project.pbxproj +++ b/WOKA.xcodeproj/project.pbxproj @@ -183,6 +183,9 @@ 9C0A85432BEE3EC90093783D /* NewPasswordVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C0A85422BEE3EC90093783D /* NewPasswordVM.swift */; }; 9C1C69FA2C106B290035B2C7 /* RSKPlaceholderTextView in Frameworks */ = {isa = PBXBuildFile; productRef = 9C1C69F92C106B290035B2C7 /* RSKPlaceholderTextView */; }; 9C1C69FC2C106C240035B2C7 /* ContactSupportVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C1C69FB2C106C240035B2C7 /* ContactSupportVM.swift */; }; + 9C21F81C2C37E1FA0050BFCC /* KaraokeContinueWatchingDM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C21F81B2C37E1FA0050BFCC /* KaraokeContinueWatchingDM.swift */; }; + 9C21F81E2C37E3CA0050BFCC /* AVPlayerVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C21F81D2C37E3CA0050BFCC /* AVPlayerVC.swift */; }; + 9C21F8222C382A580050BFCC /* AVPlayerVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C21F8212C382A580050BFCC /* AVPlayerVM.swift */; }; 9C27E1602BDB6ECA00EC1DA9 /* UserDefaultsStruct.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C27E15F2BDB6ECA00EC1DA9 /* UserDefaultsStruct.swift */; }; 9C27E1632BDB6F1900EC1DA9 /* AuthFunc.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C27E1622BDB6F1900EC1DA9 /* AuthFunc.swift */; }; 9C27E1652BDB6FBC00EC1DA9 /* StoryBoardID.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C27E1642BDB6FBC00EC1DA9 /* StoryBoardID.swift */; }; @@ -232,6 +235,11 @@ 9C9BEEC72BEE1BBF004ECC2F /* CollectionViewCenteredFlowLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C9BEEC62BEE1BBF004ECC2F /* CollectionViewCenteredFlowLayout.swift */; }; 9CA7C6C02C1093E500D73742 /* ProfileVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CA7C6BF2C1093E500D73742 /* ProfileVC.swift */; }; 9CA7C6C22C1095B600D73742 /* ProfileVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CA7C6C12C1095B600D73742 /* ProfileVM.swift */; }; + 9CB3D0852C37BA530062869D /* Karaoke.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9CB3D0842C37BA530062869D /* Karaoke.storyboard */; }; + 9CB3D08B2C37BBA50062869D /* KaraokeListingVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CB3D08A2C37BBA50062869D /* KaraokeListingVC.swift */; }; + 9CB3D08D2C37CDD60062869D /* KaraokeListingVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CB3D08C2C37CDD50062869D /* KaraokeListingVM.swift */; }; + 9CB3D08F2C37D0D60062869D /* KaraokeListingDM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CB3D08E2C37D0D60062869D /* KaraokeListingDM.swift */; }; + 9CB3D0912C37D6930062869D /* KaraokeDetailsVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CB3D0902C37D6930062869D /* KaraokeDetailsVC.swift */; }; 9CB4C5A92C118EF300737C00 /* NavBarColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CB4C5A82C118EF300737C00 /* NavBarColor.swift */; }; 9CBCB29B2BE4D614007D7934 /* LoginVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CBCB29A2BE4D614007D7934 /* LoginVC.swift */; }; 9CBCB29D2BE4D6BB007D7934 /* LoginVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CBCB29C2BE4D6BB007D7934 /* LoginVM.swift */; }; @@ -455,6 +463,9 @@ 9C0A85402BEE35670093783D /* ResetPassUserNameVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetPassUserNameVM.swift; sourceTree = ""; }; 9C0A85422BEE3EC90093783D /* NewPasswordVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewPasswordVM.swift; sourceTree = ""; }; 9C1C69FB2C106C240035B2C7 /* ContactSupportVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactSupportVM.swift; sourceTree = ""; }; + 9C21F81B2C37E1FA0050BFCC /* KaraokeContinueWatchingDM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KaraokeContinueWatchingDM.swift; sourceTree = ""; }; + 9C21F81D2C37E3CA0050BFCC /* AVPlayerVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AVPlayerVC.swift; sourceTree = ""; }; + 9C21F8212C382A580050BFCC /* AVPlayerVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AVPlayerVM.swift; sourceTree = ""; }; 9C27E15F2BDB6ECA00EC1DA9 /* UserDefaultsStruct.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDefaultsStruct.swift; sourceTree = ""; }; 9C27E1622BDB6F1900EC1DA9 /* AuthFunc.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthFunc.swift; sourceTree = ""; }; 9C27E1642BDB6FBC00EC1DA9 /* StoryBoardID.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoryBoardID.swift; sourceTree = ""; }; @@ -493,6 +504,11 @@ 9C9BEEC62BEE1BBF004ECC2F /* CollectionViewCenteredFlowLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CollectionViewCenteredFlowLayout.swift; sourceTree = ""; }; 9CA7C6BF2C1093E500D73742 /* ProfileVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileVC.swift; sourceTree = ""; }; 9CA7C6C12C1095B600D73742 /* ProfileVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileVM.swift; sourceTree = ""; }; + 9CB3D0842C37BA530062869D /* Karaoke.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Karaoke.storyboard; sourceTree = ""; }; + 9CB3D08A2C37BBA50062869D /* KaraokeListingVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KaraokeListingVC.swift; sourceTree = ""; }; + 9CB3D08C2C37CDD50062869D /* KaraokeListingVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KaraokeListingVM.swift; sourceTree = ""; }; + 9CB3D08E2C37D0D60062869D /* KaraokeListingDM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KaraokeListingDM.swift; sourceTree = ""; }; + 9CB3D0902C37D6930062869D /* KaraokeDetailsVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KaraokeDetailsVC.swift; sourceTree = ""; }; 9CB4C5A82C118EF300737C00 /* NavBarColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavBarColor.swift; sourceTree = ""; }; 9CBCB29A2BE4D614007D7934 /* LoginVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginVC.swift; sourceTree = ""; }; 9CBCB29C2BE4D6BB007D7934 /* LoginVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginVM.swift; sourceTree = ""; }; @@ -658,6 +674,7 @@ 523ED25C2BDA2BC700CFED02 /* WOKA */ = { isa = PBXGroup; children = ( + 9CB3D0832C37BA470062869D /* Karaoke */, 526A436D2C36A96A00AE148F /* Games */, 52BFB52B2C33DA9700BAAE15 /* Audio Books */, 52DAC6462C21761700E2F85B /* WebSeries */, @@ -1347,6 +1364,53 @@ path = HTML; sourceTree = ""; }; + 9CB3D0832C37BA470062869D /* Karaoke */ = { + isa = PBXGroup; + children = ( + 9CB3D0892C37BA650062869D /* Model */, + 9CB3D0882C37BA630062869D /* View */, + 9CB3D0872C37BA610062869D /* ViewModel */, + 9CB3D0862C37BA5F0062869D /* Controller */, + 9CB3D0842C37BA530062869D /* Karaoke.storyboard */, + ); + path = Karaoke; + sourceTree = ""; + }; + 9CB3D0862C37BA5F0062869D /* Controller */ = { + isa = PBXGroup; + children = ( + 9CB3D08A2C37BBA50062869D /* KaraokeListingVC.swift */, + 9CB3D0902C37D6930062869D /* KaraokeDetailsVC.swift */, + 9C21F81D2C37E3CA0050BFCC /* AVPlayerVC.swift */, + ); + path = Controller; + sourceTree = ""; + }; + 9CB3D0872C37BA610062869D /* ViewModel */ = { + isa = PBXGroup; + children = ( + 9CB3D08C2C37CDD50062869D /* KaraokeListingVM.swift */, + 9C21F8212C382A580050BFCC /* AVPlayerVM.swift */, + ); + path = ViewModel; + sourceTree = ""; + }; + 9CB3D0882C37BA630062869D /* View */ = { + isa = PBXGroup; + children = ( + ); + path = View; + sourceTree = ""; + }; + 9CB3D0892C37BA650062869D /* Model */ = { + isa = PBXGroup; + children = ( + 9CB3D08E2C37D0D60062869D /* KaraokeListingDM.swift */, + 9C21F81B2C37E1FA0050BFCC /* KaraokeContinueWatchingDM.swift */, + ); + path = Model; + sourceTree = ""; + }; 9CBCB2A62BE5104F007D7934 /* Home */ = { isa = PBXGroup; children = ( @@ -1557,6 +1621,7 @@ 9C834ED62C1C1F9200B29A9C /* Exo2-ExtraBold.ttf in Resources */, 9C834ED72C1C1F9200B29A9C /* Exo2-Regular.ttf in Resources */, 9C834ED82C1C1F9200B29A9C /* Exo2-Thin.ttf in Resources */, + 9CB3D0852C37BA530062869D /* Karaoke.storyboard in Resources */, 52C6E0262BE3B46A00E22D59 /* SelectAvatarCell.xib in Resources */, 52C8B0712BDA7512003B51D0 /* PassingCloud.json in Resources */, 9C8C4FB02C1328060017DD3B /* Disclaimer.rtf in Resources */, @@ -1693,6 +1758,7 @@ 52D2F3D82C24043D009E52FF /* ShimmerEffectView.swift in Sources */, 9C27E16F2BDB866500EC1DA9 /* CellIdentifier.swift in Sources */, 52BC3BF22C170264002FACA6 /* MoreVM.swift in Sources */, + 9CB3D08F2C37D0D60062869D /* KaraokeListingDM.swift in Sources */, 9CBE1B412C0F37B300CA6E61 /* DPDUIView+Extension.swift in Sources */, 9C27E1632BDB6F1900EC1DA9 /* AuthFunc.swift in Sources */, 9C0A85412BEE35670093783D /* ResetPassUserNameVM.swift in Sources */, @@ -1704,6 +1770,7 @@ 52B8D4D92C04A25E00ED65F3 /* UIViewController+Container.swift in Sources */, 9C834EDC2C1C26CD00B29A9C /* HtmlText.swift in Sources */, 527AC6F72C171C8F00434FB7 /* BlogsCell.swift in Sources */, + 9C21F81C2C37E1FA0050BFCC /* KaraokeContinueWatchingDM.swift in Sources */, 523ED25E2BDA2BC700CFED02 /* AppDelegate.swift in Sources */, 9C7939132C0EFCAE00F5D6E6 /* FaqVM.swift in Sources */, 52D774ED2BDFC13F001D87DE /* OTPVM.swift in Sources */, @@ -1766,6 +1833,7 @@ 9CBCB2A12BE4E50A007D7934 /* TextFieldPassword.swift in Sources */, 52BC3BEC2C16DF9F002FACA6 /* MyOrdersVC.swift in Sources */, 9C56E8482BDBEFAB00E4CA14 /* AssetColor.swift in Sources */, + 9C21F8222C382A580050BFCC /* AVPlayerVM.swift in Sources */, 52BFB5372C33E0C500BAAE15 /* AudioBookHomeVM.swift in Sources */, 9C0A85432BEE3EC90093783D /* NewPasswordVM.swift in Sources */, 526A43752C36AA4A00AE148F /* GamesListVC.swift in Sources */, @@ -1773,17 +1841,20 @@ 524C42332C049D590016A11C /* CustomizableSegmentControl.swift in Sources */, 9C535DB52C005A6D00DA6DCD /* KeyWindowFix.swift in Sources */, 9C9BEEC72BEE1BBF004ECC2F /* CollectionViewCenteredFlowLayout.swift in Sources */, + 9CB3D08D2C37CDD60062869D /* KaraokeListingVM.swift in Sources */, 5222426A2BFC7AFC0085C632 /* SideMenuVC.swift in Sources */, 527AC7012C182DCE00434FB7 /* TimeStringToSeconds.swift in Sources */, 9CBCB29D2BE4D6BB007D7934 /* LoginVM.swift in Sources */, 524C42312C0499560016A11C /* NotificationCenterReloads.swift in Sources */, 9C8C4FAE2C1315410017DD3B /* WebViewVC.swift in Sources */, 52BC3BE22C0E02EE002FACA6 /* FaqVC.swift in Sources */, + 9C21F81E2C37E3CA0050BFCC /* AVPlayerVC.swift in Sources */, 52A981D02C1AFEE8000E0BEC /* MyListVM.swift in Sources */, 5272FCE52BDFDC8C000ECB1D /* UserDetailsRegisterVM.swift in Sources */, 528E5F222C24660F00E33E4E /* SeasonCategoryCell.swift in Sources */, 525954272BE9178F00191286 /* UserDataDM.swift in Sources */, 9C27E1652BDB6FBC00EC1DA9 /* StoryBoardID.swift in Sources */, + 9CB3D08B2C37BBA50062869D /* KaraokeListingVC.swift in Sources */, 52FDBA782BFF23F4009D7AC7 /* TimePeriod.swift in Sources */, 527AC6FA2C17387300434FB7 /* SongBlogDM.swift in Sources */, 522A931C2C0DE9150098FE49 /* AboutUsVc.swift in Sources */, @@ -1801,6 +1872,7 @@ 52AC2D252C295A7900337473 /* TeaserDM.swift in Sources */, 9C535DC22C00B36900DA6DCD /* ThemeTwoVC.swift in Sources */, 9CA7C6C22C1095B600D73742 /* ProfileVM.swift in Sources */, + 9CB3D0912C37D6930062869D /* KaraokeDetailsVC.swift in Sources */, 52E214C72C2AD47F00BC2D29 /* EpisodeDetailsVC.swift in Sources */, 52D774F12BDFC53B001D87DE /* StringSubScript.swift in Sources */, 9CBE1B3F2C0F37B300CA6E61 /* DPDConstants.swift in Sources */, diff --git a/WOKA/Assets/Assets.xcassets/Karaoke/Contents.json b/WOKA/Assets/Assets.xcassets/Karaoke/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/WOKA/Assets/Assets.xcassets/Karaoke/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/WOKA/Assets/Assets.xcassets/Karaoke/Microphone.imageset/Contents.json b/WOKA/Assets/Assets.xcassets/Karaoke/Microphone.imageset/Contents.json new file mode 100644 index 0000000..4e91752 --- /dev/null +++ b/WOKA/Assets/Assets.xcassets/Karaoke/Microphone.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Microphone.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Microphone@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Microphone@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/WOKA/Assets/Assets.xcassets/Karaoke/Microphone.imageset/Microphone.png b/WOKA/Assets/Assets.xcassets/Karaoke/Microphone.imageset/Microphone.png new file mode 100644 index 0000000..804d2fb Binary files /dev/null and b/WOKA/Assets/Assets.xcassets/Karaoke/Microphone.imageset/Microphone.png differ diff --git a/WOKA/Assets/Assets.xcassets/Karaoke/Microphone.imageset/Microphone@2x.png b/WOKA/Assets/Assets.xcassets/Karaoke/Microphone.imageset/Microphone@2x.png new file mode 100644 index 0000000..4107294 Binary files /dev/null and b/WOKA/Assets/Assets.xcassets/Karaoke/Microphone.imageset/Microphone@2x.png differ diff --git a/WOKA/Assets/Assets.xcassets/Karaoke/Microphone.imageset/Microphone@3x.png b/WOKA/Assets/Assets.xcassets/Karaoke/Microphone.imageset/Microphone@3x.png new file mode 100644 index 0000000..e3bdad8 Binary files /dev/null and b/WOKA/Assets/Assets.xcassets/Karaoke/Microphone.imageset/Microphone@3x.png differ diff --git a/WOKA/Audio Books/ContinueAudioCell.swift b/WOKA/Audio Books/ContinueAudioCell.swift index 81f5e88..8b266f3 100644 --- a/WOKA/Audio Books/ContinueAudioCell.swift +++ b/WOKA/Audio Books/ContinueAudioCell.swift @@ -63,6 +63,37 @@ class ContinueAudioCell: UICollectionViewCell { } } + func setKaraokeData(data: KaraokeListingDM.KaraokeDatum){ + //heart.fill , heart , hand.thumbsup.fill , hand.thumbsup + if AuthFunc.shareInstance.getDefaultLanguage() == .english{ + audioBookTitle.text = data.contentMoreDetails?.filter({$0.languageMasterID == 1}).first?.title + }else{ + audioBookTitle.text = data.contentMoreDetails?.filter({$0.languageMasterID == 2}).first?.title + } + totalLikes.text = data.likesCount?.toString() ?? "0" + + if let url = data.thumbnailPath{ + audioBookThumbnail.imageURL(url) + } + + if let like = data.isLiked{ + switch like{ + case true: + likeBtn.setImage(UIImage(named: "LikeAdd"), for: .normal) + case false: + likeBtn.setImage(UIImage(named: "LikeRemove"), for: .normal) + } + } + + if let favourite = data.markAsFavourite{ + if favourite == true{ + favBtn.setImage(UIImage(named: "FavouriteAdd"), for: .normal) + }else{ + favBtn.setImage(UIImage(named: "FavouriteRemove"), for: .normal) + } + } + } + @IBAction func btnTapped(_ sender: UIButton) { switch sender{ case likeBtn: diff --git a/WOKA/Constants K/StoryBoard.swift b/WOKA/Constants K/StoryBoard.swift index abe7fdd..1454770 100644 --- a/WOKA/Constants K/StoryBoard.swift +++ b/WOKA/Constants K/StoryBoard.swift @@ -19,5 +19,6 @@ extension K{ static let webSeries = "WebSeries" static let audioBooks = "AudioBooks" static let Games = "Games" + static let Karaoke = "Karaoke" } } diff --git a/WOKA/Constants K/StoryBoardID.swift b/WOKA/Constants K/StoryBoardID.swift index 1b0e65c..6ce013c 100644 --- a/WOKA/Constants K/StoryBoardID.swift +++ b/WOKA/Constants K/StoryBoardID.swift @@ -81,5 +81,13 @@ extension K{ static let gamesWebViewVC = "GamesWebViewVC" } + // MARK: - Karaoke + + struct Karaoke{ + static let karaokeListingVC = "KaraokeListingVC" + static let karaokeDetailsVC = "KaraokeDetailsVC" + static let aVPlayerVC = "AVPlayerVC" + } + } } diff --git a/WOKA/Helpers/DateFormatterLib.swift b/WOKA/Helpers/DateFormatterLib.swift index e87192b..7822440 100644 --- a/WOKA/Helpers/DateFormatterLib.swift +++ b/WOKA/Helpers/DateFormatterLib.swift @@ -227,6 +227,7 @@ enum DateFormats: String, CaseIterable { case d = "d" // 2 case EEEE = "EEEE" // wednesday case EEE = "EEE" // wed + case yyyy = "yyyy" // year 2023 case yyyy_MM_dd_T_HH_mm_ss_SSSZ = "yyyy_MM_dd_T_HH_mm_ss_SSSZ" case yyyy_MM_dd_THH_mm_ss_SSSZ = "yyyy_MM_dd_THH:mm:ss.SSSZ" // 2024-05-21T17:50:15.000000Z diff --git a/WOKA/Home/Controller/MyListVC.swift b/WOKA/Home/Controller/MyListVC.swift index d6848b7..a0a56a2 100644 --- a/WOKA/Home/Controller/MyListVC.swift +++ b/WOKA/Home/Controller/MyListVC.swift @@ -506,7 +506,7 @@ extension MyListVC : ReloadSeriesFavLike{ } - print(index , type , isFav, isLike) +// print(index , type , isFav, isLike) } diff --git a/WOKA/Karaoke/Controller/AVPlayerVC.swift b/WOKA/Karaoke/Controller/AVPlayerVC.swift new file mode 100644 index 0000000..d3292b5 --- /dev/null +++ b/WOKA/Karaoke/Controller/AVPlayerVC.swift @@ -0,0 +1,263 @@ +// +// AVPlayerVC.swift +// WOKA +// +// Created by Bilal on 05/07/2024. +// + +import UIKit +import AVFoundation + +class AVPlayerVC: UIViewController { + + @IBOutlet weak var videoPlayer: UIView! +// @IBOutlet weak var videoPlayerHeight: NSLayoutConstraint! + @IBOutlet weak var viewControll: UIView! + @IBOutlet weak var stackCtrView: UIStackView! + + @IBOutlet weak var sliderStack: UIStackView! + @IBOutlet weak var tintView: UIView! + @IBOutlet weak var videoTitle: UILabel! + + @IBOutlet weak var img10SecBack: UIImageView! { + didSet { + self.img10SecBack.isUserInteractionEnabled = true + self.img10SecBack.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(onTap10SecBack))) + } + } + @IBOutlet weak var imgPlay: UIImageView! { + didSet { + self.imgPlay.isUserInteractionEnabled = true + self.imgPlay.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(onTapPlayPause))) + } + } + @IBOutlet weak var img10SecFor: UIImageView! { + didSet { + self.img10SecFor.isUserInteractionEnabled = true + self.img10SecFor.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(onTap10SecNext))) + } + } + + @IBOutlet weak var lbCurrentTime: UILabel! + @IBOutlet weak var lbTotalTime: UILabel! + + + @IBOutlet weak var seekSlider: UISlider! { + didSet { + self.seekSlider.addTarget(self, action: #selector(onTapToSlide), for: .valueChanged) + } + } + + + var videoURL : String? + var timer : Timer? + var titleVideo : String? + var vm = AVPlayerVM() + + override func viewDidLoad() { + super.viewDidLoad() + vm.vc = self + vm.initView() + self.videoTitle.text = titleVideo + startTimer() + + viewControll.addTapGesture { + self.timer?.invalidate() + self.showHideControls() + } + } + + override func viewDidAppear(_ animated: Bool) { + self.setVideoPlayer() + } + + @IBAction func closeBtnTapped(_ sender: UIButton) { + self.dismiss(animated: true) + } + + func startTimer(){ + timer = Timer.scheduledTimer(withTimeInterval: 3.5, repeats: false) { _ in + self.showHideControls() + } + } + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + self.player?.pause() + self.player = nil + } + + // MARK: - ShowHideControls + + func showHideControls(){ + stackCtrView.isHidden.toggle() + sliderStack.isHidden.toggle() + tintView.isHidden.toggle() + + if !stackCtrView.isHidden{ + startTimer() + } + } + + + private var player : AVPlayer? = nil + private var playerLayer : AVPlayerLayer? = nil + + private func setVideoPlayer() { + guard let videoURL, let url = URL(string: videoURL) else { return } + + if self.player == nil { + self.player = AVPlayer(url: url) + self.playerLayer = AVPlayerLayer(player: self.player) + self.playerLayer?.videoGravity = .resizeAspectFill + self.playerLayer?.frame = self.videoPlayer.bounds + self.playerLayer?.addSublayer(self.viewControll.layer) + if let playerLayer = self.playerLayer { + self.videoPlayer.layer.addSublayer(playerLayer) + } + self.player?.play() + self.imgPlay.image = UIImage(systemName: "pause.circle") + } + self.setObserverToPlayer() + } + + +// private var windowInterface : UIInterfaceOrientation? { +// return self.view.window?.windowScene?.interfaceOrientation +// } + +// override func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator) { +// super.willTransition(to: newCollection, with: coordinator) +// guard let windowInterface = self.windowInterface else { return } +// if windowInterface.isPortrait == true { +// self.videoPlayerHeight.constant = 300 +// } else { +// self.videoPlayerHeight.constant = self.view.layer.bounds.width +// } +// print(self.videoPlayerHeight.constant) +// DispatchQueue.main.asyncAfter(deadline: .now() + 0.1, execute: { +// self.playerLayer?.frame = self.videoPlayer.bounds +// }) +// } + + + private var timeObserver : Any? = nil + + private func setObserverToPlayer() { + let interval = CMTime(seconds: 0.3, preferredTimescale: CMTimeScale(NSEC_PER_SEC)) + timeObserver = player?.addPeriodicTimeObserver(forInterval: interval, queue: DispatchQueue.main, using: { elapsed in + self.updatePlayerTime() + }) + } + + private func updatePlayerTime() { + guard let currentTime = self.player?.currentTime() else { return } + guard let duration = self.player?.currentItem?.duration else { return } + + let currentTimeInSecond = CMTimeGetSeconds(currentTime) + let durationTimeInSecond = CMTimeGetSeconds(duration) + + if self.isThumbSeek == false { + self.seekSlider.value = Float(currentTimeInSecond/durationTimeInSecond) + } + + let value = Float64(self.seekSlider.value) * CMTimeGetSeconds(duration) + + var hours = value / 3600 + var mins = (value / 60).truncatingRemainder(dividingBy: 60) + var secs = value.truncatingRemainder(dividingBy: 60) + var timeformatter = NumberFormatter() + timeformatter.minimumIntegerDigits = 2 + timeformatter.minimumFractionDigits = 0 + timeformatter.roundingMode = .down + guard let hoursStr = timeformatter.string(from: NSNumber(value: hours)), let minsStr = timeformatter.string(from: NSNumber(value: mins)), let secsStr = timeformatter.string(from: NSNumber(value: secs)) else { + return + } + self.lbCurrentTime.text = "\(hoursStr):\(minsStr):\(secsStr)" + + hours = durationTimeInSecond / 3600 + mins = (durationTimeInSecond / 60).truncatingRemainder(dividingBy: 60) + secs = durationTimeInSecond.truncatingRemainder(dividingBy: 60) + timeformatter = NumberFormatter() + timeformatter.minimumIntegerDigits = 2 + timeformatter.minimumFractionDigits = 0 + timeformatter.roundingMode = .down + guard let hoursStr = timeformatter.string(from: NSNumber(value: hours)), let minsStr = timeformatter.string(from: NSNumber(value: mins)), let secsStr = timeformatter.string(from: NSNumber(value: secs)) else { + return + } + self.lbTotalTime.text = "\(hoursStr):\(minsStr):\(secsStr)" + } + + + @objc private func onTap10SecNext() { + guard let currentTime = self.player?.currentTime() else { return } + let seekTime10Sec = CMTimeGetSeconds(currentTime).advanced(by: 10) + let seekTime = CMTime(value: CMTimeValue(seekTime10Sec), timescale: 1) + self.player?.seek(to: seekTime, completionHandler: { completed in + + }) + } + + @objc private func onTap10SecBack() { + guard let currentTime = self.player?.currentTime() else { return } + let seekTime10Sec = CMTimeGetSeconds(currentTime).advanced(by: -10) + let seekTime = CMTime(value: CMTimeValue(seekTime10Sec), timescale: 1) + self.player?.seek(to: seekTime, completionHandler: { completed in + + }) + } + + @objc private func onTapPlayPause() { + if self.player?.timeControlStatus == .playing { + self.imgPlay.image = UIImage(systemName: "play.circle") + self.player?.pause() + } else { + self.imgPlay.image = UIImage(systemName: "pause.circle") + self.player?.play() + } + } + + private var isThumbSeek : Bool = false + @objc private func onTapToSlide() { + if timer != nil{ + timer?.invalidate() + timer = nil + } + self.isThumbSeek = true + guard let duration = self.player?.currentItem?.duration else { return } + let value = Float64(self.seekSlider.value) * CMTimeGetSeconds(duration) + if value.isNaN == false { + let seekTime = CMTime(value: CMTimeValue(value), timescale: 1) + self.player?.seek(to: seekTime, completionHandler: { completed in + if completed { + self.isThumbSeek = false + self.startTimer() +// print("Completed") + } + }) + } + } + + @objc private func onTapToggleScreen() { + if #available(iOS 16.0, *) { + guard let windowSceen = self.view.window?.windowScene else { return } + if windowSceen.interfaceOrientation == .portrait { + windowSceen.requestGeometryUpdate(.iOS(interfaceOrientations: .landscape)) { error in + print(error.localizedDescription) + } + } else { + windowSceen.requestGeometryUpdate(.iOS(interfaceOrientations: .portrait)) { error in + print(error.localizedDescription) + } + } + } else { + if UIDevice.current.orientation == .portrait { + let orientation = UIInterfaceOrientation.landscapeRight.rawValue + UIDevice.current.setValue(orientation, forKey: "orientation") + } else { + let orientation = UIInterfaceOrientation.portrait.rawValue + UIDevice.current.setValue(orientation, forKey: "orientation") + } + } + } +} diff --git a/WOKA/Karaoke/Controller/KaraokeDetailsVC.swift b/WOKA/Karaoke/Controller/KaraokeDetailsVC.swift new file mode 100644 index 0000000..6c1edc8 --- /dev/null +++ b/WOKA/Karaoke/Controller/KaraokeDetailsVC.swift @@ -0,0 +1,174 @@ +// +// KaraokeDetailsVC.swift +// WOKA +// +// Created by Bilal on 05/07/2024. +// + +import UIKit + +class KaraokeDetailsVC: UIViewController { + + @IBOutlet weak var watchingImage: UIImageView! + @IBOutlet weak var watchingTitle: UILabel! + @IBOutlet weak var watchingDesc: UITextView! + @IBOutlet weak var releaseDate: UILabel! + + @IBOutlet weak var addIcon: UIImageView! + @IBOutlet weak var addLabel: UILabel! + @IBOutlet weak var likeIcon: UIImageView! + @IBOutlet weak var likeLabel: UILabel! + @IBOutlet weak var totalLikes: UILabel! + + @IBOutlet weak var addView: UIView! + @IBOutlet weak var shareView: UIView! + @IBOutlet weak var likeView: UIView! + + var karaokeData : KaraokeListingDM.KaraokeDatum? + var delegate : ReloadAudioBooksFavLike? + + override func viewDidLoad() { + super.viewDidLoad() + initView() + tapHandler() + } + + func initView(){ + if let karaokeData{ + if let url = karaokeData.thumbnailPath{ + watchingImage.imageURL(url, color: .white) + } + + totalLikes.text = karaokeData.likesCount?.toString() ?? "0" + + if let releaseDate = karaokeData.releaseDate{ + if let formatDate = DateFormatterLib.dateMods(dateStr: releaseDate, dateCurrentFormat: .yyyy_MM_dd_HH_mm_ss, dateReturnFormat: .yyyy, stringOrDate: .string).0{ + self.releaseDate.text = formatDate + } + } + + if let like = karaokeData.isLiked{ + switch like{ + case true: + likeIcon.image = UIImage(systemName: "hand.thumbsup.fill") + likeLabel.text = "LIKED".localized(loc: AuthFunc.shareInstance.languageSelected.rawValue) + case false: + likeIcon.image = UIImage(systemName: "hand.thumbsup") + likeLabel.text = "LIKE".localized(loc: AuthFunc.shareInstance.languageSelected.rawValue) + } + } + + if let favourite = karaokeData.markAsFavourite{ + if favourite == true{ + addIcon.image = UIImage(systemName: "heart.fill") + addLabel.text = "ADDED".localized(loc: AuthFunc.shareInstance.languageSelected.rawValue) + }else{ + addIcon.image = UIImage(systemName: "heart") + addLabel.text = "ADD".localized(loc: AuthFunc.shareInstance.languageSelected.rawValue) + } + } + + if AuthFunc.shareInstance.getDefaultLanguage() == .english{ + if let englishData = karaokeData.contentMoreDetails?.filter({$0.languageMasterID == 1}).first{ + watchingTitle.text = englishData.title + if let desc = englishData.description?.replacingOccurrences(of: "
", with: "").htmlToAttributedString{ + let sizeText = NSMutableAttributedString(attributedString: desc) + sizeText.setFontFace(font: FontCustom.shareInstance.customFont(fontName: .Exo2_Regular, size: 15),color: UIColor.appColor(.TextDarkBlue)!) + self.watchingDesc.attributedText = sizeText + } + } + }else{ + if let hindiData = karaokeData.contentMoreDetails?.filter({$0.languageMasterID == 2}).first{ + watchingTitle.text = hindiData.title + if let desc = hindiData.description?.replacingOccurrences(of: "
", with: "").htmlToAttributedString{ + let sizeText = NSMutableAttributedString(attributedString: desc) + sizeText.setFontFace(font: FontCustom.shareInstance.customFont(fontName: .Exo2_Regular, size: 15),color: UIColor.appColor(.TextDarkBlue)!) + self.watchingDesc.attributedText = sizeText + } + } + } + } + } + + func tapHandler(){ + + self.view.addTapGesture { + self.dismiss(animated: true) + } + + addView.addTapGesture { [weak self] in + guard let self else{return} + + if let karaokeData{ + guard let showID = karaokeData.id, let isFav = karaokeData.markAsFavourite, let postType = karaokeData.contentMoreDetails?.first?.postType else{return} + + if isFav { + LikeFavCommonFunc.shareInstance.removeFavourite(postID: showID, postType: postType, categoryID: 0, vc: self) { isDone in + self.karaokeData?.markAsFavourite = false + K.GVar.reloadMyList = true + self.delegate?.updateRows(id: showID, type: .favourite, isFav: false, isLike: nil) + self.initView() + } + }else{ + LikeFavCommonFunc.shareInstance.addFavourite(postID: showID, postType: postType, categoryID: 0, vc: self) { isDone in + self.karaokeData?.markAsFavourite = true + K.GVar.reloadMyList = true + self.delegate?.updateRows(id: showID, type: .favourite, isFav: true, isLike: nil) + self.initView() + } + } + } + } + + likeView.addTapGesture { [weak self] in + guard let self else{return} + + if let karaokeData{ + guard let showID = karaokeData.id, let isLiked = karaokeData.isLiked, let postType = karaokeData.contentMoreDetails?.first?.postType else{return} + + if isLiked{ + LikeFavCommonFunc.shareInstance.unlikePost(postID: showID, postType: postType, vc: self) { isDone in + self.karaokeData?.isLiked = false + K.GVar.reloadMyList = true + self.delegate?.updateRows(id: showID, type: .liked, isFav: nil, isLike: false) + self.initView() + } + }else{ + LikeFavCommonFunc.shareInstance.likePost(postID: showID, postType: postType, vc: self) { isDone in + self.karaokeData?.isLiked = true + K.GVar.reloadMyList = true + self.delegate?.updateRows(id: showID, type: .liked, isFav: nil, isLike: true) + self.initView() + } + } + } + } + + shareView.addTapGesture { + print("share") + } + } + + @IBAction func playNowBtnTapped(_ sender: LocalisedElementsButton) { + let sb = UIStoryboard(name: K.StoryBoard.Karaoke, bundle: nil) + let vcPush = sb.instantiateViewController(withIdentifier: K.StoryBoardID.Karaoke.aVPlayerVC) as! AVPlayerVC + if AuthFunc.shareInstance.getDefaultLanguage() == .english{ + if let englishData = karaokeData?.contentMoreDetails?.filter({$0.languageMasterID == 1}).first{ + vcPush.titleVideo = englishData.title + vcPush.videoURL = englishData.url + } + }else{ + if let hindiData = karaokeData?.contentMoreDetails?.filter({$0.languageMasterID == 2}).first{ + vcPush.titleVideo = hindiData.title + vcPush.videoURL = hindiData.url + } + } + self.present(vcPush, animated: true) + } + + @IBAction func closeBtnTapped(_ sender: UIButton) { + self.dismiss(animated: true) { + + } + } +} diff --git a/WOKA/Karaoke/Controller/KaraokeListingVC.swift b/WOKA/Karaoke/Controller/KaraokeListingVC.swift new file mode 100644 index 0000000..79e8b4a --- /dev/null +++ b/WOKA/Karaoke/Controller/KaraokeListingVC.swift @@ -0,0 +1,233 @@ +// +// KaraokeListingVC.swift +// WOKA +// +// Created by Bilal on 05/07/2024. +// + +import UIKit + +class KaraokeListingVC: UIViewController { + + @IBOutlet weak var headerView: ShimmerEffectView! + @IBOutlet weak var selectedShowView: ShimmerEffectView! + @IBOutlet weak var headerHeight: NSLayoutConstraint! + @IBOutlet weak var headerImage: UIImageView! + @IBOutlet weak var headerTitleLabel: UILabel! + + @IBOutlet weak var scrollView: UIScrollView! + + @IBOutlet weak var continueWatchingCV: UICollectionView! + @IBOutlet weak var continueWatchingStack: UIStackView! + + @IBOutlet weak var karaokeListingTableView: UITableView! + @IBOutlet weak var tableHeight: NSLayoutConstraint! + + var vm = KaraokeListingVM() + + override func viewDidLoad() { + super.viewDidLoad() + scrollView.delegate = self + vm.vc = self + vm.initView() + navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default) + navigationController?.navigationBar.shadowImage = UIImage() + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + navigationController?.setNavigationBarHidden(false, animated: animated) + self.navigationController?.setColor(color: .white) + } + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + self.navigationController?.setNavigationBarHidden(true, animated: animated) + } + + override func viewDidDisappear(_ animated: Bool) { + super.viewDidDisappear(animated) + + // Customize the navigation bar's appearance + self.navigationController?.setColor(color: .black) + } + + override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + vm.updateTableHeight() + } +} + +// MARK: - CollectionView Delegate and Data Source + +extension KaraokeListingVC : CollectionViewSRC{ + + func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + return vm.continueWatchingData.count + } + + func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: K.CellIdentifier.AudioBooks.continueAudioCell, for: indexPath) as! ContinueAudioCell + let data = vm.continueWatchingData[indexPath.row] + cell.setKaraokeData(data: data) + + cell.btnTapped = { [self] (type) -> Void in + vm.updateFavLikes(type: type,id: vm.continueWatchingData[indexPath.row].id ?? 0) + } + return cell + } + + func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { + + let data = vm.continueWatchingData[indexPath.row] + + /* + Updated the top header data + */ + vm.indexToLoad = vm.karaokeListData.firstIndex(where: {$0.id == data.id}) ?? 0 + vm.setHeaderData() + + let sb = UIStoryboard(name: K.StoryBoard.Karaoke, bundle: nil) + let vcPush = sb.instantiateViewController(withIdentifier: K.StoryBoardID.Karaoke.karaokeDetailsVC) as! KaraokeDetailsVC + vcPush.modalPresentationStyle = .overCurrentContext + vcPush.modalTransitionStyle = .crossDissolve + vcPush.karaokeData = data + vcPush.delegate = self + self.present(vcPush, animated: true) + + } + +} + +// MARK: - Collection Flow Layout + +extension KaraokeListingVC : UICollectionViewDelegateFlowLayout{ + + func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat { + return 5 + } + + func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets { + let inset: CGFloat = 10 + return UIEdgeInsets(top: 0, left: inset, bottom: 0, right: inset) + } + + func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat { + return 0 // Space between cells + } + + func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { + let widthPerItem = collectionView.frame.width - 30 // Adjust to your desired width + return CGSize(width: widthPerItem, height: 230) + } +} + +// MARK: - TableView DataSource , Delegates + +extension KaraokeListingVC : TableViewSRC{ + + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return vm.karaokeListData.count == 0 ? 2 : vm.karaokeListData.count + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: K.CellIdentifier.WebSeries.webSeriesShowListingCell) as! WebSeriesShowListingCell + + if vm.karaokeListData.count == 0{ + cell.showShimmer() + }else{ + let data = vm.karaokeListData[indexPath.row] + cell.setKaraokeData(data: data) + cell.stopShimmer() + } + + cell.btnTapped = { [weak self] (type) -> Void in + guard let self , let id = vm.karaokeListData[indexPath.row].id else{return} + vm.updateFavLikes(type: type, id: id) + } + return cell + } + + + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + /* + Updated the top header data + */ + vm.indexToLoad = indexPath.row + vm.setHeaderData() + + let data = vm.karaokeListData[indexPath.row] + + let sb = UIStoryboard(name: K.StoryBoard.Karaoke, bundle: nil) + let vcPush = sb.instantiateViewController(withIdentifier: K.StoryBoardID.Karaoke.karaokeDetailsVC) as! KaraokeDetailsVC + vcPush.modalPresentationStyle = .overCurrentContext + vcPush.modalTransitionStyle = .crossDissolve + vcPush.karaokeData = data + vcPush.delegate = self + self.present(vcPush, animated: true) + } +} + +extension KaraokeListingVC : ReloadAudioBooksFavLike{ + func updateRows(id: Int, type: FavCellCLick, isFav: Bool?, isLike: Bool?) { + if let isFav{ + if let continueDataIndex = vm.continueWatchingData.firstIndex(where:{$0.id == id}) { + vm.continueWatchingData[continueDataIndex].markAsFavourite = isFav + continueWatchingCV.reloadItems(at: [IndexPath(row: continueDataIndex, section: 0)]) + } + + if let audioListDataIndex = vm.karaokeListData.firstIndex(where:{$0.id == id}) { + vm.karaokeListData[audioListDataIndex].markAsFavourite = isFav + karaokeListingTableView.reloadRows(at: [IndexPath(row: audioListDataIndex, section: 0)],with: .none) + K.GVar.reloadMyList = true + } + } + + if let isLike{ + if let continueDataIndex = vm.continueWatchingData.firstIndex(where:{$0.id == id}) { + vm.continueWatchingData[continueDataIndex].isLiked = isLike + continueWatchingCV.reloadItems(at: [IndexPath(row: continueDataIndex, section: 0)]) + } + + if let audioListDataIndex = vm.karaokeListData.firstIndex(where:{$0.id == id}) { + vm.karaokeListData[audioListDataIndex].isLiked = isLike + karaokeListingTableView.reloadRows(at: [IndexPath(row: audioListDataIndex, section: 0)],with: .none) + K.GVar.reloadMyList = true + } + } + } + + +} +// MARK: - Animating scrollView + +extension KaraokeListingVC: UIScrollViewDelegate { + + func scrollViewDidScroll(_ scrollView: UIScrollView) { + + // Get the current vertical offset of the scroll view + let y = scrollView.contentOffset.y + + // Define the height range for the header view + let minHeaderHeight: CGFloat = 0.0 // Height at which the header becomes invisible + let maxHeaderHeight: CGFloat = 200.0 // Maximum height when fully visible + + // Calculate the new height for the header view based on the scroll position + let newHeaderHeight: CGFloat + if y < 0 { + // When scrolling up beyond the top, ensure the header view is fully expanded + newHeaderHeight = maxHeaderHeight + } else { + // Calculate the new height for the header view, ensuring it doesn't go below the minimum height + newHeaderHeight = max(minHeaderHeight, maxHeaderHeight - y) + } + + // Update the header view's height constraint with the new height + headerHeight.constant = newHeaderHeight + + // Animate the layout changes to smoothly transition the header height + UIView.animate(withDuration: 0.3) { + self.view.layoutIfNeeded() + } + } +} diff --git a/WOKA/Karaoke/Karaoke.storyboard b/WOKA/Karaoke/Karaoke.storyboard new file mode 100644 index 0000000..cc96791 --- /dev/null +++ b/WOKA/Karaoke/Karaoke.storyboard @@ -0,0 +1,838 @@ + + + + + + + + + + + + + + Exo2-Bold + + + Exo2-Medium + + + Exo2-Regular + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WOKA/Karaoke/Model/KaraokeContinueWatchingDM.swift b/WOKA/Karaoke/Model/KaraokeContinueWatchingDM.swift new file mode 100644 index 0000000..fb63b5c --- /dev/null +++ b/WOKA/Karaoke/Model/KaraokeContinueWatchingDM.swift @@ -0,0 +1,19 @@ +// +// KaraokeContinueWatchingDM.swift +// WOKA +// +// Created by Bilal on 05/07/2024. +// + +import Foundation + +// MARK: - KaraokeListingDM +struct KaraokeContinueWatchingDM: Codable { + let result: [KaraokeListingDM.KaraokeDatum]? + let totalRecords: Int? + + enum CodingKeys: String, CodingKey { + case result + case totalRecords = "total_records" + } +} diff --git a/WOKA/Karaoke/Model/KaraokeListingDM.swift b/WOKA/Karaoke/Model/KaraokeListingDM.swift new file mode 100644 index 0000000..efeb4fd --- /dev/null +++ b/WOKA/Karaoke/Model/KaraokeListingDM.swift @@ -0,0 +1,73 @@ +// +// KaraokeListingDM.swift +// WOKA +// +// Created by Bilal on 05/07/2024. +// + +import Foundation + +// MARK: - KaraokeListingDM +struct KaraokeListingDM: Codable { + let karaokeData: [KaraokeDatum]? + let totalRecords: Int? + + enum CodingKeys: String, CodingKey { + case karaokeData = "karaoke_data" + case totalRecords = "total_records" + } + + // MARK: - KaraokeDatum + struct KaraokeDatum: Codable { + let id: Int? + let title, description: String? + let videoURL: String? + let thumbnailPath: String? + let releaseDate: String? + let duration, categoryMasterID, ageRangeMasterID, genderMasterID: String? + let languageMasterID: Int? + let contentMoreDetails: [ContentMoreDetail]? +// let categoryData, ageRangeData, genderData: [JSONAny]? + var markAsFavourite, isLiked: Bool? + var viewsCount, likesCount, bookmarkCount: Int? + + enum CodingKeys: String, CodingKey { + case id, title, description + case videoURL = "video_url" + case thumbnailPath = "thumbnail_path" + case releaseDate = "release_date" + case duration + case categoryMasterID = "category_master_id" + case ageRangeMasterID = "age_range_master_id" + case genderMasterID = "gender_master_id" + case languageMasterID = "language_master_id" + case contentMoreDetails = "content_more_details" +// case categoryData = "category_data" +// case ageRangeData = "age_range_data" +// case genderData = "gender_data" + case markAsFavourite = "mark_as_favourite" + case isLiked = "is_liked" + case viewsCount = "views_count" + case likesCount = "likes_count" + case bookmarkCount = "bookmark_count" + } + } + + // MARK: - ContentMoreDetail + struct ContentMoreDetail: Codable { + let id, contentID, postType, languageMasterID: Int? + let title, description: String? + let url: String? + let tagsKeywords: String? + + enum CodingKeys: String, CodingKey { + case id + case contentID = "content_id" + case postType = "post_type" + case languageMasterID = "language_master_id" + case title, description, url + case tagsKeywords = "tags_keywords" + } + } +} + diff --git a/WOKA/Karaoke/ViewModel/AVPlayerVM.swift b/WOKA/Karaoke/ViewModel/AVPlayerVM.swift new file mode 100644 index 0000000..314c959 --- /dev/null +++ b/WOKA/Karaoke/ViewModel/AVPlayerVM.swift @@ -0,0 +1,17 @@ +// +// AVPlayerVM.swift +// WOKA +// +// Created by Bilal on 05/07/2024. +// + +import Foundation + +class AVPlayerVM{ + + weak var vc : AVPlayerVC! + + func initView(){ + + } +} diff --git a/WOKA/Karaoke/ViewModel/KaraokeListingVM.swift b/WOKA/Karaoke/ViewModel/KaraokeListingVM.swift new file mode 100644 index 0000000..7112d5c --- /dev/null +++ b/WOKA/Karaoke/ViewModel/KaraokeListingVM.swift @@ -0,0 +1,241 @@ +// +// KaraokeListingVM.swift +// WOKA +// +// Created by Bilal on 05/07/2024. +// + +import UIKit +import Alamofire + +class KaraokeListingVM{ + + weak var vc : KaraokeListingVC! + var karaokeListData = [KaraokeListingDM.KaraokeDatum]() + var continueWatchingData = [KaraokeListingDM.KaraokeDatum]() + var indexToLoad = 0 + + func initView(){ + setupCell() + let color1 = #colorLiteral(red: 0.8, green: 0.6078431373, blue: 0.1098039216, alpha: 1) + let color2 = #colorLiteral(red: 0.8, green: 0.2901960784, blue: 0.1098039216, alpha: 1) + vc.title = "KARAOKE".localized(loc: AuthFunc.shareInstance.languageSelected.rawValue) + vc.view.applyGradient(colors: [color2, color1], startPoint: CGPoint(x: 0, y: 0), endPoint: CGPoint(x: 0.8, y: 0)) + startShimmer() + getContinueWatching() + getKaraokeListing() + } + + func setupCell(){ + vc.continueWatchingCV.register(UINib(nibName: K.CellIdentifier.AudioBooks.continueAudioCell, bundle: nil), forCellWithReuseIdentifier: K.CellIdentifier.AudioBooks.continueAudioCell) + vc.continueWatchingCV.delegate = vc.self + vc.continueWatchingCV.dataSource = vc.self + + vc.karaokeListingTableView.register(UINib(nibName: K.CellIdentifier.WebSeries.webSeriesShowListingCell, bundle: nil), forCellReuseIdentifier: K.CellIdentifier.WebSeries.webSeriesShowListingCell) + vc.karaokeListingTableView.delegate = vc.self + vc.karaokeListingTableView.dataSource = vc.self + } + + func updateTableHeight(){ + self.vc.tableHeight.constant = self.vc.karaokeListingTableView.contentSize.height + 100 + self.vc.karaokeListingTableView.layoutIfNeeded() + self.vc.tableHeight.constant = self.vc.karaokeListingTableView.contentSize.height + } + + func setHeaderData(){ + let data = karaokeListData[indexToLoad] + + if let url = data.thumbnailPath{ + self.vc.headerImage.imageURL(url, color: .white) + } + + if AuthFunc.shareInstance.getDefaultLanguage() == .english{ + let englishData = data.contentMoreDetails?.filter({$0.languageMasterID == 1}).first + vc.headerTitleLabel.text = englishData?.title + }else{ + let hindiData = data.contentMoreDetails?.filter({$0.languageMasterID == 2}).first + vc.headerTitleLabel.text = hindiData?.title + } + } + + // MARK: - GetKaraoke Listing + + func getContinueWatching(){ + // Utilities.startProgressHUD() + let headers : HTTPHeaders = ["access-token" : AuthFunc.shareInstance.getAccessToken()] + let params : Parameters = ["post_type" : 8] // 8 - Karaoke + NetworkManager.shareInstance.apiRequest(url: APIEndPoints.WebSeries.continue_watching, method: .post,parameters: params,headers : headers) { [weak self](result : Result, NetworkManager.APIError>) in + switch result{ + case .success(let data): + guard let self else{ + Utilities.dismissProgressHUD() + return + } + switch data.success{ + case 0: + /* + Error + */ + Utilities.dismissProgressHUD() + // vc.toast(msg: data.message ?? "Unrecognised error" , time: 2) + self.vc.continueWatchingStack.isHidden = true + case 1: + Utilities.dismissProgressHUD() + guard let data = data.data?.result else{return} + if data.count == 0{ + self.vc.continueWatchingStack.isHidden = true + }else{ + self.vc.continueWatchingStack.isHidden = false + } + self.continueWatchingData = data.reversed() + self.vc.continueWatchingCV.reloadData() + default: + break + } + case .failure(let error): + guard let self else{ + Utilities.dismissProgressHUD() + return + } + Utilities.dismissProgressHUD() + self.vc.continueWatchingStack.isHidden = true + vc.toast(msg: error.localizedDescription , time: 2) + } + } + } + + func getKaraokeListing(){ +// Utilities.startProgressHUD() + let headers : HTTPHeaders = ["access-token" : AuthFunc.shareInstance.getAccessToken()] + NetworkManager.shareInstance.apiRequest(url: APIEndPoints.Karaoke.sing_karaoke_listing, method: .post,headers: headers) { [weak self](result : Result, NetworkManager.APIError>) in + switch result{ + case .success(let data): + guard let self else{ + Utilities.dismissProgressHUD() + return + } + switch data.success{ + case 0: + /* + Error + */ + Utilities.dismissProgressHUD() + vc.toast(msg: data.message ?? "Unrecognised error" , time: 2) + case 1: + Utilities.dismissProgressHUD() + guard let data = data.data?.karaokeData else{return} + self.karaokeListData.removeAll() + self.karaokeListData = data + self.vc.karaokeListingTableView.reloadData() + self.vc.tableHeight.constant = self.vc.karaokeListingTableView.contentSize.height + 100 + self.vc.karaokeListingTableView.layoutIfNeeded() + self.vc.tableHeight.constant = self.vc.karaokeListingTableView.contentSize.height + setHeaderData() + self.stopShimmer() + default: + break + } + case .failure(let error): + guard let self else{ + Utilities.dismissProgressHUD() + return + } + Utilities.dismissProgressHUD() + vc.toast(msg: error.localizedDescription , time: 2) + } + } + } + + func startShimmer(){ + vc.headerView.startShimmer() + vc.selectedShowView.startShimmer() + } + + func stopShimmer(){ + self.vc.headerView.stopShimmer() + self.vc.selectedShowView.stopShimmer() + } + + // MARK: - Update Fav Likes + + func updateFavLikes(type : FavCellCLick, id : Int){ + guard let data = karaokeListData.filter({$0.id == id}).first, let audioListIndex = karaokeListData.firstIndex(where: {$0.id == id}) else{return} + switch type { + case .favourite: + guard let isFav = data.markAsFavourite ,let postID = data.id,let postType = data.contentMoreDetails?.first?.postType else{return} + if isFav == true { + LikeFavCommonFunc.shareInstance.removeFavourite(postID: postID, postType: postType, categoryID: 0, vc: self.vc) { [unowned self] isDone in + if isDone{ + karaokeListData[audioListIndex].markAsFavourite = false + vc.karaokeListingTableView.reloadRows(at: [IndexPath(row: audioListIndex, section: 0)],with: .none) + K.GVar.reloadMyList = true + + /* + Check if the data is in continue watching + */ + if let continueWatchingIndex = continueWatchingData.firstIndex(where: { $0.id == id }){ + continueWatchingData[continueWatchingIndex].markAsFavourite = false + vc.continueWatchingCV.reloadItems(at: [IndexPath(row: continueWatchingIndex, section: 0)]) + } + } + } + }else{ + LikeFavCommonFunc.shareInstance.addFavourite(postID: postID, postType: postType, categoryID: 0, vc: self.vc) { [unowned self] isDone in + if isDone{ + karaokeListData[audioListIndex].markAsFavourite = true + vc.karaokeListingTableView.reloadRows(at: [IndexPath(row: audioListIndex, section: 0)],with: .none) + K.GVar.reloadMyList = true + + /* + Check if the data is in continue watching + */ + if let continueWatchingIndex = continueWatchingData.firstIndex(where: { $0.id == id }){ + continueWatchingData[continueWatchingIndex].markAsFavourite = true + vc.continueWatchingCV.reloadItems(at: [IndexPath(row: continueWatchingIndex, section: 0)]) + } + } + } + } + return + case .liked: + guard let isLiked = data.isLiked ,let postID = data.id,let postType = data.contentMoreDetails?.first?.postType else{return} + if isLiked{ + LikeFavCommonFunc.shareInstance.unlikePost(postID: postID, postType: postType, vc: self.vc) { [unowned self] isDone in + if isDone{ + karaokeListData[audioListIndex].isLiked = false + karaokeListData[audioListIndex].likesCount! -= 1 + vc.karaokeListingTableView.reloadRows(at: [IndexPath(row: audioListIndex, section: 0)],with: .none) + K.GVar.reloadMyList = true + + /* + Check if the data is in continue watching + */ + if let continueWatchingIndex = continueWatchingData.firstIndex(where: { $0.id == id }){ + continueWatchingData[continueWatchingIndex].isLiked = false + continueWatchingData[continueWatchingIndex].likesCount! -= 1 + vc.continueWatchingCV.reloadItems(at: [IndexPath(row: continueWatchingIndex, section: 0)]) + } + } + } + }else{ + LikeFavCommonFunc.shareInstance.likePost(postID: postID, postType: postType, vc: self.vc){ [unowned self] isDone in + if isDone{ + karaokeListData[audioListIndex].isLiked = true + karaokeListData[audioListIndex].likesCount! += 1 + vc.karaokeListingTableView.reloadRows(at: [IndexPath(row: audioListIndex, section: 0)],with: .none) + K.GVar.reloadMyList = true + + /* + Check if the data is in continue watching + */ + if let continueWatchingIndex = continueWatchingData.firstIndex(where: { $0.id == id }){ + continueWatchingData[continueWatchingIndex].isLiked = true + continueWatchingData[continueWatchingIndex].likesCount! += 1 + vc.continueWatchingCV.reloadItems(at: [IndexPath(row: continueWatchingIndex, section: 0)]) + } + } + } + } + } + } +} diff --git a/WOKA/Localized Module/hi.lproj/Localizable.strings b/WOKA/Localized Module/hi.lproj/Localizable.strings index 063f227..673cc83 100644 --- a/WOKA/Localized Module/hi.lproj/Localizable.strings +++ b/WOKA/Localized Module/hi.lproj/Localizable.strings @@ -243,3 +243,9 @@ Games */ "HAVE A FUN TIME" = "आनंद करने का समय"; + +/* + Karaoke + */ +"SING ALONG & DANCE" = "साथ गायें और नाचें"; +"SING NOW" = "अभी गायें"; diff --git a/WOKA/Network Adapter/APIEndPoints.swift b/WOKA/Network Adapter/APIEndPoints.swift index 4140375..154f2db 100644 --- a/WOKA/Network Adapter/APIEndPoints.swift +++ b/WOKA/Network Adapter/APIEndPoints.swift @@ -99,6 +99,10 @@ struct APIEndPoints { static let get_token_to_auth_player = makeURL(path: "get_token_to_auth_player") } + struct Karaoke{ + static let sing_karaoke_listing = makeURL(path: "sing_karaoke_listing") + } + // Other endpoint categories... struct Links { static let privacyPolicy = "https://www.wokaland.com/privacy-policy/" diff --git a/WOKA/Theme/Base.lproj/Theme.storyboard b/WOKA/Theme/Base.lproj/Theme.storyboard index d48130d..b48c3e7 100644 --- a/WOKA/Theme/Base.lproj/Theme.storyboard +++ b/WOKA/Theme/Base.lproj/Theme.storyboard @@ -314,28 +314,8 @@ - - - - - - - - - - - - - + @@ -364,23 +344,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + - + + - - - + + - @@ -458,6 +470,7 @@ + diff --git a/WOKA/Theme/Controller/PlayerVC.swift b/WOKA/Theme/Controller/PlayerVC.swift index 0d236a8..ac9d35e 100644 --- a/WOKA/Theme/Controller/PlayerVC.swift +++ b/WOKA/Theme/Controller/PlayerVC.swift @@ -41,7 +41,7 @@ class PlayerVC: JWPlayerViewController, JWPlayerViewControllerDelegate { let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene windowScene?.requestGeometryUpdate(.iOS(interfaceOrientations: UIInterfaceOrientationMask.portrait)) } else { - UIDevice.current.setValue(UIInterfaceOrientationMask.landscapeRight.rawValue, forKey: "orientation") + UIDevice.current.setValue(UIInterfaceOrientationMask.portrait.rawValue, forKey: "orientation") } // UIDevice.current.setValue(UIInterfaceOrientation.portrait.rawValue, forKey: "orientation") UIView.setAnimationsEnabled(true) diff --git a/WOKA/Theme/Controller/ThemeOneVC.swift b/WOKA/Theme/Controller/ThemeOneVC.swift index 8d7cebf..4a6be72 100644 --- a/WOKA/Theme/Controller/ThemeOneVC.swift +++ b/WOKA/Theme/Controller/ThemeOneVC.swift @@ -29,6 +29,7 @@ class ThemeOneVC: UIViewController { @IBOutlet weak var moreStack: UIStackView! @IBOutlet weak var bottomArrow: UIImageView! @IBOutlet weak var gamesView: UIView! + @IBOutlet weak var karaokeView: UIView! var timer: Timer? diff --git a/WOKA/Theme/ViewModel/ThemeOneVM.swift b/WOKA/Theme/ViewModel/ThemeOneVM.swift index a06bad3..39b166f 100644 --- a/WOKA/Theme/ViewModel/ThemeOneVM.swift +++ b/WOKA/Theme/ViewModel/ThemeOneVM.swift @@ -144,6 +144,15 @@ class ThemeOneVM{ vc.navigationController?.pushViewController(vcPush, animated: true) } } + + vc.karaokeView.addTapGesture { [self] in + ViewButtonAnimation.sharedInstance.btnTapped(in: self.vc, view: self.vc.karaokeView) { [weak self] in + guard let self else{return} + let sb = UIStoryboard(name: K.StoryBoard.Karaoke, bundle: nil) + let vcPush = sb.instantiateViewController(withIdentifier: K.StoryBoardID.Karaoke.karaokeListingVC) as! KaraokeListingVC + vc.navigationController?.pushViewController(vcPush, animated: true) + } + } } // MARK: - Animate Clouds and LiveTV diff --git a/WOKA/WebSeries/View/WebSeriesShowListingCell.swift b/WOKA/WebSeries/View/WebSeriesShowListingCell.swift index f1ae44c..0a4011e 100644 --- a/WOKA/WebSeries/View/WebSeriesShowListingCell.swift +++ b/WOKA/WebSeries/View/WebSeriesShowListingCell.swift @@ -135,6 +135,37 @@ class WebSeriesShowListingCell: UITableViewCell { } } + func setKaraokeData(data: KaraokeListingDM.KaraokeDatum){ + //heart.fill , heart , hand.thumbsup.fill , hand.thumbsup + if AuthFunc.shareInstance.getDefaultLanguage() == .english{ + showTitle.text = data.contentMoreDetails?.filter({$0.languageMasterID == 1}).first?.title + }else{ + showTitle.text = data.contentMoreDetails?.filter({$0.languageMasterID == 2}).first?.title + } + totalLikes.text = data.likesCount?.toString() ?? "0" + + if let url = data.thumbnailPath{ + showThumbnail.imageURL(url) + } + + if let like = data.isLiked{ + switch like{ + case true: + likeBtn.setImage(UIImage(named: "LikeAdd"), for: .normal) + case false: + likeBtn.setImage(UIImage(named: "LikeRemove"), for: .normal) + } + } + + if let favourite = data.markAsFavourite{ + if favourite == true{ + favBtn.setImage(UIImage(named: "FavouriteAdd"), for: .normal) + }else{ + favBtn.setImage(UIImage(named: "FavouriteRemove"), for: .normal) + } + } + } + @IBAction func btnTapped(_ sender: UIButton) { switch sender{ case likeBtn: