From 1f650bd2b720d359486ba7edddbe3e4ac387f5eb Mon Sep 17 00:00:00 2001 From: Bilal Date: Fri, 21 Jun 2024 19:35:40 +0530 Subject: [PATCH] - added api for fetching the episode as per the selected category - made the category collection cells dynamic - handled the category selection will call the episode api - solved activity indicator view at the splash start-up - handled the app lifecycle for live tv app going in foreground and background - handled play pause while the live tv view apperas and disappears - Made the likes and favourites dynamic on episode screen --- WOKA.xcodeproj/project.pbxproj | 12 ++ .../PlayButton.imageset/Contents.json | 3 + WOKA/Constants K/CellIdentifier.swift | 1 + WOKA/Home/Home.storyboard | 2 +- WOKA/Network Adapter/APIEndPoints.swift | 1 + .../Controller/SplashVC.swift | 13 -- .../ViewModel/SplashVM.swift | 40 +++--- WOKA/SideBarNav/Controller/AboutUsVc.swift | 3 + WOKA/SideBarNav/Controller/MyOrdersVC.swift | 1 + WOKA/Theme/Controller/ThemeOneVC.swift | 15 +++ WOKA/Theme/ViewModel/ThemeOneVM.swift | 36 +++-- .../Controller/WebSeriesSeasonVC.swift | 116 +++++++--------- WOKA/WebSeries/Controller/WebSeriesVC.swift | 2 +- .../Model/SeasonEpisodeListingDM.swift | 105 +++++++++++++++ WOKA/WebSeries/View/SeasonCategoryCell.swift | 2 +- WOKA/WebSeries/View/SeasonCategoryCell.xib | 21 +-- .../WebSeries/View/WebSeriesEpisodeCell.swift | 42 ++++++ WOKA/WebSeries/View/WebSeriesEpisodeCell.xib | 126 ++++++++++++++++++ .../ViewModel/WebSeriesSeasonVM.swift | 109 ++++++++++++++- WOKA/WebSeries/WebSeries.storyboard | 77 +++++------ 20 files changed, 559 insertions(+), 168 deletions(-) create mode 100644 WOKA/WebSeries/Model/SeasonEpisodeListingDM.swift create mode 100644 WOKA/WebSeries/View/WebSeriesEpisodeCell.swift create mode 100644 WOKA/WebSeries/View/WebSeriesEpisodeCell.xib diff --git a/WOKA.xcodeproj/project.pbxproj b/WOKA.xcodeproj/project.pbxproj index 46f735b..864ba9a 100644 --- a/WOKA.xcodeproj/project.pbxproj +++ b/WOKA.xcodeproj/project.pbxproj @@ -156,6 +156,9 @@ 52FDBA7D2BFF481A009D7AC7 /* ThemeOneVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52FDBA7C2BFF481A009D7AC7 /* ThemeOneVM.swift */; }; 52FDDAB52BF34DC300E037C1 /* YesNoAlertVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52FDDAB42BF34DC300E037C1 /* YesNoAlertVC.swift */; }; 619A5A1BD8BD968ADC83C106 /* Pods_WOKA.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BBA543A4216400A2864E3D3E /* Pods_WOKA.framework */; }; + 9C007F202C255DF200F798C2 /* SeasonEpisodeListingDM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C007F1F2C255DF200F798C2 /* SeasonEpisodeListingDM.swift */; }; + 9C007F232C25603800F798C2 /* WebSeriesEpisodeCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C007F212C25603800F798C2 /* WebSeriesEpisodeCell.swift */; }; + 9C007F242C25603800F798C2 /* WebSeriesEpisodeCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9C007F222C25603800F798C2 /* WebSeriesEpisodeCell.xib */; }; 9C0A853F2BEE35340093783D /* ForgotPassDM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C0A853E2BEE35340093783D /* ForgotPassDM.swift */; }; 9C0A85412BEE35670093783D /* ResetPassUserNameVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C0A85402BEE35670093783D /* ResetPassUserNameVM.swift */; }; 9C0A85432BEE3EC90093783D /* NewPasswordVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C0A85422BEE3EC90093783D /* NewPasswordVM.swift */; }; @@ -407,6 +410,9 @@ 52FDBA7A2BFF2712009D7AC7 /* AuthFuncTimeHandling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthFuncTimeHandling.swift; sourceTree = ""; }; 52FDBA7C2BFF481A009D7AC7 /* ThemeOneVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeOneVM.swift; sourceTree = ""; }; 52FDDAB42BF34DC300E037C1 /* YesNoAlertVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YesNoAlertVC.swift; sourceTree = ""; }; + 9C007F1F2C255DF200F798C2 /* SeasonEpisodeListingDM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeasonEpisodeListingDM.swift; sourceTree = ""; }; + 9C007F212C25603800F798C2 /* WebSeriesEpisodeCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebSeriesEpisodeCell.swift; sourceTree = ""; }; + 9C007F222C25603800F798C2 /* WebSeriesEpisodeCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = WebSeriesEpisodeCell.xib; sourceTree = ""; }; 9C0A853E2BEE35340093783D /* ForgotPassDM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForgotPassDM.swift; sourceTree = ""; }; 9C0A85402BEE35670093783D /* ResetPassUserNameVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetPassUserNameVM.swift; sourceTree = ""; }; 9C0A85422BEE3EC90093783D /* NewPasswordVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewPasswordVM.swift; sourceTree = ""; }; @@ -987,6 +993,8 @@ 52D6A2562C22C1E300145908 /* WebSeriesShowListingCell.xib */, 528E5F202C24660F00E33E4E /* SeasonCategoryCell.swift */, 528E5F212C24660F00E33E4E /* SeasonCategoryCell.xib */, + 9C007F212C25603800F798C2 /* WebSeriesEpisodeCell.swift */, + 9C007F222C25603800F798C2 /* WebSeriesEpisodeCell.xib */, ); path = View; sourceTree = ""; @@ -998,6 +1006,7 @@ 52D6A24D2C22B3AB00145908 /* WebSeriesShowListDM.swift */, 52D6A2532C22B93F00145908 /* CategoryListingDM.swift */, 528E5F1A2C24531200E33E4E /* SeasonListingDM.swift */, + 9C007F1F2C255DF200F798C2 /* SeasonEpisodeListingDM.swift */, ); path = Model; sourceTree = ""; @@ -1385,6 +1394,7 @@ 525954302BEA394400191286 /* CustomAlerts.storyboard in Resources */, 52C8B0632BDA6993003B51D0 /* Localizable.strings in Resources */, 523ED2672BDA2BC900CFED02 /* Assets.xcassets in Resources */, + 9C007F242C25603800F798C2 /* WebSeriesEpisodeCell.xib in Resources */, 527AC6FE2C173A5100434FB7 /* SongListCell.xib in Resources */, 523ED26A2BDA2BC900CFED02 /* Base in Resources */, 52C8B05B2BDA5924003B51D0 /* WokaSplashSound.m4a in Resources */, @@ -1491,6 +1501,7 @@ 9C535DC62C00BF2400DA6DCD /* HomeExploreCell.swift in Sources */, 52D774EF2BDFC50D001D87DE /* StringValidations.swift in Sources */, 52D6A2512C22B58200145908 /* WebSeriesShowListingCell.swift in Sources */, + 9C007F232C25603800F798C2 /* WebSeriesEpisodeCell.swift in Sources */, 5272FCE32BDFDB05000ECB1D /* UserDetailsRegisterVC.swift in Sources */, 525954102BE8B72900191286 /* FontCustom.swift in Sources */, 5202AAFE2BDF90590043B7BD /* TextFieldImage.swift in Sources */, @@ -1533,6 +1544,7 @@ 52BC3BF02C1701F8002FACA6 /* BlogDM.swift in Sources */, 525954192BE8CC3400191286 /* ConstantString.swift in Sources */, 52D774EB2BDFC0BF001D87DE /* OTPVC.swift in Sources */, + 9C007F202C255DF200F798C2 /* SeasonEpisodeListingDM.swift in Sources */, 52D2F3D82C24043D009E52FF /* ShimmerEffectView.swift in Sources */, 9C27E16F2BDB866500EC1DA9 /* CellIdentifier.swift in Sources */, 52BC3BF22C170264002FACA6 /* MoreVM.swift in Sources */, diff --git a/WOKA/Assets/Assets.xcassets/WebSeries/PlayButton.imageset/Contents.json b/WOKA/Assets/Assets.xcassets/WebSeries/PlayButton.imageset/Contents.json index b779445..fd6f474 100644 --- a/WOKA/Assets/Assets.xcassets/WebSeries/PlayButton.imageset/Contents.json +++ b/WOKA/Assets/Assets.xcassets/WebSeries/PlayButton.imageset/Contents.json @@ -19,5 +19,8 @@ "info" : { "author" : "xcode", "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "template" } } diff --git a/WOKA/Constants K/CellIdentifier.swift b/WOKA/Constants K/CellIdentifier.swift index 38f107a..a46b3d6 100644 --- a/WOKA/Constants K/CellIdentifier.swift +++ b/WOKA/Constants K/CellIdentifier.swift @@ -42,6 +42,7 @@ extension K{ static let webSeriesCell = "WebSeriesCell" static let webSeriesShowListingCell = "WebSeriesShowListingCell" static let seasonCategoryCell = "SeasonCategoryCell" + static let webSeriesEpisodeCell = "WebSeriesEpisodeCell" } } } diff --git a/WOKA/Home/Home.storyboard b/WOKA/Home/Home.storyboard index 6f50cbc..bd98e4a 100644 --- a/WOKA/Home/Home.storyboard +++ b/WOKA/Home/Home.storyboard @@ -1222,7 +1222,7 @@ - + diff --git a/WOKA/Network Adapter/APIEndPoints.swift b/WOKA/Network Adapter/APIEndPoints.swift index 91e95da..093993f 100644 --- a/WOKA/Network Adapter/APIEndPoints.swift +++ b/WOKA/Network Adapter/APIEndPoints.swift @@ -84,6 +84,7 @@ struct APIEndPoints { static let watch_show_listing = makeURL(path: "watch_show_listing") static let category_listing = makeURL(path: "category_listing") static let season_listing = makeURL(path: "season_listing") + static let season_episode_listing = makeURL(path: "season_episode_listing") } // Other endpoint categories... diff --git a/WOKA/OnBoarding Module/Controller/SplashVC.swift b/WOKA/OnBoarding Module/Controller/SplashVC.swift index e2b7a62..a3d97cc 100644 --- a/WOKA/OnBoarding Module/Controller/SplashVC.swift +++ b/WOKA/OnBoarding Module/Controller/SplashVC.swift @@ -42,15 +42,6 @@ class SplashVC: UIViewController { AuthFunc.shareInstance.languageSelected = .english } -// let sb1 = UIStoryboard(name: "Home", bundle: nil) -// let vc1 = sb1.instantiateViewController(withIdentifier: "SideMenu") as! SideMenuController -// self.navigationController?.pushViewController(vc1, animated: true) - - -// UIApplication.setRootView(SideMenuController.instantiate(from: .Home)) -// -// return - let sb = UIStoryboard(name: K.StoryBoard.main, bundle: nil) let vc = sb.instantiateViewController(withIdentifier: K.StoryBoardID.OnBoarding.onBoardVC) as! OnBoardVC @@ -59,10 +50,6 @@ class SplashVC: UIViewController { transition.duration = 0.3 // Set the duration of the animation transition.type = CATransitionType.fade // Set the type of animation to fade - // Optionally, set other properties such as timing function, subtype, etc. - // transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut) - // transition.subtype = CATransitionSubtype.fromTop - // Get the navigation controller guard let navigationController = navigationController else { return } diff --git a/WOKA/OnBoarding Module/ViewModel/SplashVM.swift b/WOKA/OnBoarding Module/ViewModel/SplashVM.swift index 84adfc5..08cdec6 100644 --- a/WOKA/OnBoarding Module/ViewModel/SplashVM.swift +++ b/WOKA/OnBoarding Module/ViewModel/SplashVM.swift @@ -14,6 +14,25 @@ class SplashVM{ weak var vc : SplashVC! var player: AVAudioPlayer? + func initView(){ + vc.activityIndicator.hidesWhenStopped = true + let color1 = #colorLiteral(red: 0.144693464, green: 0.1426281333, blue: 0.6686832905, alpha: 1) + let color2 = #colorLiteral(red: 0.4862745098, green: 0.1960784314, blue: 0.7019607843, alpha: 1) + vc.hindiBtn.applyGradient(colors: [color1, color2], startPoint: CGPoint(x: 0, y: 0), endPoint: CGPoint(x: 0, y: 0.8)) + vc.englishBtn.applyGradient(colors: [color1, color2], startPoint: CGPoint(x: 0, y: 0), endPoint: CGPoint(x: 0, y: 0.8)) + vc.hindiBtn.roundCorner() + vc.englishBtn.roundCorner() + selectTheme() + + // check if user has selected the default language + if let language = AuthFunc.shareInstance.getDefaultLanguage(){ + AuthFunc.shareInstance.languageSelected = language + }else{ + AuthFunc.shareInstance.setDefaultLanguage(language: .english) + } + } + + // Play initial sound func playSplashSound() { guard let path = Bundle.main.path(forResource: K.StaticFilesString.wokaSplashSound, ofType:"m4a") else { return } @@ -28,24 +47,6 @@ class SplashVM{ } } - func initView(){ - let color1 = #colorLiteral(red: 0.144693464, green: 0.1426281333, blue: 0.6686832905, alpha: 1) - let color2 = #colorLiteral(red: 0.4862745098, green: 0.1960784314, blue: 0.7019607843, alpha: 1) - vc.hindiBtn.applyGradient(colors: [color1, color2], startPoint: CGPoint(x: 0, y: 0), endPoint: CGPoint(x: 0, y: 0.8)) - vc.englishBtn.applyGradient(colors: [color1, color2], startPoint: CGPoint(x: 0, y: 0), endPoint: CGPoint(x: 0, y: 0.8)) - vc.hindiBtn.roundCorner() - vc.englishBtn.roundCorner() - selectTheme() - vc.activityIndicator.stopAnimating() - - // check if user has selected the default language - if let language = AuthFunc.shareInstance.getDefaultLanguage(){ - AuthFunc.shareInstance.languageSelected = language - }else{ - AuthFunc.shareInstance.setDefaultLanguage(language: .english) - } - } - func selectTheme(){ let theme = UserDefaults.standard.string(forKey: K.UserDefaultsStruct.themeDefault) if theme != nil{ @@ -55,6 +56,8 @@ class SplashVM{ } } + // MARK: - Get the user data if loginned + func getUserData(){ if AuthFunc.shareInstance.getUserType() == 3{ //setusertype @@ -98,6 +101,7 @@ class SplashVM{ } } + // handling activity indicator func startStopIndicator(start : Bool , hide : Bool = false){ if hide{ vc.activityIndicator.stopAnimating() diff --git a/WOKA/SideBarNav/Controller/AboutUsVc.swift b/WOKA/SideBarNav/Controller/AboutUsVc.swift index 0eff652..903c707 100644 --- a/WOKA/SideBarNav/Controller/AboutUsVc.swift +++ b/WOKA/SideBarNav/Controller/AboutUsVc.swift @@ -19,13 +19,16 @@ class AboutUsVc: UIViewController { override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) + self.navigationController?.setColor(color: .black) navigationController?.setNavigationBarHidden(false, animated: animated) } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) navigationController?.setNavigationBarHidden(true, animated: animated) + self.navigationController?.setColor(color: .white) } + } diff --git a/WOKA/SideBarNav/Controller/MyOrdersVC.swift b/WOKA/SideBarNav/Controller/MyOrdersVC.swift index 1ef44f4..0c4efa1 100644 --- a/WOKA/SideBarNav/Controller/MyOrdersVC.swift +++ b/WOKA/SideBarNav/Controller/MyOrdersVC.swift @@ -53,6 +53,7 @@ class MyOrdersVC: UIViewController { override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) + self.navigationController?.setColor(color: .black) navigationController?.setNavigationBarHidden(false, animated: animated) } diff --git a/WOKA/Theme/Controller/ThemeOneVC.swift b/WOKA/Theme/Controller/ThemeOneVC.swift index 1901ea9..833ee93 100644 --- a/WOKA/Theme/Controller/ThemeOneVC.swift +++ b/WOKA/Theme/Controller/ThemeOneVC.swift @@ -48,6 +48,21 @@ class ThemeOneVC: UIViewController { vm.initView() } + override func viewWillDisappear(_ animated: Bool) { + vm.shouldAnimate = false + if let player = vm.avPlayer{ + player.pause() + } + } + + override func viewDidAppear(_ animated: Bool) { + vm.shouldAnimate = true + vm.moveLiveTVView() + if let player = vm.avPlayer{ + player.play() + } + } + override func viewDidLayoutSubviews() { vm.setupAvPlayer() } diff --git a/WOKA/Theme/ViewModel/ThemeOneVM.swift b/WOKA/Theme/ViewModel/ThemeOneVM.swift index 64cc101..926322b 100644 --- a/WOKA/Theme/ViewModel/ThemeOneVM.swift +++ b/WOKA/Theme/ViewModel/ThemeOneVM.swift @@ -18,6 +18,8 @@ class ThemeOneVM{ var avPlayer : AVPlayer! var playerLayer: AVPlayerLayer! + var shouldAnimate = true + func initView(){ vc.bottomArrow.addTapGesture { let sb = UIStoryboard(name: K.StoryBoard.theme, bundle: nil) @@ -27,7 +29,6 @@ class ThemeOneVM{ } AuthFunc.shareInstance.initTimePeriods() startInitialTimer() - moveLiveTVView() moveCloudView() handleTaps() setUserData() @@ -102,12 +103,14 @@ class ThemeOneVM{ @objc func appDidEnterBackground() { // Code to execute when the app enters the background print("App entered background") + self.avPlayer.pause() self.handleBackground() } @objc func appWillEnterForeground() { // Code to execute when the app enters the foreground print("App will enter foreground") + self.avPlayer.play() self.handleBackground() } @@ -123,29 +126,42 @@ class ThemeOneVM{ } } - //LiveTV - } // MARK: - Animate Clouds and LiveTV + + func centerLiveTVViewHorizontally() { + DispatchQueue.main.async { [weak self] in + guard let self = self else { return } + self.vc.liveTVView.center.x = self.vc.view.center.x // Center the liveTVView horizontally + } + } + func moveLiveTVView() { + guard shouldAnimate else { + self.centerLiveTVViewHorizontally() + return + } // Stop animating if shouldAnimate is false + guard let vc = self.vc else { return } // Ensure the view controller is available UIView.animate(withDuration: 6, delay: 0, options: [.allowUserInteraction], animations: { [weak self] in - guard let self else{return} + guard let self = self else { return } let margin: CGFloat = 30 - let screenWidth = self.vc.view.frame.width - let viewWidth = self.vc.liveTVView.frame.width + let screenWidth = vc.view.frame.width + let viewWidth = vc.liveTVView.frame.width let maxX = screenWidth - margin - viewWidth / 2 let minX = margin + viewWidth / 2 - if isMovingRight { + if self.isMovingRight { vc.liveTVView.center.x = maxX // Move to the right } else { vc.liveTVView.center.x = minX // Move to the left } }, completion: { [weak self] _ in - guard let self else{return} - isMovingRight.toggle() // Toggle the direction for the next iteration - moveLiveTVView() // Recursively call moveLiveTVView to create a continuous animation + guard let self = self else { return } + self.isMovingRight.toggle() // Toggle the direction for the next iteration + DispatchQueue.main.async { // Ensure the recursive call is made on the main thread + self.moveLiveTVView() // Recursively call moveLiveTVView to create a continuous animation + } }) } diff --git a/WOKA/WebSeries/Controller/WebSeriesSeasonVC.swift b/WOKA/WebSeries/Controller/WebSeriesSeasonVC.swift index 317ac84..d87546d 100644 --- a/WOKA/WebSeries/Controller/WebSeriesSeasonVC.swift +++ b/WOKA/WebSeries/Controller/WebSeriesSeasonVC.swift @@ -19,12 +19,24 @@ class WebSeriesSeasonVC: UIViewController { @IBOutlet weak var seasonDesc: UILabel! @IBOutlet weak var categoryCV: UICollectionView! + @IBOutlet weak var episodeTableView: UITableView! + @IBOutlet weak var tableHeight: NSLayoutConstraint! + + + @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 addStack: UIStackView! + @IBOutlet weak var shareStack: UIStackView! + @IBOutlet weak var likeStack: UIStackView! override func viewDidLoad() { super.viewDidLoad() vm.vc = self vm.initView() - navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default) navigationController?.navigationBar.shadowImage = UIImage() } @@ -51,8 +63,25 @@ class WebSeriesSeasonVC: UIViewController { @IBAction func watchBtnTapped(_ sender: LocalisedElementsButton) { } - @IBAction func btnTapped(_ sender: LocalisedElementsButton) { +} + +// MARK: - TableView DataSource , Delegates + +extension WebSeriesSeasonVC : TableViewSRC{ + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return vm.seasonEpisodeData.count + } + + func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { + return 100 + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: K.CellIdentifier.WebSeries.webSeriesEpisodeCell) as! WebSeriesEpisodeCell + let data = vm.seasonEpisodeData[indexPath.row] + cell.setData(data: data) + return cell } } @@ -68,12 +97,14 @@ extension WebSeriesSeasonVC : CollectionViewSRC{ let cell = collectionView.dequeueReusableCell(withReuseIdentifier: K.CellIdentifier.WebSeries.seasonCategoryCell, for: indexPath) as! SeasonCategoryCell let data = vm.seasonListingData[indexPath.row] - cell.setData(title: data.seasonNumber ?? "Season", iselected: indexPath.row == vm.selectedCateogory) + cell.setData(title: data.seasonNumber ?? "Season", iselected: data.id == vm.episodeSelectedCateogory) return cell } func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { - print(indexPath.row) + vm.episodeSelectedCateogory = vm.seasonListingData[indexPath.row].id + vm.getSeasonEpisode() + self.categoryCV.reloadData() } } @@ -83,76 +114,19 @@ extension WebSeriesSeasonVC : UICollectionViewDelegateFlowLayout{ func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { // Generate a random string for testing purposes let randomText = vm.seasonListingData[indexPath.row].seasonNumber! - + // Define the font for the text - let font = FontCustom.shareInstance.customFont(fontName: .Exo2_Bold, size: 18) // You can adjust the font size as needed - + let font = FontCustom.shareInstance.customFont(fontName: .Exo2_Bold, size: 18) // Adjust the font size as needed + // Calculate the width of the text - let textWidth = randomText.size(withAttributes: [.font: font]).width - + let attributes = [NSAttributedString.Key.font: font] + let textWidth = (randomText as NSString).size(withAttributes: attributes).width + // Set the cell width based on the text width and any additional padding - let cellWidth = textWidth + 25 // Add any additional spacing you want - - return CGSize(width: cellWidth, height: 50) - } - - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat { - section == 0 ? 15 : 5 - } - - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets { - UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10) - } - -} - -// Helper method to calculate text width -extension String { - func width(withConstrainedHeight height: CGFloat, font: UIFont) -> CGFloat { - let constraintRect = CGSize(width: .greatestFiniteMagnitude, height: height) - let boundingBox = self.boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, attributes: [.font: font], context: nil) - return ceil(boundingBox.width) - } -} - -@IBDesignable -class VerticalButton: UIButton { - - @IBInspectable public var padding: CGFloat = 20.0 { - didSet { - setNeedsLayout() - } - } - - override var intrinsicContentSize: CGSize { - let maxSize = CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude) - - if let titleSize = titleLabel?.sizeThatFits(maxSize), let imageSize = imageView?.sizeThatFits(maxSize) { - let width = ceil(max(imageSize.width, titleSize.width)) - let height = ceil(imageSize.height + titleSize.height + padding) - - return CGSize(width: width, height: height) - } - - return super.intrinsicContentSize - } - - override func layoutSubviews() { - if let image = imageView?.image, let title = titleLabel?.attributedText { - let imageSize = image.size - let titleSize = title.size() - - if effectiveUserInterfaceLayoutDirection == .leftToRight { - titleEdgeInsets = UIEdgeInsets(top: 0.0, left: -imageSize.width, bottom: -(imageSize.height + padding), right: 0.0) - imageEdgeInsets = UIEdgeInsets(top: -(titleSize.height + padding), left: 0.0, bottom: 0.0, right: -titleSize.width) - } - else { - titleEdgeInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: -(imageSize.height + padding), right: -imageSize.width) - imageEdgeInsets = UIEdgeInsets(top: -(titleSize.height + padding), left: -titleSize.width, bottom: 0.0, right: 0.0) - } - } - - super.layoutSubviews() + // 14 for container view + 10 for inside spacing. + let padding: CGFloat = 24 + 20 // Adjust padding as needed + let cellWidth = textWidth + padding + return CGSize(width: cellWidth , height: 60) } } diff --git a/WOKA/WebSeries/Controller/WebSeriesVC.swift b/WOKA/WebSeries/Controller/WebSeriesVC.swift index 0e9cc46..a36e050 100644 --- a/WOKA/WebSeries/Controller/WebSeriesVC.swift +++ b/WOKA/WebSeries/Controller/WebSeriesVC.swift @@ -195,7 +195,7 @@ extension WebSeriesVC : TableViewSRC{ let sb = UIStoryboard(name: K.StoryBoard.webSeries, bundle: nil) let vcPush = sb.instantiateViewController(withIdentifier: K.StoryBoardID.WebSeries.webSeriesSeasonVC) as! WebSeriesSeasonVC - vcPush.vm.watchShowID = showData.id + vcPush.vm.showData = showData if let selectedIndex = vm.dropDownModule.indexForSelectedRow{ let categoryID = vm.categoryListingData[selectedIndex] vcPush.vm.categoryID = categoryID.id diff --git a/WOKA/WebSeries/Model/SeasonEpisodeListingDM.swift b/WOKA/WebSeries/Model/SeasonEpisodeListingDM.swift new file mode 100644 index 0000000..f336984 --- /dev/null +++ b/WOKA/WebSeries/Model/SeasonEpisodeListingDM.swift @@ -0,0 +1,105 @@ +// +// SeasonEpisodeListingDM.swift +// WOKA +// +// Created by Bilal on 21/06/2024. +// + +import Foundation + +// MARK: - SeasonEpisodeListingDM +struct SeasonEpisodeListingDM: Codable { + let result: [ResultData]? + let totalRecords: Int? + + enum CodingKeys: String, CodingKey { + case result + case totalRecords = "total_records" + } + + // MARK: - Result + struct ResultData: Codable { + let id, watchShowsMasterID: Int? + let seasonNumber: String? + let noOfEpisodes: Int? + let seasonDescription: String? + let releaseYear: Int? + let seasonTitle: String? + let trailerURL: String? + let thumbnailPath: String? + let thumbnailImgURL: String? + let tagsKeyword, releaseDate, mediaType: String? + let seasonMoreDetails: [MoreDetail]? + let episodeData: [EpisodeDatum]? + let episodeTotalRecords: Int? + + enum CodingKeys: String, CodingKey { + case id + case watchShowsMasterID = "watch_shows_master_id" + case seasonNumber = "season_number" + case noOfEpisodes = "no_of_episodes" + case seasonDescription = "season_description" + case releaseYear = "release_year" + case seasonTitle = "season_title" + case trailerURL = "trailer_url" + case thumbnailPath = "thumbnail_path" + case thumbnailImgURL = "thumbnail_img_url" + case tagsKeyword = "tags_keyword" + case releaseDate = "release_date" + case mediaType = "media_type" + case seasonMoreDetails = "season_more_details" + case episodeData = "episode_data" + case episodeTotalRecords = "episode_total_records" + } + } + + // MARK: - EpisodeDatum + struct EpisodeDatum: Codable { + let id, watchShowsMasterID, seasonMasterID, episodeNumber: Int? + let episodeTitle, episodeDescription: String? + let thumbnailPath: String? + let thumbnailImgURL: String? + let episodeURL: String? + let languageMasterID: Int? + let tagsKeyword, episodeDuration, releaseDate: String? + let contentMoreDetails: [MoreDetail]? + + enum CodingKeys: String, CodingKey { + case id + case watchShowsMasterID = "watch_shows_master_id" + case seasonMasterID = "season_master_id" + case episodeNumber = "episode_number" + case episodeTitle = "episode_title" + case episodeDescription = "episode_description" + case thumbnailPath = "thumbnail_path" + case thumbnailImgURL = "thumbnail_img_url" + case episodeURL = "episode_url" + case languageMasterID = "language_master_id" + case tagsKeyword = "tags_keyword" + case episodeDuration = "episode_duration" + case releaseDate = "release_date" + case contentMoreDetails = "content_more_details" + } + } + + // MARK: - MoreDetail + struct MoreDetail: Codable { + let id, contentID, postType, languageMasterID: Int? + let title, description, tagsKeywords: String? + let contentHDURL, contentSDURL, trailerHDURL, trailerSDURL: String? + + enum CodingKeys: String, CodingKey { + case id + case contentID = "content_id" + case postType = "post_type" + case languageMasterID = "language_master_id" + case title, description + case tagsKeywords = "tags_keywords" + case contentHDURL = "content_hd_url" + case contentSDURL = "content_sd_url" + case trailerHDURL = "trailer_hd_url" + case trailerSDURL = "trailer_sd_url" + } + } + +} diff --git a/WOKA/WebSeries/View/SeasonCategoryCell.swift b/WOKA/WebSeries/View/SeasonCategoryCell.swift index 3c9a645..a1f46a4 100644 --- a/WOKA/WebSeries/View/SeasonCategoryCell.swift +++ b/WOKA/WebSeries/View/SeasonCategoryCell.swift @@ -18,7 +18,7 @@ class SeasonCategoryCell: UICollectionViewCell { } override func layoutSubviews() { - outerView.roundCorner() + outerView.roundCorner(radius: 25) } func setData(title : String , iselected : Bool){ diff --git a/WOKA/WebSeries/View/SeasonCategoryCell.xib b/WOKA/WebSeries/View/SeasonCategoryCell.xib index cf43827..4dfe05d 100644 --- a/WOKA/WebSeries/View/SeasonCategoryCell.xib +++ b/WOKA/WebSeries/View/SeasonCategoryCell.xib @@ -7,6 +7,11 @@ + + + Exo2-SemiBold + + @@ -17,11 +22,11 @@ - - + + - @@ -40,8 +45,8 @@ - - + + diff --git a/WOKA/WebSeries/View/WebSeriesEpisodeCell.swift b/WOKA/WebSeries/View/WebSeriesEpisodeCell.swift new file mode 100644 index 0000000..a5825dd --- /dev/null +++ b/WOKA/WebSeries/View/WebSeriesEpisodeCell.swift @@ -0,0 +1,42 @@ +// +// WebSeriesEpisodeCell.swift +// WOKA +// +// Created by Bilal on 21/06/2024. +// + +import UIKit + +class WebSeriesEpisodeCell: UITableViewCell { + + @IBOutlet weak var seasonImage: UIImageView! + @IBOutlet weak var seasonTitle: UILabel! + @IBOutlet weak var seasonTime: UILabel! + @IBOutlet weak var playBtn: UIButton! + + override func awakeFromNib() { + super.awakeFromNib() + // Initialization code + } + + override func setSelected(_ selected: Bool, animated: Bool) { + super.setSelected(selected, animated: animated) + + // Configure the view for the selected state + } + + func setData(data : SeasonEpisodeListingDM.ResultData){ + if let url = data.thumbnailPath{ + self.seasonImage.imageURL(url, color: UIColor.appColor(.TextDarkBlue)!) + } + + if AuthFunc.shareInstance.getDefaultLanguage() == .english{ + seasonTitle.text = data.seasonMoreDetails?.filter({$0.languageMasterID == 1}).first?.title + }else{ + seasonTitle.text = data.seasonMoreDetails?.filter({$0.languageMasterID == 2}).first?.title + } + } + + @IBAction func playBtnTapped(_ sender: UIButton) { + } +} diff --git a/WOKA/WebSeries/View/WebSeriesEpisodeCell.xib b/WOKA/WebSeries/View/WebSeriesEpisodeCell.xib new file mode 100644 index 0000000..31f9d70 --- /dev/null +++ b/WOKA/WebSeries/View/WebSeriesEpisodeCell.xib @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + Exo2-Bold + + + Exo2-Regular + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WOKA/WebSeries/ViewModel/WebSeriesSeasonVM.swift b/WOKA/WebSeries/ViewModel/WebSeriesSeasonVM.swift index 062360e..234bfa3 100644 --- a/WOKA/WebSeries/ViewModel/WebSeriesSeasonVM.swift +++ b/WOKA/WebSeries/ViewModel/WebSeriesSeasonVM.swift @@ -12,29 +12,86 @@ class WebSeriesSeasonVM{ weak var vc : WebSeriesSeasonVC! - var watchShowID : Int? +// var watchShowID : Int? var categoryID : Int? - var selectedCateogory = 0 + var episodeSelectedCateogory : Int? var seasonListingData = [SeasonListingDM.Result]() + var seasonEpisodeData = [SeasonEpisodeListingDM.ResultData]() + + var showData : WebSeriesShowListDM.ShowDatum? + func initView(){ getSeasonListing() setupCell() + setShowData() + + vc.shareStack.addTapGesture { + print("share") + } + } + + func setShowData(){ + guard let showData else{return} + vc.totalLikes.text = showData.likesCount?.toString() ?? "0" + if let like = showData.isLiked{ + switch like{ + case true: + vc.likeIcon.image = UIImage(systemName: "hand.thumbsup.fill") + vc.likeLabel.text = "Liked" + case false: + vc.likeIcon.image = UIImage(systemName: "hand.thumbsup") + vc.likeLabel.text = "Like" + } + } + + if let favourite = showData.markAsFavourite{ + if let categoryIds = showData.favouriteCategoryIDS?.rawValue { // if string, it means category is selected for multiple language + let components = categoryIds.components(separatedBy: ",") + if favourite == true && (components.first == categoryID?.toString() || components.last == categoryID?.toString()){ + vc.addIcon.image = UIImage(systemName: "heart.fill") + vc.addLabel.text = "Added" + }else{ + vc.addIcon.image = UIImage(systemName: "heart") + vc.addLabel.text = "Add" + } + return + } + + if favourite == true && showData.favouriteCategoryIDS?.intValue == categoryID{ + vc.addIcon.image = UIImage(systemName: "heart.fill") + vc.addLabel.text = "Added" + }else{ + vc.addIcon.image = UIImage(systemName: "heart") + vc.addLabel.text = "Add" + } +// switch favourite{ +// case true: +// favBtn.setImage(UIImage(systemName: "heart.fill"), for: .normal) +// case false: +// favBtn.setImage(UIImage(systemName: "heart"), for: .normal) +// +// } + } } func setupCell(){ vc.categoryCV.register(UINib(nibName: K.CellIdentifier.WebSeries.seasonCategoryCell, bundle: nil), forCellWithReuseIdentifier: K.CellIdentifier.WebSeries.seasonCategoryCell) vc.categoryCV.delegate = vc.self vc.categoryCV.dataSource = vc.self + + vc.episodeTableView.register(UINib(nibName: K.CellIdentifier.WebSeries.webSeriesEpisodeCell, bundle: nil), forCellReuseIdentifier: K.CellIdentifier.WebSeries.webSeriesEpisodeCell) + vc.episodeTableView.delegate = vc.self + vc.episodeTableView.dataSource = vc.self } // MARK: - Api Calls func getSeasonListing(){ Utilities.startProgressHUD() - guard let watchShowID, let categoryID else{return} + guard let watchShowID = showData?.id, let categoryID else{return} let headers : HTTPHeaders = ["access-token" : AuthFunc.shareInstance.getAccessToken()] let params : Parameters = ["watch_show_id" : watchShowID, "category_id" : categoryID] @@ -57,6 +114,8 @@ class WebSeriesSeasonVM{ guard let data = data.data?.result else{return} self.seasonListingData = data setSeasonData() + episodeSelectedCateogory = seasonListingData.first?.id + getSeasonEpisode() self.vc.categoryCV.reloadData() default: break @@ -99,4 +158,48 @@ class WebSeriesSeasonVM{ vc.seasonEpisodes.text = data.noOfEpisodes?.toString() vc.seasonMediaType.text = data.mediaType } + + func getSeasonEpisode(){ + Utilities.startProgressHUD() + guard let watchShowID = showData?.id, let episodeSelectedCateogory else{return} + let headers : HTTPHeaders = ["access-token" : AuthFunc.shareInstance.getAccessToken()] + let params : Parameters = ["watch_show_id" : watchShowID, + "season_id" : episodeSelectedCateogory] + NetworkManager.shareInstance.apiRequest(url: APIEndPoints.WebSeries.season_episode_listing, 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) + case 1: + Utilities.dismissProgressHUD() + guard let data = data.data?.result else{return} + self.seasonEpisodeData.removeAll() + self.seasonEpisodeData = data + + self.vc.episodeTableView.reloadData() + self.vc.tableHeight.constant = self.vc.episodeTableView.contentSize.height + 100 + self.vc.episodeTableView.layoutIfNeeded() + self.vc.tableHeight.constant = self.vc.episodeTableView.contentSize.height + default: + break + } + case .failure(let error): + guard let self else{ + Utilities.dismissProgressHUD() + return + } + Utilities.dismissProgressHUD() + vc.toast(msg: error.localizedDescription , time: 2) + } + } + } } diff --git a/WOKA/WebSeries/WebSeries.storyboard b/WOKA/WebSeries/WebSeries.storyboard index 4f5de6e..b58737d 100644 --- a/WOKA/WebSeries/WebSeries.storyboard +++ b/WOKA/WebSeries/WebSeries.storyboard @@ -265,7 +265,7 @@ - + @@ -366,9 +366,8 @@ - - + - + - + @@ -513,31 +512,16 @@ - - - - - - + - - - - - - - - + + + - + - + @@ -546,7 +530,7 @@ - + @@ -564,13 +548,23 @@ + + + + + + + + + + @@ -579,7 +573,6 @@ -