From 9ca7c1e4b0064f9302e853df7a64e13162ce43c4 Mon Sep 17 00:00:00 2001 From: Bilal Date: Sat, 17 Aug 2024 01:34:28 +0530 Subject: [PATCH] competed user video view --- WOKA.xcodeproj/project.pbxproj | 24 +- WOKA/Address/Address.storyboard | 22 +- WOKA/Address/Controller/AddressListVC.swift | 5 + WOKA/Address/ViewModel/AddressListVM.swift | 12 + WOKA/Audio Books/AudioBookDetailsVC.swift | 4 +- WOKA/Audio Books/AudioBookHomeVC.swift | 15 +- WOKA/Constants K/ConstantString.swift | 2 + WOKA/Constants K/GVar.swift | 4 + WOKA/Games/Controller/GamesDetailVC.swift | 6 +- WOKA/Games/Controller/GamesWebViewVC.swift | 42 ++- WOKA/Helpers/DateFormatterLib.swift | 16 ++ WOKA/Home/Controller/MyListVC.swift | 4 + WOKA/Home/Home.storyboard | 53 +++- WOKA/Home/ViewModel/MyListVM.swift | 17 +- .../Controller/JWKaraokePlayerVC.swift | 70 ++++- .../Karaoke/Controller/KaraokeListingVC.swift | 7 + .../Karaoke/ViewModel/JWKaraokePlayerVM.swift | 16 ++ .../Main/AuthFunc/AuthFuncUserVideoView.swift | 45 ++++ WOKA/Network Adapter/APIEndPoints.swift | 1 + WOKA/PersistentStorage.swift | 151 +++++------ WOKA/Theme/Base.lproj/Theme.storyboard | 12 +- WOKA/Theme/Controller/MoreVC.swift | 86 +++---- WOKA/Theme/Controller/PlayerVC.swift | 241 +++++++++++------- WOKA/Theme/Controller/ThemeOneVC.swift | 2 + WOKA/Theme/Controller/ThemeTwoVC.swift | 6 +- WOKA/Theme/ViewModel/MoreVM.swift | 9 +- WOKA/Theme/ViewModel/PlayerVM.swift | 172 +++++++++++++ WOKA/Theme/ViewModel/ThemeOneVM.swift | 5 +- WOKA/WOKAFM/Controller/WokaFMVC.swift | 52 ++-- WOKA/WOKAFM/ViewModel/WokaFMVM.swift | 3 + WOKA/WOKAFM/WokaFM.storyboard | 1 - .../Controller/ContinueWatchingVC.swift | 6 +- .../Controller/WebSeriesSeasonVC.swift | 66 ++--- WOKA/WebSeries/Controller/WebSeriesVC.swift | 19 +- WOKA/WebSeries/JWPlayerManager.swift | 5 +- 35 files changed, 857 insertions(+), 344 deletions(-) create mode 100644 WOKA/Main/AuthFunc/AuthFuncUserVideoView.swift create mode 100644 WOKA/Theme/ViewModel/PlayerVM.swift diff --git a/WOKA.xcodeproj/project.pbxproj b/WOKA.xcodeproj/project.pbxproj index c5f690f..6843e8b 100644 --- a/WOKA.xcodeproj/project.pbxproj +++ b/WOKA.xcodeproj/project.pbxproj @@ -103,7 +103,6 @@ 527AC6FD2C173A5100434FB7 /* SongListCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 527AC6FB2C173A5100434FB7 /* SongListCell.swift */; }; 527AC6FE2C173A5100434FB7 /* SongListCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 527AC6FC2C173A5100434FB7 /* SongListCell.xib */; }; 527AC7012C182DCE00434FB7 /* TimeStringToSeconds.swift in Sources */ = {isa = PBXBuildFile; fileRef = 527AC7002C182DCE00434FB7 /* TimeStringToSeconds.swift */; }; - 527CA43A2C6C7FBF00EEDD91 /* WOKA.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 527CA4382C6C7FBE00EEDD91 /* WOKA.xcdatamodeld */; }; 528BEF602C2C372900FFDAB8 /* ContinueWatchingVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 528BEF5F2C2C372900FFDAB8 /* ContinueWatchingVC.swift */; }; 528E5F1B2C24531200E33E4E /* SeasonListingDM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 528E5F1A2C24531200E33E4E /* SeasonListingDM.swift */; }; 528E5F222C24660F00E33E4E /* SeasonCategoryCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 528E5F202C24660F00E33E4E /* SeasonCategoryCell.swift */; }; @@ -338,6 +337,9 @@ 9CBE1B432C0F37B300CA6E61 /* DropDown.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CBE1B382C0F37B200CA6E61 /* DropDown.swift */; }; 9CBE1B442C0F37B300CA6E61 /* DropDown+Appearance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CBE1B392C0F37B200CA6E61 /* DropDown+Appearance.swift */; }; 9CBE1B452C0F37B300CA6E61 /* DropDownCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CBE1B3A2C0F37B200CA6E61 /* DropDownCell.swift */; }; + 9CC0D2F82C6F339D0019DF73 /* WOKA.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 9CC0D2F62C6F339D0019DF73 /* WOKA.xcdatamodeld */; }; + 9CC0D2FA2C6F33BE0019DF73 /* AuthFuncUserVideoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CC0D2F92C6F33BE0019DF73 /* AuthFuncUserVideoView.swift */; }; + 9CC0D2FC2C6F5CAE0019DF73 /* PlayerVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CC0D2FB2C6F5CAE0019DF73 /* PlayerVM.swift */; }; 9CDAEB032C53B97B00890C47 /* VersionTexts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CDAEB022C53B97B00890C47 /* VersionTexts.swift */; }; 9CDAEB052C53DB2900890C47 /* ProductDetailsVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CDAEB042C53DB2900890C47 /* ProductDetailsVC.swift */; }; 9CDAEB072C53E42900890C47 /* ProductDetailsVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CDAEB062C53E42900890C47 /* ProductDetailsVM.swift */; }; @@ -494,7 +496,6 @@ 527AC6FB2C173A5100434FB7 /* SongListCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SongListCell.swift; sourceTree = ""; }; 527AC6FC2C173A5100434FB7 /* SongListCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SongListCell.xib; sourceTree = ""; }; 527AC7002C182DCE00434FB7 /* TimeStringToSeconds.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeStringToSeconds.swift; sourceTree = ""; }; - 527CA4392C6C7FBE00EEDD91 /* WOKA.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = WOKA.xcdatamodel; sourceTree = ""; }; 528BEF5F2C2C372900FFDAB8 /* ContinueWatchingVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContinueWatchingVC.swift; sourceTree = ""; }; 528E5F1A2C24531200E33E4E /* SeasonListingDM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeasonListingDM.swift; sourceTree = ""; }; 528E5F202C24660F00E33E4E /* SeasonCategoryCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeasonCategoryCell.swift; sourceTree = ""; }; @@ -719,6 +720,9 @@ 9CBE1B392C0F37B200CA6E61 /* DropDown+Appearance.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DropDown+Appearance.swift"; sourceTree = ""; }; 9CBE1B3A2C0F37B200CA6E61 /* DropDownCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DropDownCell.swift; sourceTree = ""; }; 9CBE1B3C2C0F37B200CA6E61 /* DropDown.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DropDown.h; sourceTree = ""; }; + 9CC0D2F72C6F339D0019DF73 /* WOKA.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = WOKA.xcdatamodel; sourceTree = ""; }; + 9CC0D2F92C6F33BE0019DF73 /* AuthFuncUserVideoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthFuncUserVideoView.swift; sourceTree = ""; }; + 9CC0D2FB2C6F5CAE0019DF73 /* PlayerVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerVM.swift; sourceTree = ""; }; 9CDAEB022C53B97B00890C47 /* VersionTexts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VersionTexts.swift; sourceTree = ""; }; 9CDAEB042C53DB2900890C47 /* ProductDetailsVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductDetailsVC.swift; sourceTree = ""; }; 9CDAEB062C53E42900890C47 /* ProductDetailsVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductDetailsVM.swift; sourceTree = ""; }; @@ -930,7 +934,7 @@ 9C535DC82C00C34000DA6DCD /* Theme */, 52DAC6462C21761700E2F85B /* WebSeries */, 9C834ED92C1C20EC00B29A9C /* WOKA.entitlements */, - 527CA4382C6C7FBE00EEDD91 /* WOKA.xcdatamodeld */, + 9CC0D2F62C6F339D0019DF73 /* WOKA.xcdatamodeld */, 52ACC1292C610EC900791528 /* PersistentStorage.swift */, ); path = WOKA; @@ -1656,6 +1660,7 @@ 9C27E1622BDB6F1900EC1DA9 /* AuthFunc.swift */, 525327D82BFCDDF700F64283 /* AuthFuncStartupSoundHandling.swift */, 52FDBA7A2BFF2712009D7AC7 /* AuthFuncTimeHandling.swift */, + 9CC0D2F92C6F33BE0019DF73 /* AuthFuncUserVideoView.swift */, ); path = AuthFunc; sourceTree = ""; @@ -1731,6 +1736,7 @@ 524C422A2C04781B0016A11C /* ThemeTwoVM.swift */, 52BC3BF12C170264002FACA6 /* MoreVM.swift */, 529CFEED2C60F49000B0B380 /* UserNotificationVM.swift */, + 9CC0D2FB2C6F5CAE0019DF73 /* PlayerVM.swift */, ); path = ViewModel; sourceTree = ""; @@ -2314,7 +2320,7 @@ 52A6DCA02C4E3AA600F63C51 /* ShopListingCell.swift in Sources */, 525954192BE8CC3400191286 /* ConstantString.swift in Sources */, 52D774EB2BDFC0BF001D87DE /* OTPVC.swift in Sources */, - 527CA43A2C6C7FBF00EEDD91 /* WOKA.xcdatamodeld in Sources */, + 9CC0D2F82C6F339D0019DF73 /* WOKA.xcdatamodeld in Sources */, 9C8446872C40FC6E003E3E53 /* AVPlayerTesting.swift in Sources */, 52AF71F42C36C40B00BC5972 /* GamesWebViewVC.swift in Sources */, 9C007F202C255DF200F798C2 /* EpisodeListingDM.swift in Sources */, @@ -2327,6 +2333,7 @@ 525861DE2C4FE7A100C33C79 /* CouponCell.swift in Sources */, 9C27E1632BDB6F1900EC1DA9 /* AuthFunc.swift in Sources */, 9C0A85412BEE35670093783D /* ResetPassUserNameVM.swift in Sources */, + 9CC0D2FA2C6F33BE0019DF73 /* AuthFuncUserVideoView.swift in Sources */, 52C6E0292BE3B52500E22D59 /* SelectAvatarVM.swift in Sources */, 9CDAEB032C53B97B00890C47 /* VersionTexts.swift in Sources */, 52C8B0592BDA57FA003B51D0 /* StaticFilesString.swift in Sources */, @@ -2493,6 +2500,7 @@ 5258464F2C491829004F074B /* connectedness.swift in Sources */, 9CBE1B452C0F37B300CA6E61 /* DropDownCell.swift in Sources */, 9C27E16D2BDB852F00EC1DA9 /* GVar.swift in Sources */, + 9CC0D2FC2C6F5CAE0019DF73 /* PlayerVM.swift in Sources */, 52B8D4E02C04A25E00ED65F3 /* UIView+Container.swift in Sources */, 527A2BCA2C57776A0080DF9B /* AddNewAddressVC.swift in Sources */, 9C56E8462BDBEE6400E4CA14 /* EmailVC.swift in Sources */, @@ -3070,14 +3078,14 @@ /* End XCSwiftPackageProductDependency section */ /* Begin XCVersionGroup section */ - 527CA4382C6C7FBE00EEDD91 /* WOKA.xcdatamodeld */ = { + 9CC0D2F62C6F339D0019DF73 /* WOKA.xcdatamodeld */ = { isa = XCVersionGroup; children = ( - 527CA4392C6C7FBE00EEDD91 /* WOKA.xcdatamodel */, + 9CC0D2F72C6F339D0019DF73 /* WOKA.xcdatamodel */, ); - currentVersion = 527CA4392C6C7FBE00EEDD91 /* WOKA.xcdatamodel */; + currentVersion = 9CC0D2F72C6F339D0019DF73 /* WOKA.xcdatamodel */; name = WOKA.xcdatamodeld; - path = /Users/macbookpro/Desktop/WOKA/WOKA/WOKA.xcdatamodeld; + path = /Users/bilal/Desktop/woka_native_ios_swift/WOKA/WOKA.xcdatamodeld; sourceTree = ""; versionGroupType = wrapper.xcdatamodel; }; diff --git a/WOKA/Address/Address.storyboard b/WOKA/Address/Address.storyboard index 591d7f0..46f76d6 100644 --- a/WOKA/Address/Address.storyboard +++ b/WOKA/Address/Address.storyboard @@ -549,19 +549,36 @@ + + + + @@ -582,7 +599,7 @@ - + @@ -636,6 +653,7 @@ + @@ -643,7 +661,7 @@ - + diff --git a/WOKA/Address/Controller/AddressListVC.swift b/WOKA/Address/Controller/AddressListVC.swift index 409689e..96c5ff2 100644 --- a/WOKA/Address/Controller/AddressListVC.swift +++ b/WOKA/Address/Controller/AddressListVC.swift @@ -13,6 +13,7 @@ class AddressListVC: UIViewController { @IBOutlet weak var tableView: UITableView! @IBOutlet weak var useSelectedAddBtn : LocalisedElementsButton! @IBOutlet weak var addNewAddressBtn : LocalisedElementsButton! + @IBOutlet weak var noDataStack: UIStackView! var vm = AddressListVM() @@ -61,6 +62,10 @@ class AddressListVC: UIViewController { switch sender{ case useSelectedAddBtn: + if CartDataCache.addressData.count == 0{ + self.toast(msg: "Please add address", time: 1.5) + return + } if let addressID = CartDataCache.addressData.filter({$0.isDefault == true}).first?.id{ vm.createOrder(addressID: addressID, couponCode: vm.couponCodeApplied) } diff --git a/WOKA/Address/ViewModel/AddressListVM.swift b/WOKA/Address/ViewModel/AddressListVM.swift index b8bd843..29c40eb 100644 --- a/WOKA/Address/ViewModel/AddressListVM.swift +++ b/WOKA/Address/ViewModel/AddressListVM.swift @@ -64,6 +64,7 @@ class AddressListVM{ Error */ Utilities.dismissProgressHUD() + self.checkForNoData() case 1: Utilities.dismissProgressHUD() guard let data = data.data else{return} @@ -73,6 +74,7 @@ class AddressListVM{ CartDataCache.addressData[0].isAnimating = true } self.vc.tableView.reloadData() + self.checkForNoData() if let pincode = CartDataCache.addressData.first?.pincode , let id = CartDataCache.addressData.first?.id{ checkEstimatedDeliveryData(pinCode: pincode, id: id) } @@ -83,9 +85,11 @@ class AddressListVM{ case .failure(let error): guard let self else{ Utilities.dismissProgressHUD() + self?.checkForNoData() return } Utilities.dismissProgressHUD() + checkForNoData() Utilities.alertWithBtnCompletion(title: "Error", msgBody: error.localizedDescription, okBtnStr: "Retry?", vc: self.vc) { isDone in if isDone{ self.getAddressListing() @@ -95,6 +99,14 @@ class AddressListVM{ } } + func checkForNoData(){ + if CartDataCache.addressData.count == 0{ + vc.noDataStack.isHidden = false + }else{ + vc.noDataStack.isHidden = true + } + } + func checkEstimatedDeliveryData(pinCode : String, id : Int){ let headers : HTTPHeaders = ["access-token" : AuthFunc.shareInstance.getAccessToken()] let params : Parameters = ["pincode" : pinCode] diff --git a/WOKA/Audio Books/AudioBookDetailsVC.swift b/WOKA/Audio Books/AudioBookDetailsVC.swift index 3876453..81ed6db 100644 --- a/WOKA/Audio Books/AudioBookDetailsVC.swift +++ b/WOKA/Audio Books/AudioBookDetailsVC.swift @@ -361,7 +361,9 @@ class AudioBookDetailsVC : UIViewController{ // } // } // } - JWPlayerManager.shared.presentPlayer(from: self, playerItems: playerItems, startIndex: 0, contentType: .audioBooks) + if let audioID = audioData?.id{ + JWPlayerManager.shared.presentPlayer(from: self, playerItems: playerItems, startIndex: 0, contentType: .audioBooks,videoIDs: [audioID]) + } } @IBAction func closeBtnTapped(_ sender: UIButton) { diff --git a/WOKA/Audio Books/AudioBookHomeVC.swift b/WOKA/Audio Books/AudioBookHomeVC.swift index c417bb4..e4a66bb 100644 --- a/WOKA/Audio Books/AudioBookHomeVC.swift +++ b/WOKA/Audio Books/AudioBookHomeVC.swift @@ -66,6 +66,13 @@ class AudioBookHomeVC: UIViewController { } } + override func viewDidAppear(_ animated: Bool) { + if K.GVar.reloadContinueAudioBooks{ + K.GVar.reloadContinueAudioBooks = false + vm.getContinueWatching() + } + } + override func viewDidLayoutSubviews() { vm.updateTableHeight() } @@ -78,10 +85,8 @@ class AudioBookHomeVC: UIViewController { } @IBAction func listenAudioBtnTapped(_ sender: LocalisedElementsButton) { - guard let data = vm.headerData else{return} - if let postID = data.id{ - PersistentStorage.shared.addAudioCount(postID: postID) - } + guard let data = vm.headerData, let postID = data.id else{return} + PersistentStorage.shared.addAudioCount(postID: postID) var playerItems = [JwPlayerItemCreate]() if AuthFunc.shareInstance.getDefaultLanguage() == .english{ if let englishData = data.contentMoreDetails?.filter({$0.languageMasterID == 1}).first, let url = englishData.url{ @@ -92,7 +97,7 @@ class AudioBookHomeVC: UIViewController { playerItems.append(JwPlayerItemCreate(url: url, poster: data.thumbnailPath, titles: hindiData.title)) } } - JWPlayerManager.shared.presentPlayer(from: self, playerItems: playerItems, startIndex: 0, contentType: .audioBooks) + JWPlayerManager.shared.presentPlayer(from: self, playerItems: playerItems, startIndex: 0, contentType: .audioBooks, videoIDs: [postID]) } } diff --git a/WOKA/Constants K/ConstantString.swift b/WOKA/Constants K/ConstantString.swift index e594bae..52019a4 100644 --- a/WOKA/Constants K/ConstantString.swift +++ b/WOKA/Constants K/ConstantString.swift @@ -33,5 +33,7 @@ extension K{ static let error = "Error" static let rupeeSign = "₹" + + static let sync = "Syncing..." } } diff --git a/WOKA/Constants K/GVar.swift b/WOKA/Constants K/GVar.swift index 1a5f609..67ca5dd 100644 --- a/WOKA/Constants K/GVar.swift +++ b/WOKA/Constants K/GVar.swift @@ -24,5 +24,9 @@ extension K{ static var reloadMyListAll = 0 // 0 - null, 1 - add , 2- remove static var reloadMyListAllID = 0 + + static var reloadContinueKaraoke = false + static var reloadContinueAudioBooks = false + static var reloadContinueWebSeries = false } } diff --git a/WOKA/Games/Controller/GamesDetailVC.swift b/WOKA/Games/Controller/GamesDetailVC.swift index 6bbb5c2..dbda41e 100644 --- a/WOKA/Games/Controller/GamesDetailVC.swift +++ b/WOKA/Games/Controller/GamesDetailVC.swift @@ -205,7 +205,11 @@ class GamesDetailVC: UIViewController { } } - shareView.addTapGesture { + shareView.addTapGesture { [weak self] in + guard let self else{return} + if let postID = gameData?.id{ + PersistentStorage.shared.addGamesCount(postID: postID) + } if let name = URL(string: "https://apps.apple.com/in/app/woka/id6465305185"), !name.absoluteString.isEmpty { let objectsToShare = [name] let activityVC = UIActivityViewController(activityItems: objectsToShare, applicationActivities: nil) diff --git a/WOKA/Games/Controller/GamesWebViewVC.swift b/WOKA/Games/Controller/GamesWebViewVC.swift index c5fc600..5773383 100644 --- a/WOKA/Games/Controller/GamesWebViewVC.swift +++ b/WOKA/Games/Controller/GamesWebViewVC.swift @@ -14,12 +14,20 @@ class GamesWebViewVC: UIViewController, WKNavigationDelegate,UIGestureRecognizer var orientation : ScreenOrientation? var count = 0 var postID : Int? + @IBOutlet weak var clickView: UIView! @IBOutlet weak var webView: WKWebView! + var startTimeStamp = Date() + + typealias btnTappedBlock = () -> Void + var btnTapped : btnTappedBlock? + deinit{ -// print("Deinit Game") + NotificationCenter.default.removeObserver(self,name: UIApplication.didEnterBackgroundNotification, object: nil) + NotificationCenter.default.removeObserver(self,name: UIApplication.willEnterForegroundNotification, object: nil) + if let postID = self.postID{ PersistentStorage.shared.addGamesCount(postID: postID,count: count) } @@ -49,6 +57,10 @@ class GamesWebViewVC: UIViewController, WKNavigationDelegate,UIGestureRecognizer // Add the gesture recognizer to the web view clickView.addGestureRecognizer(tap) + + // Add observers + NotificationCenter.default.addObserver(self,selector: #selector(appDidEnterBackground),name: UIApplication.didEnterBackgroundNotification,object: nil) + NotificationCenter.default.addObserver(self,selector: #selector(appWillEnterForeground),name: UIApplication.willEnterForegroundNotification,object: nil) } func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool { @@ -61,9 +73,7 @@ class GamesWebViewVC: UIViewController, WKNavigationDelegate,UIGestureRecognizer } @IBAction func backBtnTapped(_ sender: UIButton) { - if let postID = self.postID{ - PersistentStorage.shared.addOthersCount() - } + PersistentStorage.shared.addOthersCount() let sb = UIStoryboard(name: K.StoryBoard.customAlerts, bundle: nil) let vcPush = sb.instantiateViewController(withIdentifier: K.StoryBoardID.CustomAlerts.yesNoAlertVC) as! YesNoAlertVC @@ -75,7 +85,8 @@ class GamesWebViewVC: UIViewController, WKNavigationDelegate,UIGestureRecognizer guard let self else{return} switch mode{ case .yes: - + // update continue watching + self.updateGamesView() if orientation == .landscape{ appDelegate.deviceOrientation = .portrait let value = UIInterfaceOrientation.portrait.rawValue @@ -85,7 +96,6 @@ class GamesWebViewVC: UIViewController, WKNavigationDelegate,UIGestureRecognizer self.dismiss(animated: true) } } - case .no: if let postID = self.postID{ PersistentStorage.shared.addGamesCount(postID: postID) @@ -98,6 +108,26 @@ class GamesWebViewVC: UIViewController, WKNavigationDelegate,UIGestureRecognizer self.present(vcPush, animated: true) } + + // MARK: - App LifeCycle HAndler + + @objc func appDidEnterBackground() { + //when app goes in background make a count + updateGamesView() + } + + @objc func appWillEnterForeground() { + //reset the start time + startTimeStamp = Date() + } + + func updateGamesView(){ + if let postID { + let duration = DateFormatterLib.dateDifferenceINT(date1: startTimeStamp, date2: Date()) + AuthFunc.shareInstance.userVideoView(postID: postID, postType: PostType.game.rawValue, duration: duration, catID: 0) { _ in} + } + } + // MARK: - Handle Screen Transition override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { diff --git a/WOKA/Helpers/DateFormatterLib.swift b/WOKA/Helpers/DateFormatterLib.swift index c4c372d..4697e53 100644 --- a/WOKA/Helpers/DateFormatterLib.swift +++ b/WOKA/Helpers/DateFormatterLib.swift @@ -191,6 +191,22 @@ class DateFormatterLib{ } } + + static func dateDifferenceINT(date1 : Date, date2 : Date) -> Int{ + // Calculate the difference in seconds + let timeInterval = date2.timeIntervalSince(date1) + + // Convert the time interval to an integer representing the difference in seconds + let differenceInSeconds = Int(timeInterval) + + // If you want the difference in minutes, divide by 60 +// let differenceInMinutes = Int(timeInterval / 60) + + // If you want the difference in hours, divide by 3600 +// let differenceInHours = Int(timeInterval / 3600) + + return differenceInSeconds + } } extension Date { diff --git a/WOKA/Home/Controller/MyListVC.swift b/WOKA/Home/Controller/MyListVC.swift index ff969e2..881a1ea 100644 --- a/WOKA/Home/Controller/MyListVC.swift +++ b/WOKA/Home/Controller/MyListVC.swift @@ -37,6 +37,10 @@ class MyListVC: UIViewController{ @IBOutlet weak var gamesBtn: LocalisedElementsButton! @IBOutlet weak var karaokeViewBtn: LocalisedElementsButton! + @IBOutlet weak var shimmerStack: UIStackView! + @IBOutlet var shimmerView: [ShimmerEffectView]! + + var vm = MyListVM() deinit{ diff --git a/WOKA/Home/Home.storyboard b/WOKA/Home/Home.storyboard index f8069b0..ecdb5d9 100644 --- a/WOKA/Home/Home.storyboard +++ b/WOKA/Home/Home.storyboard @@ -1461,6 +1461,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1469,6 +1512,8 @@ + + @@ -1477,6 +1522,7 @@ + @@ -1491,6 +1537,7 @@ + @@ -1510,17 +1557,21 @@ + + + + - + diff --git a/WOKA/Home/ViewModel/MyListVM.swift b/WOKA/Home/ViewModel/MyListVM.swift index 031d2c8..49fa971 100644 --- a/WOKA/Home/ViewModel/MyListVM.swift +++ b/WOKA/Home/ViewModel/MyListVM.swift @@ -36,7 +36,7 @@ class MyListVM{ } setupCell() - Utilities.startProgressHUD() + startShimmer(load: true) getFavouriteListing() vc.karaokeViewBtn.roundCorner() @@ -46,6 +46,18 @@ class MyListVM{ vc.webSeriesHindiBtn.roundCorner() } + func startShimmer(load : Bool){ + vc.shimmerView.forEach { shimmer in + if load{ + shimmer.gradientColorOne = UIColor.lightGray.cgColor + shimmer.startShimmer() + }else{ + shimmer.stopShimmer() + } + } + vc.shimmerStack.isHidden = !load + } + @objc func viewPush(notification: Notification){ if let userInfo = notification.userInfo, let action = userInfo["action"] as? TopViewPush { switch action { @@ -134,6 +146,7 @@ class MyListVM{ case 0: self.refreshControl.endRefreshing() Utilities.dismissProgressHUD() + self.startShimmer(load: false) self.vc.toast(msg: data.message ?? "Unrecognised error" , time: 2) // MyListDataTemp.shareInstance.webSeriesHindi.removeAll() MyListDataTemp.shareInstance.favListingData = nil @@ -148,6 +161,7 @@ class MyListVM{ case 1: self.refreshControl.endRefreshing() Utilities.dismissProgressHUD() + self.startShimmer(load: false) guard let data = data.data?.result else{return} MyListDataTemp.shareInstance.favListingData = nil // MyListDataTemp.shareInstance.webSeriesHindi.removeAll() @@ -218,6 +232,7 @@ class MyListVM{ guard let self else{return} self.refreshControl.endRefreshing() Utilities.dismissProgressHUD() + self.startShimmer(load: false) checkNil() if MyListDataTemp.shareInstance.favListingData?.showData == nil { MyListDataTemp.shareInstance.favListingData = FavouriteListingDM.ResultData(totalRecords: nil, showData: FavouriteListingDM.ResultData.ShowData(hindi: [],english: []),videoData: [],gameData: [],singKaraokeData: [],audioData: []) diff --git a/WOKA/Karaoke/Controller/JWKaraokePlayerVC.swift b/WOKA/Karaoke/Controller/JWKaraokePlayerVC.swift index 4c67366..357dd44 100644 --- a/WOKA/Karaoke/Controller/JWKaraokePlayerVC.swift +++ b/WOKA/Karaoke/Controller/JWKaraokePlayerVC.swift @@ -30,8 +30,15 @@ class JWKaraokePlayerVC: JWPlayerViewController, JWPlayerViewControllerDelegate var audioPlayer = AVPlayer() + var videoID = Int() + var vm = JWKaraokePlayerVM() + deinit{ + NotificationCenter.default.removeObserver(self,name: UIApplication.didEnterBackgroundNotification, object: nil) + NotificationCenter.default.removeObserver(self,name: UIApplication.willEnterForegroundNotification, object: nil) + } + override func viewDidLoad() { super.viewDidLoad() vm.vc = self @@ -43,7 +50,11 @@ class JWKaraokePlayerVC: JWPlayerViewController, JWPlayerViewControllerDelegate playerView.allowsPictureInPicturePlayback = false playerView.captionStyle = .none self.view.bringSubviewToFront(outerStack) - self.view.bringSubviewToFront(backButton) + self.view.bringSubviewToFront(backButton) + + // Add observers + NotificationCenter.default.addObserver(self,selector: #selector(appDidEnterBackground),name: UIApplication.didEnterBackgroundNotification,object: nil) + NotificationCenter.default.addObserver(self,selector: #selector(appWillEnterForeground),name: UIApplication.willEnterForegroundNotification,object: nil) } override func viewWillAppear(_ animated: Bool) { @@ -129,7 +140,20 @@ class JWKaraokePlayerVC: JWPlayerViewController, JWPlayerViewControllerDelegate PersistentStorage.shared.addKaraokeCount(postID: postID) } self.player.stop() - self.dismiss(animated: true) + if let postID = vm.postID{ + Utilities.startProgressHUD(msg: "Syncing...") + let duration = DateFormatterLib.dateDifferenceINT(date1: vm.startTimeStamp, date2: Date()) + AuthFunc.shareInstance.userVideoView(postID: postID, postType: PostType.karaokeVideo.rawValue, duration: duration, catID: 0) { isDone in + if isDone{ + K.GVar.reloadContinueKaraoke = true + Utilities.dismissProgressHUD() + self.dismiss(animated: true) + }else{ + Utilities.dismissProgressHUD() + self.dismiss(animated: true) + } + } + } } @IBAction func retryBtnTapped(_ sender: LocalisedElementsButton) { @@ -140,12 +164,35 @@ class JWKaraokePlayerVC: JWPlayerViewController, JWPlayerViewControllerDelegate vm.setupKaraoke() } + // MARK: - App LifeCycle HAndler + + @objc func appDidEnterBackground() { + //when app goes in background make a count + vm.updateKaraokeVideoView() + self.player.pause() + + self.playBtn.isEnabled = false + + if isRecording { + vm.stopRecording() + //make sure the interfacebehaviour is enabbled && updated the record btn title and image + self.interfaceBehavior = .normal + startRecordBtn.setTitle("Start Recording", for: .normal) + isRecording = false + } + } + + @objc func appWillEnterForeground() { + //reset the start time + vm.startTimeStamp = Date() + self.player.play() + } + // MARK: - JWPlayerViewControllerDelegate override func jwplayer(_ player: any JWPlayer, didFinishLoadingWithTime loadTime: TimeInterval) { super.jwplayer(player, didFinishLoadingWithTime: loadTime) print("LoadTime", loadTime) - DispatchQueue.main.async { [weak self] in guard let self else{return} vm.setupKaraoke() @@ -241,6 +288,9 @@ extension JWKaraokePlayerVC { // self.setDeviceOrientation(orientation: .portrait) self.player.stop() self.dismiss(animated: true) + + vm.updateKaraokeVideoView() + print("playerViewControllerWillGoFullScreen") return nil } @@ -257,13 +307,13 @@ extension JWKaraokePlayerVC { } func playerViewControllerDidDismissFullScreen(_ controller: JWPlayerViewController) { - print("playerViewControllerDidDismissFullScreen") - - self.dismissTapped?() - Timer.scheduledTimer(withTimeInterval: 0.5, repeats: false) { _ in - self.player.stop() - controller.dismiss(animated: true) - } +// print("playerViewControllerDidDismissFullScreen") +// +// self.dismissTapped?() +// Timer.scheduledTimer(withTimeInterval: 0.5, repeats: false) { _ in +// self.player.stop() +// controller.dismiss(animated: true) +// } } } diff --git a/WOKA/Karaoke/Controller/KaraokeListingVC.swift b/WOKA/Karaoke/Controller/KaraokeListingVC.swift index fcc17d0..080a43d 100644 --- a/WOKA/Karaoke/Controller/KaraokeListingVC.swift +++ b/WOKA/Karaoke/Controller/KaraokeListingVC.swift @@ -65,6 +65,13 @@ class KaraokeListingVC: UIViewController { vm.updateTableHeight() } + override func viewDidAppear(_ animated: Bool) { + if K.GVar.reloadContinueKaraoke{ + K.GVar.reloadContinueKaraoke = false + self.vm.getContinueWatching() + } + } + @IBAction func loadMoreBtnTapped(_ sender: LocalisedElementsButton) { PersistentStorage.shared.addOthersCount() loadMoreBtn.isHidden = true diff --git a/WOKA/Karaoke/ViewModel/JWKaraokePlayerVM.swift b/WOKA/Karaoke/ViewModel/JWKaraokePlayerVM.swift index 75564e3..1dac155 100644 --- a/WOKA/Karaoke/ViewModel/JWKaraokePlayerVM.swift +++ b/WOKA/Karaoke/ViewModel/JWKaraokePlayerVM.swift @@ -26,7 +26,10 @@ class JWKaraokePlayerVM{ var startTime : TimeInterval? var endTime : TimeInterval? + var startTimeStamp = Date() + func initView(){ + startTimeStamp = Date() vc.downloadRecordingBtn.isEnabled = false hideShowKaraoke(isLoading: true) } @@ -85,6 +88,19 @@ class JWKaraokePlayerVM{ } } + // MARK: - App LifeCycle HAndler + + func updateKaraokeVideoView(){ + if let postID { + let duration = DateFormatterLib.dateDifferenceINT(date1: startTimeStamp, date2: Date()) + AuthFunc.shareInstance.userVideoView(postID: postID, postType: PostType.karaokeVideo.rawValue, duration: duration, catID: 0) { isDone in + if isDone{ + K.GVar.reloadContinueKaraoke = true + } + } + } + } + // MARK: - AudioRecording func setupAudio() { diff --git a/WOKA/Main/AuthFunc/AuthFuncUserVideoView.swift b/WOKA/Main/AuthFunc/AuthFuncUserVideoView.swift new file mode 100644 index 0000000..01f34ee --- /dev/null +++ b/WOKA/Main/AuthFunc/AuthFuncUserVideoView.swift @@ -0,0 +1,45 @@ +// +// AuthFuncUserVideoView.swift +// WOKA +// +// Created by Bilal on 16/08/2024. +// + +import Foundation +import Alamofire + +extension AuthFunc{ + + func userVideoView(postID : Int, postType : Int, duration : Int, catID : Int, onCompletion : @escaping (Bool) -> Void){ + let headers : HTTPHeaders = ["access-token" : AuthFunc.shareInstance.getAccessToken(), + "device-id": AuthFunc.shareInstance.getDeviceUUID()] + let params : Parameters = ["post_id" : postID, + "post_type" : postType, + "total_watched_duration" : duration, + "device_type" : "2", //1- android, 2 - iOS + "category_id": catID] + NetworkManager.shareInstance.apiRequest(url: APIEndPoints.Analytics.user_video_view, method: .post,parameters: params,headers: headers) { (result : Result) in + switch result{ + case .success(let data): + switch data.success{ + case 0: + /* + Error + */ + Utilities.dismissProgressHUD() + onCompletion(false) + case 1: + Utilities.dismissProgressHUD() + print("Updated PostType:- \(postType)") + onCompletion(true) + default: + onCompletion(false) + } + case .failure(let error): + Utilities.dismissProgressHUD() + print(error) + onCompletion(false) + } + } + } +} diff --git a/WOKA/Network Adapter/APIEndPoints.swift b/WOKA/Network Adapter/APIEndPoints.swift index 785b332..bef2f9c 100644 --- a/WOKA/Network Adapter/APIEndPoints.swift +++ b/WOKA/Network Adapter/APIEndPoints.swift @@ -144,6 +144,7 @@ struct APIEndPoints { struct Analytics{ static let user_clicks = makeURL(path: "v2/user_clicks") + static let user_video_view = makeURL(path: "user_video_view") } // Helper method to construct full URL from base URL and path diff --git a/WOKA/PersistentStorage.swift b/WOKA/PersistentStorage.swift index 3db7e9d..2e6abe1 100644 --- a/WOKA/PersistentStorage.swift +++ b/WOKA/PersistentStorage.swift @@ -15,7 +15,6 @@ import CoreData enum PersistentStorageEnum : String{ case UserClicks - case click_counts case category_id case post_id @@ -41,25 +40,6 @@ enum PostType: Int { case home = 16 } -//enum PostType: String { -// case series = "1" -// case season = "2" -// case episode = "3" -// case video = "4" -//// case paint = "5" -// case game = "6" -// case audio = "7" -// case karaokeVideo = "8" -// case shopProduct = "9" -//// case parentalVideo = "10" -//// case article = "11" -// case liveTV = "12" -// case FM = "13" -// case teaser = "14" -// case others = "15" -// case home = "16" -//} - struct UserClickData { let clickCounts: Int let categoryId: Int @@ -67,6 +47,13 @@ struct UserClickData { let postType: Int } +//struct UserVideoViewData { +// let postId: Int +// let postType: Int +// let watchedDuration: Double +// let categoryId: Int +//} + final class PersistentStorage { @@ -126,18 +113,18 @@ final class PersistentStorage let fetchRequest = NSFetchRequest(entityName: PersistentStorageEnum.UserClicks.rawValue) // fetchRequest.fetchLimit = 1 // fetchRequest.predicate = NSPredicate(format: "id == %d" ,id) - fetchRequest.predicate = NSPredicate(format: "\(key.rawValue) == %@" ,clicksData.postType.toString()) + fetchRequest.predicate = NSPredicate(format: "\(key.rawValue) == %@ AND post_id == %@" ,clicksData.postType.toString(),clicksData.postId.toString()) do { guard let result = try managedContext.fetch(fetchRequest) as? [UserClicks] else {return} if result.isEmpty{ //create PersistentStorage.shared.createData(data: clicksData) - print("create") + print("create, In Exist") }else{ //update let objectUpdate = result[0] as NSManagedObject - print("Update") + print("Update, In Exist") objectUpdate.setValue(result.first!.click_counts + Int64(clicksData.clickCounts), forKey: "click_counts") do{ try managedContext.save() @@ -216,7 +203,7 @@ final class PersistentStorage //We need to create a context from this container let managedContext = PersistentStorage.shared.context let fetchRequest:NSFetchRequest = NSFetchRequest.init(entityName: "UserClicks") - fetchRequest.fetchLimit = 4 + fetchRequest.fetchLimit = 10 do { guard let result = try managedContext.fetch(fetchRequest) as? [UserClicks] else {return} result.forEach { clicks in @@ -238,7 +225,7 @@ final class PersistentStorage // let path = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask) // debugPrint(path[0]) let fetchRequest:NSFetchRequest = NSFetchRequest.init(entityName: "UserClicks") - fetchRequest.fetchLimit = 4 + fetchRequest.fetchLimit = 15 do { guard let result = try managedContext.fetch(fetchRequest) as? [UserClicks] else {return} var userClicks = [ClicksAnalytics]() @@ -275,73 +262,8 @@ final class PersistentStorage debugPrint("Failed to delete data:", error) } } - // func updateData(){ - // //We need to create a context from this container - // let managedContext = PersistentStorage.shared.context - // - // - // let fetchRequest:NSFetchRequest = NSFetchRequest.init(entityName: "UserClicks") - // fetchRequest.predicate = NSPredicate(format: "uuid = %@", "2") - // do - // { - // let test = try managedContext.fetch(fetchRequest) - // - // let objectUpdate = test[0] as! NSManagedObject - // objectUpdate.setValue("Bilal Ahmed Khan New Name", forKey: "name") - // do{ - // try managedContext.save() - // self.retrieveData() - // } - // catch - // { - // print(error) - // } - // } - // catch - // { - // print(error) - // } - // - // } - // func deleteData(){ - // //We need to create a context from this container - // let managedContext = PersistentStorage.shared.context - // - // let fetchRequest = NSFetchRequest(entityName: "UserClicks") - //// fetchRequest.fetchLimit = 1 - //// fetchRequest.predicate = NSPredicate(format: "uuid = %@ AND uuid = %@", "1", "1") - // fetchRequest.predicate = NSPredicate(format: "post_id = %@", "11") - // - // do - // { - // let test = try managedContext.fetch(fetchRequest) - // - // let objectToDelete = test[0] as! NSManagedObject - //// test.forEach { obbject in - //// managedContext.delete(obbject as! NSManagedObject) - //// } - // managedContext.delete(test.first as! NSManagedObject) - //// managedContext.delete(objectToDelete) - // - // do{ - // try managedContext.save() - //// self.createData() - // self.retrieveData() - // } - // catch - // { - // print(error) - // } - // - // } - // catch - // { - // print(error) - // } - // } - - // MARK: - Handle Clicks + // MARK: - Handle Clicks For UserClicks func addOthersCount(){ let userClicks = UserClickData(clickCounts: 1, categoryId: 0, postId: 0, postType: PostType.others.rawValue) @@ -389,4 +311,51 @@ final class PersistentStorage let userClicks = UserClickData(clickCounts: 1, categoryId: catID, postId: postID, postType: postType.rawValue) PersistentStorage.shared.checkWebSeries(clicksData: userClicks) } + + + // MARK: - Handling UserViewView CRUD + +// func createVideoViewData(data : UserVideoViewData){ +// +// //We need to create a context from this container +// let managedContext = PersistentStorage.shared.context +// +// let videoData = UserVideoView(context: managedContext) +// videoData.post_id = Int64(data.postId) +// videoData.post_type = Int64(data.postType) +// videoData.total_watched_duration = data.watchedDuration +// videoData.category_id = Int64(data.categoryId) +// +// do { +// try managedContext.save() +// retrieveData(postID: data.postId, catID: data.categoryId, postType: data.postType) +// } catch let error as NSError { +// print("Could not save. \(error), \(error.userInfo)") +// } +// } +// +// func retrieveVideoViewData(postID : Int?, catID : Int?, postType : Int) { +// +// //We need to create a context from this container +// let managedContext = PersistentStorage.shared.context +// +// let path = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask) +// // debugPrint(path[0]) +// let fetchRequest:NSFetchRequest = NSFetchRequest.init(entityName: "UserVideoView") +// +// fetchRequest.predicate = NSPredicate(format: "post_id == %@ AND category_id == %@ AND post_type == %@" ,postID?.toString() ?? "0", catID?.toString() ?? "0" ,postType.toString()) +// +// do { +// guard let result = try managedContext.fetch(fetchRequest) as? [UserClicks] else {return} +// result.forEach { clicks in +// print("VideoView:- ","ID:-" , PostType(rawValue: Int(clicks.post_type))!, "CatID:- ", clicks.category_id, "PostID:- ", clicks.post_id , "Count:-", clicks.click_counts) +// } +// } +// catch let error +// { +// debugPrint(error) +// } +// } + // MARK: - Handle Clicks For UserVideoView + } diff --git a/WOKA/Theme/Base.lproj/Theme.storyboard b/WOKA/Theme/Base.lproj/Theme.storyboard index 1151492..1c9fc1e 100644 --- a/WOKA/Theme/Base.lproj/Theme.storyboard +++ b/WOKA/Theme/Base.lproj/Theme.storyboard @@ -1098,19 +1098,19 @@