diff --git a/WOKA.xcodeproj/project.pbxproj b/WOKA.xcodeproj/project.pbxproj index 864ba9a..332c4bc 100644 --- a/WOKA.xcodeproj/project.pbxproj +++ b/WOKA.xcodeproj/project.pbxproj @@ -13,7 +13,6 @@ 522242662BFC74380085C632 /* MyListVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 522242632BFC74380085C632 /* MyListVC.swift */; }; 522242682BFC74380085C632 /* TabBarVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 522242652BFC74380085C632 /* TabBarVC.swift */; }; 5222426A2BFC7AFC0085C632 /* SideMenuVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 522242692BFC7AFC0085C632 /* SideMenuVC.swift */; }; - 522A93132C0DB5D50098FE49 /* JWPlayerKit in Frameworks */ = {isa = PBXBuildFile; productRef = 522A93122C0DB5D50098FE49 /* JWPlayerKit */; }; 522A931A2C0DE8CC0098FE49 /* SideBarNav.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 522A93192C0DE8CC0098FE49 /* SideBarNav.storyboard */; }; 522A931C2C0DE9150098FE49 /* AboutUsVc.swift in Sources */ = {isa = PBXBuildFile; fileRef = 522A931B2C0DE9150098FE49 /* AboutUsVc.swift */; }; 522D655E2C1ACCF40021E505 /* UserNotificationDM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 522D655D2C1ACCF40021E505 /* UserNotificationDM.swift */; }; @@ -89,6 +88,8 @@ 52A981D02C1AFEE8000E0BEC /* MyListVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52A981CF2C1AFEE8000E0BEC /* MyListVM.swift */; }; 52A981D72C1B0E27000E0BEC /* FavouriteCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52A981D52C1B0E27000E0BEC /* FavouriteCell.swift */; }; 52A981D82C1B0E27000E0BEC /* FavouriteCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 52A981D62C1B0E27000E0BEC /* FavouriteCell.xib */; }; + 52AC2D252C295A7900337473 /* TeaserDM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52AC2D242C295A7900337473 /* TeaserDM.swift */; }; + 52AC2D272C29791500337473 /* JWPlayerManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52AC2D262C29791500337473 /* JWPlayerManager.swift */; }; 52AECA802C08BCB6004A7579 /* PlayerVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52AECA7F2C08BCB6004A7579 /* PlayerVC.swift */; }; 52B8D4D92C04A25E00ED65F3 /* UIViewController+Container.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52B8D4CE2C04A25D00ED65F3 /* UIViewController+Container.swift */; }; 52B8D4DA2C04A25E00ED65F3 /* Preferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52B8D4CF2C04A25D00ED65F3 /* Preferences.swift */; }; @@ -150,6 +151,7 @@ 52D774F12BDFC53B001D87DE /* StringSubScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52D774F02BDFC53B001D87DE /* StringSubScript.swift */; }; 52DAC6482C21762900E2F85B /* WebSeries.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 52DAC6472C21762900E2F85B /* WebSeries.storyboard */; }; 52DAC64E2C21775300E2F85B /* WebSeriesVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52DAC64D2C21775300E2F85B /* WebSeriesVC.swift */; }; + 52E59A922C29AE3F00BB9B04 /* JWPlayerKit in Frameworks */ = {isa = PBXBuildFile; productRef = 52E59A912C29AE3F00BB9B04 /* JWPlayerKit */; }; 52FB2D8F2BDF898F0009B0C7 /* TextFieldPadding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52FB2D8E2BDF898F0009B0C7 /* TextFieldPadding.swift */; }; 52FDBA782BFF23F4009D7AC7 /* TimePeriod.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52FDBA772BFF23F4009D7AC7 /* TimePeriod.swift */; }; 52FDBA7B2BFF2712009D7AC7 /* AuthFuncTimeHandling.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52FDBA7A2BFF2712009D7AC7 /* AuthFuncTimeHandling.swift */; }; @@ -340,6 +342,8 @@ 52A981CF2C1AFEE8000E0BEC /* MyListVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyListVM.swift; sourceTree = ""; }; 52A981D52C1B0E27000E0BEC /* FavouriteCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavouriteCell.swift; sourceTree = ""; }; 52A981D62C1B0E27000E0BEC /* FavouriteCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = FavouriteCell.xib; sourceTree = ""; }; + 52AC2D242C295A7900337473 /* TeaserDM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TeaserDM.swift; sourceTree = ""; }; + 52AC2D262C29791500337473 /* JWPlayerManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JWPlayerManager.swift; sourceTree = ""; }; 52AECA7F2C08BCB6004A7579 /* PlayerVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerVC.swift; sourceTree = ""; }; 52B8D4CE2C04A25D00ED65F3 /* UIViewController+Container.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIViewController+Container.swift"; sourceTree = ""; }; 52B8D4CF2C04A25D00ED65F3 /* Preferences.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Preferences.swift; sourceTree = ""; }; @@ -485,7 +489,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 522A93132C0DB5D50098FE49 /* JWPlayerKit in Frameworks */, + 52E59A922C29AE3F00BB9B04 /* JWPlayerKit in Frameworks */, 9C1C69FA2C106B290035B2C7 /* RSKPlaceholderTextView in Frameworks */, 619A5A1BD8BD968ADC83C106 /* Pods_WOKA.framework in Frameworks */, ); @@ -962,6 +966,7 @@ 52DAC64A2C2176CB00E2F85B /* ViewModel */, 52DAC6492C21767900E2F85B /* Controller */, 52DAC6472C21762900E2F85B /* WebSeries.storyboard */, + 52AC2D262C29791500337473 /* JWPlayerManager.swift */, ); path = WebSeries; sourceTree = ""; @@ -1007,6 +1012,7 @@ 52D6A2532C22B93F00145908 /* CategoryListingDM.swift */, 528E5F1A2C24531200E33E4E /* SeasonListingDM.swift */, 9C007F1F2C255DF200F798C2 /* SeasonEpisodeListingDM.swift */, + 52AC2D242C295A7900337473 /* TeaserDM.swift */, ); path = Model; sourceTree = ""; @@ -1289,8 +1295,8 @@ ); name = WOKA; packageProductDependencies = ( - 522A93122C0DB5D50098FE49 /* JWPlayerKit */, 9C1C69F92C106B290035B2C7 /* RSKPlaceholderTextView */, + 52E59A912C29AE3F00BB9B04 /* JWPlayerKit */, ); productName = WOKA; productReference = 523ED25A2BDA2BC700CFED02 /* WOKA.app */; @@ -1366,8 +1372,8 @@ ); mainGroup = 523ED2512BDA2BC700CFED02; packageReferences = ( - 522A93112C0DB5D50098FE49 /* XCRemoteSwiftPackageReference "JWPlayerKit-package" */, 9C1C69F82C106B290035B2C7 /* XCRemoteSwiftPackageReference "RSKPlaceholderTextView" */, + 52E59A902C29AE3F00BB9B04 /* XCRemoteSwiftPackageReference "JWPlayerKit-package" */, ); productRefGroup = 523ED25B2BDA2BC700CFED02 /* Products */; projectDirPath = ""; @@ -1577,6 +1583,7 @@ 9C56E83B2BDBC6E600E4CA14 /* SelectAgeVM.swift in Sources */, 9C535DC02C00B36000DA6DCD /* HomeVC.swift in Sources */, 52B8D4E22C04A25E00ED65F3 /* Segue.swift in Sources */, + 52AC2D272C29791500337473 /* JWPlayerManager.swift in Sources */, 5259542E2BEA393700191286 /* AlertCustomVC.swift in Sources */, 52CA28FA2BE119F500708B49 /* UserIntrestVC.swift in Sources */, 9CBE1B442C0F37B300CA6E61 /* DropDown+Appearance.swift in Sources */, @@ -1644,6 +1651,7 @@ 52C1A4E12C05B69F007BAA50 /* UIApplicationSwitchRoot.swift in Sources */, 52663FF72BDFACF60001D8CE /* ShadowView.swift in Sources */, 522D65602C1ACD8D0021E505 /* UserNotificationVC.swift in Sources */, + 52AC2D252C295A7900337473 /* TeaserDM.swift in Sources */, 9C535DC22C00B36900DA6DCD /* ThemeTwoVC.swift in Sources */, 9CA7C6C22C1095B600D73742 /* ProfileVM.swift in Sources */, 52D774F12BDFC53B001D87DE /* StringSubScript.swift in Sources */, @@ -2074,7 +2082,7 @@ /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ - 522A93112C0DB5D50098FE49 /* XCRemoteSwiftPackageReference "JWPlayerKit-package" */ = { + 52E59A902C29AE3F00BB9B04 /* XCRemoteSwiftPackageReference "JWPlayerKit-package" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/jwplayer/JWPlayerKit-package.git"; requirement = { @@ -2093,9 +2101,9 @@ /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ - 522A93122C0DB5D50098FE49 /* JWPlayerKit */ = { + 52E59A912C29AE3F00BB9B04 /* JWPlayerKit */ = { isa = XCSwiftPackageProductDependency; - package = 522A93112C0DB5D50098FE49 /* XCRemoteSwiftPackageReference "JWPlayerKit-package" */; + package = 52E59A902C29AE3F00BB9B04 /* XCRemoteSwiftPackageReference "JWPlayerKit-package" */; productName = JWPlayerKit; }; 9C1C69F92C106B290035B2C7 /* RSKPlaceholderTextView */ = { diff --git a/WOKA/Assets/Assets.xcassets/WebSeries/PlayButton.imageset/PlayButton.png b/WOKA/Assets/Assets.xcassets/WebSeries/PlayButton.imageset/PlayButton.png index effc134..ef4bbd3 100644 Binary files a/WOKA/Assets/Assets.xcassets/WebSeries/PlayButton.imageset/PlayButton.png and b/WOKA/Assets/Assets.xcassets/WebSeries/PlayButton.imageset/PlayButton.png differ diff --git a/WOKA/Assets/Assets.xcassets/WebSeries/PlayButton.imageset/PlayButton@2x.png b/WOKA/Assets/Assets.xcassets/WebSeries/PlayButton.imageset/PlayButton@2x.png index 20b5275..96690c0 100644 Binary files a/WOKA/Assets/Assets.xcassets/WebSeries/PlayButton.imageset/PlayButton@2x.png and b/WOKA/Assets/Assets.xcassets/WebSeries/PlayButton.imageset/PlayButton@2x.png differ diff --git a/WOKA/Assets/Assets.xcassets/WebSeries/PlayButton.imageset/PlayButton@3x.png b/WOKA/Assets/Assets.xcassets/WebSeries/PlayButton.imageset/PlayButton@3x.png index 446dd93..58414e0 100644 Binary files a/WOKA/Assets/Assets.xcassets/WebSeries/PlayButton.imageset/PlayButton@3x.png and b/WOKA/Assets/Assets.xcassets/WebSeries/PlayButton.imageset/PlayButton@3x.png differ diff --git a/WOKA/Home/ViewModel/MyListVM.swift b/WOKA/Home/ViewModel/MyListVM.swift index e710cf3..c51aec7 100644 --- a/WOKA/Home/ViewModel/MyListVM.swift +++ b/WOKA/Home/ViewModel/MyListVM.swift @@ -89,10 +89,15 @@ class MyListVM{ // Deleting the hindi series from main (those with category ID "18") for (index, element) in data.enumerated() { if let bookMarkCatID = element.bookmarkCategoryIDS?.components(separatedBy: ","){ - if bookMarkCatID.count > 1{ + if bookMarkCatID.count > 1{ // means multiple language + /* + if its greater than one , its for sure we have extracted the hindi episode + */ hindiData[index].bookmarkCategoryIDS = "1" - }else{ - indicesToRemove.append(index) + }else{ // means single language + if bookMarkCatID.first == "18"{ + indicesToRemove.append(index) + } } } } diff --git a/WOKA/Localized Module/hi.lproj/Localizable.strings b/WOKA/Localized Module/hi.lproj/Localizable.strings index 9b81087..bfb2d32 100644 --- a/WOKA/Localized Module/hi.lproj/Localizable.strings +++ b/WOKA/Localized Module/hi.lproj/Localizable.strings @@ -222,3 +222,6 @@ "Select Video Language" = "वीडियो भाषा चुनें"; "TRAILER" = "ट्रेलर"; +"TEASERS" = "टीज़र"; +"CONTINUE WATCHING" = "देखना जारी रखें"; +"PLAY TRAILER" = "प्ले ट्रेलर"; diff --git a/WOKA/Network Adapter/APIEndPoints.swift b/WOKA/Network Adapter/APIEndPoints.swift index 093993f..16c4aed 100644 --- a/WOKA/Network Adapter/APIEndPoints.swift +++ b/WOKA/Network Adapter/APIEndPoints.swift @@ -21,6 +21,8 @@ struct APIEndPoints { struct BaseURL { static let staging = "https://wokaland.com/admin/api/" static let production = "https://simplitend.com" + + static let appUrl = "https://apps.apple.com/in/app/woka/id6465305185" } struct Auth { @@ -85,6 +87,7 @@ struct APIEndPoints { 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") + static let teaser_listing = makeURL(path: "teaser_listing") } // Other endpoint categories... diff --git a/WOKA/Theme/Controller/PlayerVC.swift b/WOKA/Theme/Controller/PlayerVC.swift index d293b0e..fefe567 100644 --- a/WOKA/Theme/Controller/PlayerVC.swift +++ b/WOKA/Theme/Controller/PlayerVC.swift @@ -16,6 +16,7 @@ class PlayerVC: JWPlayerViewController, JWPlayerViewControllerDelegate { let backButton = UIButton(type: .system) var config: JWPlayerConfiguration! var dismissTapped: (() -> Void)? + var videoIndex : Int? func rotateToLandsScapeDevice(){ let appDelegate = UIApplication.shared.delegate as! AppDelegate @@ -42,16 +43,14 @@ class PlayerVC: JWPlayerViewController, JWPlayerViewControllerDelegate { // UIDevice.current.setValue(UIInterfaceOrientation.portrait.rawValue, forKey: "orientation") UIView.setAnimationsEnabled(true) } + override func viewDidLoad() { super.viewDidLoad() self.rotateToLandsScapeDevice() self.delegate = self player.configurePlayer(with: config) - -// NotificationCenter.default.addObserver(self, selector: #selector(applicationDidBecomeActive), name: UIApplication.willEnterForegroundNotification, object: nil) } - @objc func applicationDidBecomeActive() { self.setDeviceOrientation(orientation: .landscapeRight) } @@ -85,11 +84,13 @@ class PlayerVC: JWPlayerViewController, JWPlayerViewControllerDelegate { override func jwplayer(_ player: any JWPlayer, didFinishLoadingWithTime loadTime: TimeInterval) { super.jwplayer(player, didFinishLoadingWithTime: loadTime) print("LoadTime", loadTime) - self.player.play() +// self.player.play() } override func jwplayerIsReady(_ player: JWPlayer) { super.jwplayerIsReady(player) + player.loadPlayerItemAt(index: 4) + player.seek(to: 30) print("IsReady") } @@ -121,7 +122,7 @@ class PlayerVC: JWPlayerViewController, JWPlayerViewControllerDelegate { override func jwplayer(_ player: JWPlayer, isBufferingWithReason reason: JWBufferReason) { super.jwplayer(player, isBufferingWithReason: reason) - player.play() +// player.play() print("Buffering Reason:", reason) } diff --git a/WOKA/Theme/ViewModel/ThemeOneVM.swift b/WOKA/Theme/ViewModel/ThemeOneVM.swift index 926322b..ff3616c 100644 --- a/WOKA/Theme/ViewModel/ThemeOneVM.swift +++ b/WOKA/Theme/ViewModel/ThemeOneVM.swift @@ -192,60 +192,119 @@ class ThemeOneVM{ vc.liveTVView.isUserInteractionEnabled = true } - // function which is triggered when handleTap is called + // function which is triggered when handleTap on livetv is called @objc func handleTap(_ sender: UITapGestureRecognizer) { Utilities.startProgressHUD(msg: "Loading...") print("tapped") - let vc = self.vc.storyboard?.instantiateViewController(identifier: "PlayerVC") as! PlayerVC + + guard let storyboard = self.vc.storyboard else { + print("Storyboard not found") + Utilities.dismissProgressHUD() + return + } + + guard let vc = storyboard.instantiateViewController(identifier: "PlayerVC") as? PlayerVC else { + print("PlayerVC not found") + Utilities.dismissProgressHUD() + return + } DispatchQueue.main.async { do { - // Create a JWMediaTrack with the thumbnails .vtt file - // let thumbnailTrack = try JWThumbnailTrackBuilder() - // .file(URL(string:"https://content.jwplatform.com/videos/Agy4RIje-Ysj2G4DQ.mp4")!) - // .build() + // Ensure the liveStreamURL is valid + guard let liveStreamURL = URL(string: self.liveStreamURL) else { + print("Invalid live stream URL") + Utilities.dismissProgressHUD() + return + } // Create a JWPlayerItem let item = try JWPlayerItemBuilder() - .file(URL(string: self.liveStreamURL)!) + .file(liveStreamURL) .title("Testing Title") -// .posterImage(URL(string: "https://img.freepik.com/free-photo/painting-mountain-lake-with-mountain-background_188544-9126.jpg")!) - // .mediaTracks([thumbnailTrack]) .build() - // Create a config, and give it the item as a playlist. + // Create a JWPlayerConfiguration let config = try JWPlayerConfigurationBuilder() .playlist(items: [item]) .autostart(true) -// .preload(.auto) -// .repeatContent(true) .build() vc.config = config vc.dismissTapped = self.tapped - vc.modalPresentationStyle = .overFullScreen - Utilities.dismissProgressHUD() + + // Present the PlayerVC self.vc.present(vc, animated: false) { self.stopLiveStream() vc.transitionToFullScreen(animated: true) { print("FullScreen") } - // vc.setDeviceOrientation(orientation: .landscapeRight) } -// Utilities.dismissProgressHUD() -// self.vc.navigationController?.pushViewController(vc, animated: true) -// self.stopLiveStream() - } - catch { - // Handle Error + } catch { + print("Error creating JWPlayer configuration: \(error)") + Utilities.dismissProgressHUD() } + + // Dismiss the progress HUD after the view controller presentation + Utilities.dismissProgressHUD() } } + +// @objc func handleTap(_ sender: UITapGestureRecognizer) { +// Utilities.startProgressHUD(msg: "Loading...") +// print("tapped") +// let vc = self.vc.storyboard?.instantiateViewController(identifier: "PlayerVC") as! PlayerVC +// +// DispatchQueue.main.async { +// do { +// // Create a JWMediaTrack with the thumbnails .vtt file +// // let thumbnailTrack = try JWThumbnailTrackBuilder() +// // .file(URL(string:"https://content.jwplatform.com/videos/Agy4RIje-Ysj2G4DQ.mp4")!) +// // .build() +// +// // Create a JWPlayerItem +// let item = try JWPlayerItemBuilder() +// .file(URL(string: self.liveStreamURL)!) +// .title("Testing Title") +//// .posterImage(URL(string: "https://img.freepik.com/free-photo/painting-mountain-lake-with-mountain-background_188544-9126.jpg")!) +// // .mediaTracks([thumbnailTrack]) +// .build() +// +// // Create a config, and give it the item as a playlist. +// let config = try JWPlayerConfigurationBuilder() +// .playlist(items: [item]) +// .autostart(true) +//// .preload(.auto) +//// .repeatContent(true) +// .build() +// +// vc.config = config +// vc.dismissTapped = self.tapped +// +// vc.modalPresentationStyle = .overFullScreen +// Utilities.dismissProgressHUD() +// self.vc.present(vc, animated: false) { +// self.stopLiveStream() +// vc.transitionToFullScreen(animated: true) { +// print("FullScreen") +// } +// // vc.setDeviceOrientation(orientation: .landscapeRight) +// } +//// Utilities.dismissProgressHUD() +//// self.vc.navigationController?.pushViewController(vc, animated: true) +//// self.stopLiveStream() +// } +// catch { +// // Handle Error +// } +// } +// } func tapped(){ Timer.scheduledTimer(withTimeInterval: 0.2, repeats: false) { _ in - self.startLiveStream() + self.avPlayer.play() + self.moveLiveTVView() self.vc.liveTvPlayer.layoutIfNeeded() } print("Sadasd") diff --git a/WOKA/Theme/ViewModel/ThemeTwoVM.swift b/WOKA/Theme/ViewModel/ThemeTwoVM.swift index af9209a..41441f3 100644 --- a/WOKA/Theme/ViewModel/ThemeTwoVM.swift +++ b/WOKA/Theme/ViewModel/ThemeTwoVM.swift @@ -21,6 +21,9 @@ class ThemeTwoVM{ var avPlayer : AVPlayer! var playerLayer: AVPlayerLayer! + /* + Static cell data + */ var cellData = [Theme2Struct(imageName: "WokaFMT2", text: "WOKA FM"), Theme2Struct(imageName: "LiveTVT2", text: "LIVE TV"), Theme2Struct(imageName: "WebSeriesT2", text: "WEB SERIES"), @@ -31,11 +34,38 @@ class ThemeTwoVM{ func initView(){ setupCell() - NotificationCenter.default.addObserver(self, selector: #selector(self.reloadTheme), name: NSNotification.Name(rawValue: K.NotificationCenterReloads.reloadTheme), object: nil) setupAvPlayer() setUserData() + + handleNotificationCenter() } + private func handleNotificationCenter(){ + NotificationCenter.default.addObserver(self, selector: #selector(self.reloadTheme), name: NSNotification.Name(rawValue: K.NotificationCenterReloads.reloadTheme), object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(appDidEnterBackground), name: UIApplication.didEnterBackgroundNotification, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(appWillEnterForeground), name: UIApplication.willEnterForegroundNotification, object: nil) + } + + // MARK: - Notification Center Handlers + + @objc func reloadTheme(){ + self.vc.delegate?.didPressSwitchButton(from: self.vc) + } + + @objc func appDidEnterBackground() { + // Code to execute when the app enters the background + print("App entered background") + self.avPlayer.pause() + } + + @objc func appWillEnterForeground() { + // Code to execute when the app enters the foreground + print("App will enter foreground") + self.avPlayer.play() + } + + // MARK: - Live TV + func playLiveTV(){ Utilities.startProgressHUD(msg: "Loading...") print("tapped") @@ -177,11 +207,7 @@ class ThemeTwoVM{ } - // MARK: - Notification Center Handlers - - @objc func reloadTheme(){ - self.vc.delegate?.didPressSwitchButton(from: self.vc) - } + // MARK: - SetupCell func setupCell(){ vc.collectionView.register(UINib(nibName: K.CellIdentifier.Theme.homeExploreCell, bundle: nil), forCellWithReuseIdentifier: K.CellIdentifier.Theme.homeExploreCell) diff --git a/WOKA/WebSeries/Controller/WebSeriesSeasonVC.swift b/WOKA/WebSeries/Controller/WebSeriesSeasonVC.swift index d87546d..c689fbc 100644 --- a/WOKA/WebSeries/Controller/WebSeriesSeasonVC.swift +++ b/WOKA/WebSeries/Controller/WebSeriesSeasonVC.swift @@ -19,9 +19,16 @@ class WebSeriesSeasonVC: UIViewController { @IBOutlet weak var seasonDesc: UILabel! @IBOutlet weak var categoryCV: UICollectionView! + + //Episode Outlet + @IBOutlet weak var episodeTitle: UILabel! @IBOutlet weak var episodeTableView: UITableView! @IBOutlet weak var tableHeight: NSLayoutConstraint! + //Teaser Outlet + @IBOutlet weak var teaserTableView: UITableView! + @IBOutlet weak var teaserTableHeight: NSLayoutConstraint! + @IBOutlet weak var teaserTitle: LocalisedElementsLabel! @IBOutlet weak var addIcon: UIImageView! @IBOutlet weak var addLabel: UILabel! @@ -63,13 +70,23 @@ class WebSeriesSeasonVC: UIViewController { @IBAction func watchBtnTapped(_ sender: LocalisedElementsButton) { } + @IBAction func retryBtnTapped(_ sender: LocalisedElementsButton) { + } + } // MARK: - TableView DataSource , Delegates extension WebSeriesSeasonVC : TableViewSRC{ func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return vm.seasonEpisodeData.count + switch tableView{ + case episodeTableView: + return vm.seasonEpisodeData.first?.episodeData?.count ?? 0 + case teaserTableView: + return vm.teaserData.count + default: + return 0 + } } func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { @@ -78,9 +95,34 @@ extension WebSeriesSeasonVC : TableViewSRC{ func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: K.CellIdentifier.WebSeries.webSeriesEpisodeCell) as! WebSeriesEpisodeCell + switch tableView{ + case episodeTableView: + if let data = vm.seasonEpisodeData.first?.episodeData?[indexPath.row]{ + cell.setData(data: data) + } + case teaserTableView: + let data = vm.teaserData[indexPath.row] + cell.setTeaserData(data: data) + default: + break + } + + cell.btnTapped = { [self] () -> Void in + var urls = [String]() + var title = [String]() + if let episodeData = vm.seasonEpisodeData.first?.episodeData{ + for i in episodeData{ + urls.append(i.episodeURL ?? "") + title.append(i.episodeTitle ?? "Episode") + } + } + + if let data = vm.seasonEpisodeData.first?.episodeData?[indexPath.row] , let url = data.episodeURL{ + JWPlayerManager.shared.presentPlayer(from: self, withURLs: urls, titles: title,startIndex: indexPath.row) + } + + } - let data = vm.seasonEpisodeData[indexPath.row] - cell.setData(data: data) return cell } } @@ -103,7 +145,11 @@ extension WebSeriesSeasonVC : CollectionViewSRC{ func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { vm.episodeSelectedCateogory = vm.seasonListingData[indexPath.row].id + vm.setSeasonData() + episodeTitle.isHidden = false + episodeTitle.text = "" vm.getSeasonEpisode() + vm.getTeaserListing() self.categoryCV.reloadData() } } diff --git a/WOKA/WebSeries/Controller/WebSeriesVC.swift b/WOKA/WebSeries/Controller/WebSeriesVC.swift index a36e050..8c942c4 100644 --- a/WOKA/WebSeries/Controller/WebSeriesVC.swift +++ b/WOKA/WebSeries/Controller/WebSeriesVC.swift @@ -60,6 +60,9 @@ class WebSeriesVC: UIViewController { // MARK: - Tap Handler + @IBAction func playTrailer(_ sender: LocalisedElementsButton) { + } + @IBAction func expandLanguageTapped(_ sender: UIButton) { vm.dropDownModule.show() self.expandBtn.setImage(UIImage(named: "SupportUpArrow"), for: .normal) diff --git a/WOKA/WebSeries/JWPlayerManager.swift b/WOKA/WebSeries/JWPlayerManager.swift new file mode 100644 index 0000000..f352e4a --- /dev/null +++ b/WOKA/WebSeries/JWPlayerManager.swift @@ -0,0 +1,141 @@ +// +// JWPlayerManager.swift +// WOKA +// +// Created by MacBook Pro on 24/06/24. +// + +import UIKit +import JWPlayerKit + +class JWPlayerManager { + static let shared = JWPlayerManager() + + private init() {} + + func presentPlayer(from viewController: UIViewController, withURLs liveStreamURLs: [String], titles: [String]? = nil, startIndex: Int = 0, completion: (() -> Void)? = nil) { + DispatchQueue.main.async { + Utilities.startProgressHUD(msg: "Loading...") + } + + let sb = UIStoryboard(name: K.StoryBoard.theme, bundle: nil) + guard let playerVC = sb.instantiateViewController(identifier: "PlayerVC") as? PlayerVC else { + print("PlayerVC not found") + Utilities.dismissProgressHUD() + return + } + + DispatchQueue.main.async { + do { + // Create an array to hold the JWPlayerItems + var items: [JWPlayerItem] = [] + + // Ensure the liveStreamURLs and titles arrays have the same count, if titles are provided + if let titles = titles, titles.count != liveStreamURLs.count { + print("Titles count does not match URLs count") + Utilities.dismissProgressHUD() + return + } + + // Iterate over the liveStreamURLs to create JWPlayerItems + for (index, urlString) in liveStreamURLs.enumerated() { + guard let url = URL(string: urlString) else { + print("Invalid live stream URL at index \(index)") + continue + } + + // Use the corresponding title if provided, otherwise use a default title + let itemTitle = titles?[index] ?? "Default Title \(index + 1)" + let item = try JWPlayerItemBuilder() + .file(url) + .title(itemTitle) + .build() + + items.append(item) + } + + // Ensure there is at least one valid item + guard !items.isEmpty else { + print("No valid items to play") + Utilities.dismissProgressHUD() + return + } + + // Create a JWPlayerConfiguration with the playlist + let config = try JWPlayerConfigurationBuilder() + .playlist(items: items) + .autostart(false) + .build() + + playerVC.videoIndex = startIndex + playerVC.config = config + playerVC.modalPresentationStyle = .overFullScreen + + // Present the PlayerVC + viewController.present(playerVC, animated: false) { + completion?() + playerVC.transitionToFullScreen(animated: true) { + print("FullScreen") + } + } + } catch { + print("Error creating JWPlayer configuration: \(error)") + Utilities.dismissProgressHUD() + } + + // Dismiss the progress HUD after the view controller presentation + Utilities.dismissProgressHUD() + } + } + +// func presentPlayer(from viewController: UIViewController, withURL liveStreamURL: String, title: String = "Testing Title", completion: (() -> Void)? = nil) { +// Utilities.startProgressHUD(msg: "Loading...") +// +// let sb = UIStoryboard(name: K.StoryBoard.theme, bundle: nil) +// guard let playerVC = sb.instantiateViewController(identifier: "PlayerVC") as? PlayerVC else { +// print("PlayerVC not found") +// Utilities.dismissProgressHUD() +// return +// } +// +// DispatchQueue.main.async { +// do { +// // Ensure the liveStreamURL is valid +// guard let url = URL(string: liveStreamURL) else { +// print("Invalid live stream URL") +// Utilities.dismissProgressHUD() +// return +// } +// +// // Create a JWPlayerItem +// let item = try JWPlayerItemBuilder() +// .file(url) +// .title(title) +// .build() +// +// // Create a JWPlayerConfiguration +// let config = try JWPlayerConfigurationBuilder() +// .playlist(items: [item]) +// .autostart(true) +// .build() +// +// playerVC.config = config +// playerVC.modalPresentationStyle = .overFullScreen +// +// // Present the PlayerVC +// viewController.present(playerVC, animated: false) { +// completion?() +// playerVC.transitionToFullScreen(animated: true) { +// print("FullScreen") +// } +// } +// } catch { +// print("Error creating JWPlayer configuration: \(error)") +// Utilities.dismissProgressHUD() +// } +// +// // Dismiss the progress HUD after the view controller presentation +// Utilities.dismissProgressHUD() +// } +// } +} diff --git a/WOKA/WebSeries/Model/TeaserDM.swift b/WOKA/WebSeries/Model/TeaserDM.swift new file mode 100644 index 0000000..9e94a72 --- /dev/null +++ b/WOKA/WebSeries/Model/TeaserDM.swift @@ -0,0 +1,85 @@ +// +// TeaserDM.swift +// WOKA +// +// Created by MacBook Pro on 24/06/24. +// + +import Foundation + +// MARK: - TeaserDM +struct TeaserDM: Codable { + let result: [ResultData]? + let totalRecords: Int? + + enum CodingKeys: String, CodingKey { + case result + case totalRecords = "total_records" + } + + // MARK: - ResultData + struct ResultData: Codable { + let id, watchShowsMasterID, seasonMasterID, teaserNumber: Int? + let serialNumber: Int? + let teaserTitle, teaserDescription: String? + let thumbnailPath: String? + let thumbnailImgURL: String? + let teaserURL: String? + let languageMasterID: Int? + let tagsKeyword, teaserDuration, releaseDate: String? + let contentMoreDetails: [ContentMoreDetail]? + let seasonData: SeasonData? +// let userVideoView: [JSONAny]? + + enum CodingKeys: String, CodingKey { + case id + case watchShowsMasterID = "watch_shows_master_id" + case seasonMasterID = "season_master_id" + case teaserNumber = "teaser_number" + case serialNumber = "serial_number" + case teaserTitle = "teaser_title" + case teaserDescription = "teaser_description" + case thumbnailPath = "thumbnail_path" + case thumbnailImgURL = "thumbnail_img_url" + case teaserURL = "teaser_url" + case languageMasterID = "language_master_id" + case tagsKeyword = "tags_keyword" + case teaserDuration = "teaser_duration" + case releaseDate = "release_date" + case contentMoreDetails = "content_more_details" + case seasonData = "season_data" +// case userVideoView = "user_video_view" + } + } + + // MARK: - ContentMoreDetail + struct ContentMoreDetail: Codable { + let id, contentID, postType, languageMasterID: Int? + let title, description, tagsKeywords: String? + let contentHDURL, contentSDURL: 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" + } + } + + // MARK: - SeasonData + struct SeasonData: Codable { + let id, watchShowsMasterID: Int? + let seasonNumber: String? + + enum CodingKeys: String, CodingKey { + case id + case watchShowsMasterID = "watch_shows_master_id" + case seasonNumber = "season_number" + } + } + +} diff --git a/WOKA/WebSeries/View/WebSeriesEpisodeCell.swift b/WOKA/WebSeries/View/WebSeriesEpisodeCell.swift index a5825dd..cdb3e91 100644 --- a/WOKA/WebSeries/View/WebSeriesEpisodeCell.swift +++ b/WOKA/WebSeries/View/WebSeriesEpisodeCell.swift @@ -14,8 +14,12 @@ class WebSeriesEpisodeCell: UITableViewCell { @IBOutlet weak var seasonTime: UILabel! @IBOutlet weak var playBtn: UIButton! + typealias btnTappedBlock = () -> Void // 0 - plus 1 - minus + var btnTapped : btnTappedBlock! + override func awakeFromNib() { super.awakeFromNib() + // Initialization code } @@ -25,18 +29,37 @@ class WebSeriesEpisodeCell: UITableViewCell { // Configure the view for the selected state } - func setData(data : SeasonEpisodeListingDM.ResultData){ + func setData(data : SeasonEpisodeListingDM.EpisodeDatum){ if let url = data.thumbnailPath{ self.seasonImage.imageURL(url, color: UIColor.appColor(.TextDarkBlue)!) } + self.seasonTime.text = data.episodeDuration ?? "0:00:00" + if AuthFunc.shareInstance.getDefaultLanguage() == .english{ - seasonTitle.text = data.seasonMoreDetails?.filter({$0.languageMasterID == 1}).first?.title + seasonTitle.text = data.contentMoreDetails?.filter({$0.languageMasterID == 1}).first?.title }else{ - seasonTitle.text = data.seasonMoreDetails?.filter({$0.languageMasterID == 2}).first?.title + seasonTitle.text = data.contentMoreDetails?.filter({$0.languageMasterID == 2}).first?.title + } + } + + func setTeaserData(data : TeaserDM.ResultData){ + if let url = data.thumbnailPath{ + self.seasonImage.imageURL(url, color: UIColor.appColor(.TextDarkBlue)!) + } + + self.seasonTime.text = data.teaserDuration ?? "0:00:00" + + if AuthFunc.shareInstance.getDefaultLanguage() == .english{ + seasonTitle.text = data.contentMoreDetails?.filter({$0.languageMasterID == 1}).first?.title + }else{ + seasonTitle.text = data.contentMoreDetails?.filter({$0.languageMasterID == 2}).first?.title } } @IBAction func playBtnTapped(_ sender: UIButton) { + if btnTapped != nil { + btnTapped() + } } } diff --git a/WOKA/WebSeries/View/WebSeriesEpisodeCell.xib b/WOKA/WebSeries/View/WebSeriesEpisodeCell.xib index 31f9d70..8e7de22 100644 --- a/WOKA/WebSeries/View/WebSeriesEpisodeCell.xib +++ b/WOKA/WebSeries/View/WebSeriesEpisodeCell.xib @@ -6,7 +6,6 @@ - @@ -42,10 +41,10 @@ - + - - - - - - + @@ -115,12 +104,9 @@ Episodes - + - - - diff --git a/WOKA/WebSeries/ViewModel/WebSeriesSeasonVM.swift b/WOKA/WebSeries/ViewModel/WebSeriesSeasonVM.swift index 234bfa3..4e5375e 100644 --- a/WOKA/WebSeries/ViewModel/WebSeriesSeasonVM.swift +++ b/WOKA/WebSeries/ViewModel/WebSeriesSeasonVM.swift @@ -12,7 +12,6 @@ class WebSeriesSeasonVM{ weak var vc : WebSeriesSeasonVC! -// var watchShowID : Int? var categoryID : Int? var episodeSelectedCateogory : Int? @@ -21,6 +20,8 @@ class WebSeriesSeasonVM{ var seasonEpisodeData = [SeasonEpisodeListingDM.ResultData]() + var teaserData = [TeaserDM.ResultData]() + var showData : WebSeriesShowListDM.ShowDatum? func initView(){ @@ -67,13 +68,6 @@ class WebSeriesSeasonVM{ 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) -// -// } } } @@ -85,6 +79,10 @@ class WebSeriesSeasonVM{ 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 + + vc.teaserTableView.register(UINib(nibName: K.CellIdentifier.WebSeries.webSeriesEpisodeCell, bundle: nil), forCellReuseIdentifier: K.CellIdentifier.WebSeries.webSeriesEpisodeCell) + vc.teaserTableView.delegate = vc.self + vc.teaserTableView.dataSource = vc.self } // MARK: - Api Calls @@ -113,9 +111,10 @@ class WebSeriesSeasonVM{ Utilities.dismissProgressHUD() guard let data = data.data?.result else{return} self.seasonListingData = data - setSeasonData() episodeSelectedCateogory = seasonListingData.first?.id + setSeasonData() getSeasonEpisode() + getTeaserListing() self.vc.categoryCV.reloadData() default: break @@ -132,12 +131,12 @@ class WebSeriesSeasonVM{ } func setSeasonData(){ - guard let data = seasonListingData.first else{return} + guard let data = seasonListingData.filter({$0.id == episodeSelectedCateogory}).first else{return} vc.seasonImage.imageURL(data.thumbnailPath!, color: UIColor.appColor(.TextDarkBlue)!) if AuthFunc.shareInstance.getDefaultLanguage() == .english{ let englishData = data.seasonMoreDetails?.filter({$0.languageMasterID == 1}).first - vc.seasonTitle.text = englishData?.title + vc.seasonTitle.text = (englishData?.title ?? "NA") + "\n" + (data.seasonNumber ?? "NA") if let desc = englishData?.description?.replacingOccurrences(of: "
", with: "").htmlToAttributedString{ let sizeText = NSMutableAttributedString(attributedString: desc) @@ -146,7 +145,7 @@ class WebSeriesSeasonVM{ } }else{ let hindiData = data.seasonMoreDetails?.filter({$0.languageMasterID == 2}).first - vc.seasonTitle.text = hindiData?.title + vc.seasonTitle.text = (hindiData?.title ?? "NA") + "\n" + (data.seasonNumber ?? "NA") 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)!) @@ -184,6 +183,16 @@ class WebSeriesSeasonVM{ guard let data = data.data?.result else{return} self.seasonEpisodeData.removeAll() self.seasonEpisodeData = data + self.seasonEpisodeData = self.seasonEpisodeData.filter { + $0.episodeData != nil && !$0.episodeData!.isEmpty + } + if self.seasonEpisodeData.count == 0{ + self.vc.episodeTitle.isHidden = true + self.vc.episodeTitle.text = "" + }else{ + self.vc.episodeTitle.isHidden = false + self.vc.episodeTitle.text = data.first?.mediaType?.uppercased() + } self.vc.episodeTableView.reloadData() self.vc.tableHeight.constant = self.vc.episodeTableView.contentSize.height + 100 @@ -202,4 +211,54 @@ class WebSeriesSeasonVM{ } } } + + func getTeaserListing(){ + guard let watchShowID = showData?.id, let episodeSelectedCateogory else{return} + let headers : HTTPHeaders = ["access-token" : AuthFunc.shareInstance.getAccessToken()] + let params : Parameters = ["watch_show_master_id" : watchShowID, + "season_master_id" : episodeSelectedCateogory] + NetworkManager.shareInstance.apiRequest(url: APIEndPoints.WebSeries.teaser_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() + self.teaserData.removeAll() + self.reloadTeaserTable() + self.vc.teaserTitle.isHidden = true +// vc.toast(msg: data.message ?? "Unrecognised error" , time: 2) + case 1: + Utilities.dismissProgressHUD() + guard let data = data.data?.result else{return} + self.teaserData.removeAll() + self.teaserData = data + self.reloadTeaserTable() + self.vc.teaserTitle.isHidden = false + default: + break + } + case .failure(let error): + guard let self else{ + Utilities.dismissProgressHUD() + return + } + Utilities.dismissProgressHUD() + vc.toast(msg: error.localizedDescription , time: 2) + } + } + } + + private func reloadTeaserTable(){ + self.vc.teaserTableView.reloadData() + self.vc.teaserTableHeight.constant = self.vc.teaserTableView.contentSize.height + 100 + self.vc.teaserTableView.layoutIfNeeded() + self.vc.teaserTableHeight.constant = self.vc.teaserTableView.contentSize.height + } } diff --git a/WOKA/WebSeries/WebSeries.storyboard b/WOKA/WebSeries/WebSeries.storyboard index b58737d..7d79d24 100644 --- a/WOKA/WebSeries/WebSeries.storyboard +++ b/WOKA/WebSeries/WebSeries.storyboard @@ -35,14 +35,42 @@ + + + @@ -103,7 +131,7 @@