competed user video view

This commit is contained in:
Bilal
2024-08-17 01:34:28 +05:30
parent c6ed16cad2
commit 9ca7c1e4b0
35 changed files with 857 additions and 344 deletions

View File

@@ -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 = "<group>"; };
527AC6FC2C173A5100434FB7 /* SongListCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SongListCell.xib; sourceTree = "<group>"; };
527AC7002C182DCE00434FB7 /* TimeStringToSeconds.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeStringToSeconds.swift; sourceTree = "<group>"; };
527CA4392C6C7FBE00EEDD91 /* WOKA.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = WOKA.xcdatamodel; sourceTree = "<group>"; };
528BEF5F2C2C372900FFDAB8 /* ContinueWatchingVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContinueWatchingVC.swift; sourceTree = "<group>"; };
528E5F1A2C24531200E33E4E /* SeasonListingDM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeasonListingDM.swift; sourceTree = "<group>"; };
528E5F202C24660F00E33E4E /* SeasonCategoryCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeasonCategoryCell.swift; sourceTree = "<group>"; };
@@ -719,6 +720,9 @@
9CBE1B392C0F37B200CA6E61 /* DropDown+Appearance.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DropDown+Appearance.swift"; sourceTree = "<group>"; };
9CBE1B3A2C0F37B200CA6E61 /* DropDownCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DropDownCell.swift; sourceTree = "<group>"; };
9CBE1B3C2C0F37B200CA6E61 /* DropDown.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DropDown.h; sourceTree = "<group>"; };
9CC0D2F72C6F339D0019DF73 /* WOKA.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = WOKA.xcdatamodel; sourceTree = "<group>"; };
9CC0D2F92C6F33BE0019DF73 /* AuthFuncUserVideoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthFuncUserVideoView.swift; sourceTree = "<group>"; };
9CC0D2FB2C6F5CAE0019DF73 /* PlayerVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerVM.swift; sourceTree = "<group>"; };
9CDAEB022C53B97B00890C47 /* VersionTexts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VersionTexts.swift; sourceTree = "<group>"; };
9CDAEB042C53DB2900890C47 /* ProductDetailsVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductDetailsVC.swift; sourceTree = "<group>"; };
9CDAEB062C53E42900890C47 /* ProductDetailsVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductDetailsVM.swift; sourceTree = "<group>"; };
@@ -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 = "<group>";
@@ -1731,6 +1736,7 @@
524C422A2C04781B0016A11C /* ThemeTwoVM.swift */,
52BC3BF12C170264002FACA6 /* MoreVM.swift */,
529CFEED2C60F49000B0B380 /* UserNotificationVM.swift */,
9CC0D2FB2C6F5CAE0019DF73 /* PlayerVM.swift */,
);
path = ViewModel;
sourceTree = "<group>";
@@ -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 = "<group>";
versionGroupType = wrapper.xcdatamodel;
};

View File

@@ -549,19 +549,36 @@
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</view>
<stackView hidden="YES" opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="n6H-pw-g1w">
<rect key="frame" x="118.66666666666669" y="290.66666666666669" width="177" height="200"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="SupportGirlImage" translatesAutoresizingMaskIntoConstraints="NO" id="Rnc-CS-DVv">
<rect key="frame" x="0.0" y="0.0" width="177" height="166"/>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="No Address Found!" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="SR8-rF-46h" customClass="LocalisedElementsLabel" customModule="WOKA" customModuleProvider="target">
<rect key="frame" x="0.0" y="176" width="177" height="24"/>
<fontDescription key="fontDescription" name="Exo2-Bold" family="Exo 2" pointSize="20"/>
<color key="textColor" name="TextDarkBlue"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
</subviews>
<viewLayoutGuide key="safeArea" id="37x-el-mdR"/>
<color key="backgroundColor" systemColor="systemGreenColor"/>
<constraints>
<constraint firstItem="n6H-pw-g1w" firstAttribute="centerY" secondItem="w05-l0-ALY" secondAttribute="centerY" id="bbS-Lc-ZsW"/>
<constraint firstItem="37x-el-mdR" firstAttribute="bottom" secondItem="Ry1-Ll-tvj" secondAttribute="bottom" constant="5" id="g8o-D8-sxQ"/>
<constraint firstItem="37x-el-mdR" firstAttribute="trailing" secondItem="Ry1-Ll-tvj" secondAttribute="trailing" constant="10" id="hfh-kM-3II"/>
<constraint firstItem="Ry1-Ll-tvj" firstAttribute="top" secondItem="37x-el-mdR" secondAttribute="top" constant="5" id="nXO-UI-rOM"/>
<constraint firstItem="n6H-pw-g1w" firstAttribute="centerX" secondItem="w05-l0-ALY" secondAttribute="centerX" id="vdb-8x-PwN"/>
<constraint firstItem="Ry1-Ll-tvj" firstAttribute="leading" secondItem="37x-el-mdR" secondAttribute="leading" constant="10" id="zid-rU-Ovk"/>
</constraints>
</view>
<connections>
<outlet property="addNewAddressBtn" destination="02u-58-7FW" id="eWv-38-GfZ"/>
<outlet property="innerView" destination="JAF-kY-lUa" id="cM7-cm-pqy"/>
<outlet property="noDataStack" destination="n6H-pw-g1w" id="EMJ-ob-Dr1"/>
<outlet property="tableView" destination="w05-l0-ALY" id="J15-i9-ySS"/>
<outlet property="useSelectedAddBtn" destination="ZNs-65-Cqv" id="hYN-Nc-H8h"/>
</connections>
@@ -582,7 +599,7 @@
<rect key="frame" x="0.0" y="44" width="414" height="852"/>
<color key="backgroundColor" red="0.36078431370000003" green="0.38823529410000002" blue="0.4039215686" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<wkWebViewConfiguration key="configuration" allowsAirPlayForMediaPlayback="NO" allowsPictureInPictureMediaPlayback="NO">
<dataDetectorTypes key="dataDetectorTypes"/>
<dataDetectorTypes key="dataDetectorTypes" none="YES"/>
<audiovisualMediaTypes key="mediaTypesRequiringUserActionForPlayback" none="YES"/>
<wkPreferences key="preferences"/>
</wkWebViewConfiguration>
@@ -636,6 +653,7 @@
</designable>
</designables>
<resources>
<image name="SupportGirlImage" width="166" height="166"/>
<namedColor name="TextDarkBlue">
<color red="0.10599999874830246" green="0.050999999046325684" blue="0.60399997234344482" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</namedColor>
@@ -643,7 +661,7 @@
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
<systemColor name="systemGreenColor">
<color red="0.20392156862745098" green="0.7803921568627451" blue="0.34901960784313724" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color red="0.20392156859999999" green="0.78039215689999997" blue="0.34901960780000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</systemColor>
</resources>
</document>

View File

@@ -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)
}

View File

@@ -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]

View File

@@ -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) {

View File

@@ -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])
}
}

View File

@@ -33,5 +33,7 @@ extension K{
static let error = "Error"
static let rupeeSign = ""
static let sync = "Syncing..."
}
}

View File

@@ -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
}
}

View File

@@ -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)

View File

@@ -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) {

View File

@@ -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 {

View File

@@ -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{

View File

@@ -1461,6 +1461,49 @@
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</stackView>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="20" translatesAutoresizingMaskIntoConstraints="NO" id="n3b-MP-wOW">
<rect key="frame" x="0.0" y="126" width="430" height="660"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="zVG-vD-Pa9" customClass="ShimmerEffectView" customModule="WOKA" customModuleProvider="target">
<rect key="frame" x="15" y="10" width="400" height="200"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstAttribute="height" constant="200" id="BOv-Or-mtr"/>
</constraints>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
<integer key="value" value="10"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="5PD-9x-fXz" customClass="ShimmerEffectView" customModule="WOKA" customModuleProvider="target">
<rect key="frame" x="15" y="230" width="400" height="200"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstAttribute="height" constant="200" id="1Hd-rU-zAi"/>
</constraints>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
<integer key="value" value="10"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="LMU-lo-nNz" customClass="ShimmerEffectView" customModule="WOKA" customModuleProvider="target">
<rect key="frame" x="15" y="450" width="400" height="200"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstAttribute="height" constant="200" id="xlu-qi-KIb"/>
</constraints>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
<integer key="value" value="10"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</view>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<edgeInsets key="layoutMargins" top="10" left="15" bottom="10" right="15"/>
</stackView>
</subviews>
<viewLayoutGuide key="safeArea" id="fPD-rO-ZgU"/>
<color key="backgroundColor" red="0.82745098039215681" green="0.93725490196078431" blue="0.97254901960784312" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
@@ -1469,6 +1512,8 @@
<constraint firstItem="fPD-rO-ZgU" firstAttribute="trailing" secondItem="a7Y-B6-f0Q" secondAttribute="trailing" constant="15" id="1TC-Nf-fdz"/>
<constraint firstItem="jbL-QO-JJl" firstAttribute="leading" secondItem="5ML-g4-686" secondAttribute="trailing" constant="15" id="5bI-AA-E64"/>
<constraint firstItem="SyC-Qw-kzE" firstAttribute="bottom" secondItem="fPD-rO-ZgU" secondAttribute="bottom" id="7R3-kt-ANX"/>
<constraint firstItem="n3b-MP-wOW" firstAttribute="leading" secondItem="fPD-rO-ZgU" secondAttribute="leading" id="E1C-E8-97R"/>
<constraint firstItem="n3b-MP-wOW" firstAttribute="trailing" secondItem="fPD-rO-ZgU" secondAttribute="trailing" id="I4g-uI-OU6"/>
<constraint firstItem="fTK-nk-bN9" firstAttribute="leading" secondItem="fPD-rO-ZgU" secondAttribute="leading" id="KDZ-vt-s13"/>
<constraint firstItem="a7Y-B6-f0Q" firstAttribute="top" secondItem="fPD-rO-ZgU" secondAttribute="top" constant="10" id="L4o-KM-D1O"/>
<constraint firstItem="cxl-Av-gEU" firstAttribute="bottom" secondItem="a7Y-B6-f0Q" secondAttribute="bottom" constant="7" id="Lur-Ax-w8w"/>
@@ -1477,6 +1522,7 @@
<constraint firstItem="5ML-g4-686" firstAttribute="leading" secondItem="23B-pX-ODs" secondAttribute="leading" constant="5" id="Na5-Wr-DSa"/>
<constraint firstItem="SyC-Qw-kzE" firstAttribute="top" secondItem="a7Y-B6-f0Q" secondAttribute="bottom" constant="10" id="Nyh-j8-zuL"/>
<constraint firstItem="fPD-rO-ZgU" firstAttribute="trailing" secondItem="ygH-wj-cLk" secondAttribute="trailing" id="Pyd-Eq-Pwe"/>
<constraint firstItem="n3b-MP-wOW" firstAttribute="bottom" relation="lessThanOrEqual" secondItem="fPD-rO-ZgU" secondAttribute="bottom" id="UgR-R8-f7G"/>
<constraint firstItem="fPD-rO-ZgU" firstAttribute="trailing" secondItem="fTK-nk-bN9" secondAttribute="trailing" id="XRW-xO-sGx"/>
<constraint firstItem="cxl-Av-gEU" firstAttribute="top" secondItem="23B-pX-ODs" secondAttribute="top" id="Y0G-Ua-UcP"/>
<constraint firstItem="QHo-nZ-miK" firstAttribute="centerX" secondItem="fPD-rO-ZgU" secondAttribute="centerX" id="ZkK-bD-6Ys"/>
@@ -1491,6 +1537,7 @@
<constraint firstItem="ygH-wj-cLk" firstAttribute="top" secondItem="cxl-Av-gEU" secondAttribute="bottom" id="rb7-EW-WCc"/>
<constraint firstItem="fPD-rO-ZgU" firstAttribute="trailing" secondItem="cxl-Av-gEU" secondAttribute="trailing" id="usz-Hi-BR2"/>
<constraint firstItem="fPD-rO-ZgU" firstAttribute="bottom" secondItem="fTK-nk-bN9" secondAttribute="bottom" constant="-20" id="vmC-a4-Yy3"/>
<constraint firstItem="n3b-MP-wOW" firstAttribute="top" secondItem="cxl-Av-gEU" secondAttribute="bottom" constant="10" id="xGm-9v-fwc"/>
</constraints>
</view>
<tabBarItem key="tabBarItem" title="MY LIST" image="HeartIcon" id="dhn-IV-GcD"/>
@@ -1510,17 +1557,21 @@
<outlet property="karaokeViewBtn" destination="MNq-YB-EUG" id="nhX-tu-YWQ"/>
<outlet property="noDataStack" destination="QHo-nZ-miK" id="mA1-FT-iQl"/>
<outlet property="scrollView" destination="SyC-Qw-kzE" id="0xd-Wb-TU1"/>
<outlet property="shimmerStack" destination="n3b-MP-wOW" id="taO-4R-ZPG"/>
<outlet property="webSeriesBtn" destination="zNj-21-nce" id="Tkc-4Z-odt"/>
<outlet property="webSeriesCV" destination="6Y6-vJ-OYT" id="FRf-D2-kxM"/>
<outlet property="webSeriesEnglishStack" destination="vZT-j7-NyY" id="HG5-LW-alT"/>
<outlet property="webSeriesHindiBtn" destination="PHL-y5-hHs" id="5Ez-Te-6El"/>
<outlet property="webSeriesHindiCV" destination="aW7-x8-HRh" id="eJM-QC-gIw"/>
<outlet property="webSeriesHindiStack" destination="h1g-o9-Qbb" id="cbP-E3-4Bc"/>
<outletCollection property="shimmerView" destination="zVG-vD-Pa9" collectionClass="NSMutableArray" id="zku-q7-DXa"/>
<outletCollection property="shimmerView" destination="5PD-9x-fXz" collectionClass="NSMutableArray" id="JrO-dN-fRP"/>
<outletCollection property="shimmerView" destination="LMU-lo-nNz" collectionClass="NSMutableArray" id="Va8-vH-tav"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="lPK-ME-Nlb" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="2198.5507246376815" y="977.67857142857133"/>
<point key="canvasLocation" x="2197.6744186046512" y="977.2532188841202"/>
</scene>
<!--EXPLORE WOKA-->
<scene sceneID="taU-OT-R2P">

View File

@@ -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: [])

View File

@@ -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)
// }
}
}

View File

@@ -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

View File

@@ -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() {

View File

@@ -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<CommonResponseModel, NetworkManager.APIError>) 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)
}
}
}
}

View File

@@ -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

View File

@@ -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<NSManagedObject>(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<NSFetchRequestResult> = 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<NSFetchRequestResult> = 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<NSFetchRequestResult> = 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<NSFetchRequestResult>(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<NSFetchRequestResult> = 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
}

View File

@@ -1098,19 +1098,19 @@
<cells/>
</collectionView>
<stackView hidden="YES" opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="Nqj-wh-mOZ">
<rect key="frame" x="113.66666666666669" y="295.66666666666669" width="166" height="245.66666666666669"/>
<rect key="frame" x="93.666666666666686" y="295.66666666666669" width="206" height="245.66666666666669"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="SupportGirlImage" translatesAutoresizingMaskIntoConstraints="NO" id="aKI-uI-tys">
<rect key="frame" x="0.0" y="0.0" width="166" height="166"/>
<rect key="frame" x="0.0" y="0.0" width="206" height="166"/>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="No Blogs Found" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="h4b-OB-vin" customClass="LocalisedElementsLabel" customModule="WOKA" customModuleProvider="target">
<rect key="frame" x="0.0" y="176" width="166" height="24"/>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="No Notification Found" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="h4b-OB-vin" customClass="LocalisedElementsLabel" customModule="WOKA" customModuleProvider="target">
<rect key="frame" x="0.0" y="176" width="206" height="24"/>
<fontDescription key="fontDescription" name="Exo2-Bold" family="Exo 2" pointSize="20"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="JCl-tp-aCA">
<rect key="frame" x="0.0" y="210" width="166" height="35.666666666666657"/>
<rect key="frame" x="0.0" y="210" width="206" height="35.666666666666657"/>
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<state key="normal" title="Button"/>
<buttonConfiguration key="configuration" style="plain">
@@ -1319,7 +1319,7 @@
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
<systemColor name="systemBrownColor">
<color red="0.63529411759999999" green="0.51764705879999995" blue="0.36862745099999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color red="0.63529411764705879" green="0.51764705882352946" blue="0.36862745098039218" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</systemColor>
</resources>
</document>

View File

@@ -41,7 +41,7 @@ class MoreVC: UIViewController {
@IBAction func playTrailerBtnTapped(_ sender: LocalisedElementsButton) {
PersistentStorage.shared.addTrailerCount()
let item = JwPlayerItemCreate(url: APIEndPoints.StaticURLs.masilaUrl, poster: nil, titles: "Masila")
JWPlayerManager.shared.presentPlayer(from: self, playerItems: [item], contentType: .trailer)
JWPlayerManager.shared.presentPlayer(from: self, playerItems: [item], contentType: .trailer, videoIDs: [0])
}
}
@@ -256,45 +256,45 @@ extension MoreVC : UICollectionViewDelegateFlowLayout{
}
class VideoAVPlayer {
var player: AVPlayer?
var playerObserver: NSKeyValueObservation?
var status = PlayerStatus.loading
init(url: URL) {
self.player = AVPlayer(url: url)
observePlayer()
}
private func observePlayer() {
playerObserver = player?.observe(\.timeControlStatus, options: [.new, .old], changeHandler: { [weak self] player, change in
guard let self = self else { return }
switch player.timeControlStatus {
case .playing:
print("Player is playing")
self.status = .play
case .paused:
print("Player is paused")
self.status = .pause
case .waitingToPlayAtSpecifiedRate:
print("Player is waiting to play at specified rate")
self.status = .loading
@unknown default:
print("Unknown player status")
}
})
}
deinit {
playerObserver?.invalidate()
}
func play() {
player?.play()
}
func pause() {
player?.pause()
}
}
//class VideoAVPlayer {
//
// var player: AVPlayer?
// var playerObserver: NSKeyValueObservation?
// var status = PlayerStatus.loading
//
// init(url: URL) {
// self.player = AVPlayer(url: url)
// observePlayer()
// }
//
// private func observePlayer() {
// playerObserver = player?.observe(\.timeControlStatus, options: [.new, .old], changeHandler: { [weak self] player, change in
// guard let self = self else { return }
// switch player.timeControlStatus {
// case .playing:
// print("Player is playing")
// self.status = .play
// case .paused:
// print("Player is paused")
// self.status = .pause
// case .waitingToPlayAtSpecifiedRate:
// print("Player is waiting to play at specified rate")
// self.status = .loading
// @unknown default:
// print("Unknown player status")
// }
// })
// }
//
// deinit {
// playerObserver?.invalidate()
// }
//
// func play() {
// player?.play()
// }
//
// func pause() {
// player?.pause()
// }
//}

View File

@@ -9,7 +9,7 @@ import UIKit
import JWPlayerKit
import AVKit
class PlayerVC: JWPlayerViewController, JWPlayerViewControllerDelegate {
class PlayerVC: JWPlayerViewController, JWPlayerViewControllerDelegate{
@IBOutlet weak var backButton: UIButton!
var previousScale: CGFloat = 1.0
@@ -19,8 +19,17 @@ class PlayerVC: JWPlayerViewController, JWPlayerViewControllerDelegate {
var config: JWPlayerConfiguration!
var dismissTapped: (() -> Void)?
var videoIndex : Int?
var isFullScreenBtn = false
var vm = PlayerVM()
deinit {
NotificationCenter.default.removeObserver(self,name: UIApplication.didEnterBackgroundNotification, object: nil)
NotificationCenter.default.removeObserver(self,name: UIApplication.willEnterForegroundNotification, object: nil)
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .allButUpsideDown
}
@@ -31,40 +40,20 @@ class PlayerVC: JWPlayerViewController, JWPlayerViewControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
vm.vc = self
vm.initView()
// rotateView(to: .pi / 2) // Example: 90 degrees rotation
//bring back button to the front
self.view.bringSubviewToFront(backButton)
// NotificationCenter.default.addObserver(self, selector: #selector(appDidEnterBackground), name: UIApplication.didEnterBackgroundNotification, object: nil)
// NotificationCenter.default.addObserver(self, selector: #selector(appWillEnterForeground), name: UIApplication.willEnterForegroundNotification, 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 appDidEnterBackground() {
// Code to execute when the app enters the background
print("App entered background PlayerVC")
if UIApplication.topViewController() == self{
player.stop()
}
}
@objc func appWillEnterForeground() {
// Code to execute when the app enters the foreground
print("App will enter foreground PlayerVC")
if UIApplication.topViewController() == self{
player.play()
}
}
// func rotateView(to angle: CGFloat) {
// // Apply rotation to the view's transform
// view.transform = CGAffineTransform(rotationAngle: angle)
// }
@objc func applicationDidBecomeActive() {
// self.setDeviceOrientation(orientation: .landscapeRight)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
@@ -88,77 +77,147 @@ class PlayerVC: JWPlayerViewController, JWPlayerViewControllerDelegate {
}
@IBAction func backBtnTapped(_ sender: UIButton) {
handleBackAction()
}
func handleBackAction(){
self.interfaceBehavior = .hidden
self.player.stop()
if contentType == .liveStream{
self.dismissTapped?()
}
appDelegate.deviceOrientation = .portrait
updateClicks()
let value = UIInterfaceOrientation.portrait.rawValue
UIDevice.current.setValue(value, forKey: "orientation")
UIViewController.attemptRotationToDeviceOrientation()
}
func updateClicks(){
switch contentType {
case .liveStream:
PersistentStorage.shared.addLiveTVCount()
// case .webSeries:
//// PersistentStorage.shared.addOthersCount()
if let postID = vm.videoIDs.first {
let duration = DateFormatterLib.dateDifferenceINT(date1: vm.startTimeStamp, date2: Date())
let totalDuration = duration + vm.totalVideoViewTime
AuthFunc.shareInstance.userVideoView(postID: postID, postType: PostType.liveTV.rawValue, duration: totalDuration, catID: 0) { _ in}
vm.handleBackAction()
}
case .webSeries:
if let catID = vm.catID, vm.currentPlayingIndex >= 0 && vm.currentPlayingIndex < (vm.videoIDs.count - 1) {
let postID = vm.videoIDs[vm.currentPlayingIndex]
let duration = DateFormatterLib.dateDifferenceINT(date1: vm.startTimeStamp, date2: Date())
let totalDuration = duration + vm.totalVideoViewTime
Utilities.startProgressHUD(msg: K.ConstantString.sync)
AuthFunc.shareInstance.userVideoView(postID: postID, postType: PostType.episode.rawValue, duration: totalDuration, catID: catID) { [weak self] isDone in
guard let self else{return}
if isDone{
Utilities.dismissProgressHUD()
vm.handleBackAction()
K.GVar.reloadContinueWebSeries = true
}else{
Utilities.dismissProgressHUD()
vm.handleBackAction()
}
}
} else {
vm.handleBackAction()
}
case .trailer:
PersistentStorage.shared.addTrailerCount()
// case .continueWatching:
// <#code#>
// case .audioBooks:
// <#code#>
// case .games:
// <#code#>
// case .songs:
// <#code#>
case nil:
let duration = DateFormatterLib.dateDifferenceINT(date1: vm.startTimeStamp, date2: Date())
let totalDuration = duration + vm.totalVideoViewTime
AuthFunc.shareInstance.userVideoView(postID: 0, postType: PostType.episode.rawValue, duration: totalDuration, catID: 0) { _ in}
vm.handleBackAction()
case .continueWatching:
if let catID = vm.catID,let postID = vm.videoIDs.first{
let duration = DateFormatterLib.dateDifferenceINT(date1: vm.startTimeStamp, date2: Date())
let totalDuration = duration + vm.totalVideoViewTime
Utilities.startProgressHUD(msg: K.ConstantString.sync)
AuthFunc.shareInstance.userVideoView(postID: postID, postType: PostType.episode.rawValue, duration: totalDuration, catID: catID) { [weak self] isDone in
guard let self else{return}
if isDone{
Utilities.dismissProgressHUD()
vm.handleBackAction()
K.GVar.reloadContinueWebSeries = true
}else{
Utilities.dismissProgressHUD()
vm.handleBackAction()
}
}
} else {
vm.handleBackAction()
}
case .audioBooks:
if let postID = vm.videoIDs.first {
let duration = DateFormatterLib.dateDifferenceINT(date1: vm.startTimeStamp, date2: Date())
let totalDuration = duration + vm.totalVideoViewTime
Utilities.startProgressHUD(msg: K.ConstantString.sync)
AuthFunc.shareInstance.userVideoView(postID: postID, postType: PostType.audio.rawValue, duration: totalDuration, catID: 0) { [weak self] isDone in
guard let self else{
Utilities.dismissProgressHUD()
return
}
if isDone{
Utilities.dismissProgressHUD()
vm.handleBackAction()
}else{
Utilities.dismissProgressHUD()
vm.handleBackAction()
}
}
}
case .games:
break
case .songs:
break
default:
vm.handleBackAction()
}
}
// MARK: - App LifeCycle Handling
@objc func appDidEnterBackground() {
print("App entered background PlayerVC")
player.pause()
//Update uservideo view
switch contentType {
case .liveStream:
vm.updateUserView()
case .webSeries:
vm.updateUserView()
case .trailer:
vm.updateUserView()
case .continueWatching:
vm.updateUserView()
case .audioBooks:
vm.updateUserView()
case .games:
break
case .songs:
break
default:
break
}
}
@objc func appWillEnterForeground() {
print("App will enter foreground PlayerVC")
//Reset StartTimestamp
vm.startTimeStamp = Date()
player.play()
}
// MARK: - Handle Screen Transition
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
coordinator.animate(alongsideTransition: nil) { _ in
self.checkOrientation()
}
}
private func checkOrientation() {
let isPortrait = UIScreen.main.bounds.size.width < UIScreen.main.bounds.size.height
if isPortrait {
print("Device is in portrait mode")
Timer.scheduledTimer(withTimeInterval: 0.4, repeats: false) { _ in
self.dismiss(animated: true)
}
} else {
print("Device is in landscape mode")
if isFullScreenBtn{
appDelegate.deviceOrientation = .portrait
let value = UIInterfaceOrientation.portrait.rawValue
UIDevice.current.setValue(value, forKey: "orientation")
UIViewController.attemptRotationToDeviceOrientation()
}
coordinator.animate(alongsideTransition: nil) { [weak self] _ in
guard let self else{return}
vm.checkOrientation()
}
}
// MARK: - JWPlayerViewControllerDelegate
// override func jwplayerPlaylistHasCompleted(_ player: any JWPlayer) {
// print("PlayList Over")
// }
// this will give index
override func jwplayer(_ player: any JWPlayer, didLoadPlaylistItem item: JWPlayerItem, at index: UInt) {
super.jwplayer(player, didLoadPlaylistItem: item, at: index)
print("didLoadPlaylistItem ", index)
vm.currentPlayingIndex = Int(index)
}
override func jwplayer(_ player: any JWPlayer, didFinishLoadingWithTime loadTime: TimeInterval) {
super.jwplayer(player, didFinishLoadingWithTime: loadTime)
print("LoadTime", loadTime)
@@ -194,8 +253,6 @@ class PlayerVC: JWPlayerViewController, JWPlayerViewControllerDelegate {
case nil:
break
}
print("IsReady")
}
@@ -211,19 +268,19 @@ class PlayerVC: JWPlayerViewController, JWPlayerViewControllerDelegate {
DispatchQueue.main.async {
Utilities.alertWithBtnCancelCompletion(title: "Error", msgBody: message, okBtnStr: "Connect", vc: self) { [weak self] isDone in
guard let self else{
self?.handleBackAction()
self?.vm.handleBackAction()
return
}
if isDone{
self.player.configurePlayer(with: config)
self.player.play()
}else{
self.handleBackAction()
self.vm.handleBackAction()
}
}
}
}
override func jwplayer(_ player: JWPlayer, encounteredWarning code: UInt, message: String) {
super.jwplayer(player, encounteredWarning: code, message: message)
//Handle the reconnecting of video here
@@ -250,7 +307,7 @@ class PlayerVC: JWPlayerViewController, JWPlayerViewControllerDelegate {
override func jwplayer(_ player: JWPlayer, didPauseWithReason reason: JWPauseReason) {
super.jwplayer(player, didPauseWithReason: reason)
if reason == .interaction{
updateClicks()
vm.updateClicks()
}
// Implement custom behavior
}
@@ -259,10 +316,10 @@ class PlayerVC: JWPlayerViewController, JWPlayerViewControllerDelegate {
override func jwplayer(_ player: JWPlayer, isPlayingWithReason reason: JWPlayReason) {
super.jwplayer(player, isPlayingWithReason: reason)
if reason == .interaction{
updateClicks()
vm.updateClicks()
}
}
}
// MARK: - Full Screen Handling
@@ -289,13 +346,19 @@ extension PlayerVC {
}
func playerViewControllerWillDismissFullScreen(_ controller: JWPlayerViewController) {
switch contentType {
case .audioBooks,.liveStream,.webSeries, .continueWatching, .trailer:
vm.updateUserView()
default:
break
}
print("playerViewControllerWillDismissFullScreen")
}
func playerViewControllerDidDismissFullScreen(_ controller: JWPlayerViewController) {
print("playerViewControllerDidDismissFullScreen")
appDelegate.deviceOrientation = .portrait
updateClicks()
vm.updateClicks()
let value = UIInterfaceOrientation.portrait.rawValue
UIDevice.current.setValue(value, forKey: "orientation")
UIViewController.attemptRotationToDeviceOrientation()
@@ -327,7 +390,7 @@ extension PlayerVC {
}
func playerViewController(_ controller: JWPlayerKit.JWPlayerViewController, relatedItemBeganPlaying item: JWPlayerKit.JWPlayerItem, atIndex index: Int, withMethod method: JWPlayerKit.JWRelatedMethod) {
print("Item ", item)
print("Item ", item, index)
}
}

View File

@@ -128,6 +128,8 @@ class ThemeOneVC: UIViewController {
let sb = UIStoryboard(name: K.StoryBoard.theme, bundle: nil)
let vcPush = sb.instantiateViewController(withIdentifier: K.StoryBoardID.Home.userNotificationVC) as! UserNotificationVC
self.navigationController?.pushViewController(vcPush, animated: true)
PersistentStorage.shared.sendDataToServer()
}
@IBAction func radioBtnTapped(_ sender: UIButton) {

View File

@@ -6,6 +6,7 @@
//
import UIKit
import AVFAudio
class ThemeTwoVC: UIViewController {
@@ -44,6 +45,9 @@ class ThemeTwoVC: UIViewController {
override func viewDidAppear(_ animated: Bool) {
K.GVar.topView = .theme2
if let player = vm.avPlayer{
player.play()
}
}
override func viewDidLayoutSubviews() {
@@ -72,7 +76,7 @@ class ThemeTwoVC: UIViewController {
@IBAction func playTrailer(_ sender: LocalisedElementsButton) {
PersistentStorage.shared.addOthersCount()
let item = JwPlayerItemCreate(url: APIEndPoints.StaticURLs.masilaUrl, poster: nil, titles: "Masila")
JWPlayerManager.shared.presentPlayer(from: self, playerItems: [item], contentType: .trailer)
JWPlayerManager.shared.presentPlayer(from: self, playerItems: [item], contentType: .trailer, videoIDs: [0])
}
}

View File

@@ -41,9 +41,12 @@ class MoreVM{
vc.songTableView.showsVerticalScrollIndicator = false
vc.songTableView.showsHorizontalScrollIndicator = false
vc.homeBtn.addTapGesture {
self.vc.dismiss(animated: true) {
PersistentStorage.shared.addOthersCount()
vc.homeBtn.addTapGesture { [weak self] in
guard let self else{return}
DispatchQueue.main.async{
self.vc.dismiss(animated: true) {
PersistentStorage.shared.addOthersCount()
}
}
}
}

View File

@@ -0,0 +1,172 @@
//
// PlayerVM.swift
// WOKA
//
// Created by Bilal on 16/08/2024.
//
import UIKit
class PlayerVM{
weak var vc : PlayerVC!
// this will map the start time
var startTimeStamp = Date()
var totalVideoViewTime = 0
// this will come from webseries, audiobooks, live tv
var videoIDs = [Int]()
// this will come only for webseries
var catID : Int?
// this will store the index of the item playing
var currentPlayingIndex = 0
func initView(){
switch vc.contentType {
case .liveStream, .trailer, .continueWatching, .audioBooks:
startTimeStamp = Date()
// case .games:
// <#code#>
// case .songs:
// <#code#>
case nil:
break
default:
break
}
}
// MARK: - Update UserVideo View
func updateUserView(){
switch vc.contentType {
case .liveStream:
if let postID = videoIDs.first {
let duration = DateFormatterLib.dateDifferenceINT(date1: startTimeStamp, date2: Date())
let totalDuration = duration + totalVideoViewTime
startTimeStamp = Date()
AuthFunc.shareInstance.userVideoView(postID: postID, postType: PostType.liveTV.rawValue, duration: totalDuration, catID: 0) { isDone in
if isDone{
K.GVar.reloadContinueAudioBooks = true
}else{
}
}
}
case .webSeries:
if let catID = catID, currentPlayingIndex >= 0 && currentPlayingIndex < (videoIDs.count - 1) {
let postID = videoIDs[currentPlayingIndex]
let duration = DateFormatterLib.dateDifferenceINT(date1: startTimeStamp, date2: Date())
let totalDuration = duration + totalVideoViewTime
startTimeStamp = Date()
AuthFunc.shareInstance.userVideoView(postID: postID, postType: PostType.episode.rawValue, duration: totalDuration, catID: catID) { isDone in
if isDone{
K.GVar.reloadContinueWebSeries = true
}
}
}
case .trailer:
let duration = DateFormatterLib.dateDifferenceINT(date1: startTimeStamp, date2: Date())
let totalDuration = duration + totalVideoViewTime
AuthFunc.shareInstance.userVideoView(postID: 0, postType: PostType.episode.rawValue, duration: totalDuration, catID: 0) { _ in}
case .continueWatching:
if let catID = catID , let postID = videoIDs.first{
let duration = DateFormatterLib.dateDifferenceINT(date1: startTimeStamp, date2: Date())
let totalDuration = duration + totalVideoViewTime
startTimeStamp = Date()
AuthFunc.shareInstance.userVideoView(postID: postID, postType: PostType.episode.rawValue, duration: totalDuration, catID: catID) { isDone in
if isDone{
K.GVar.reloadContinueWebSeries = true
}
}
}
case .audioBooks:
if let postID = videoIDs.first {
let duration = DateFormatterLib.dateDifferenceINT(date1: startTimeStamp, date2: Date())
let totalDuration = duration + totalVideoViewTime
startTimeStamp = Date()
AuthFunc.shareInstance.userVideoView(postID: postID, postType: PostType.audio.rawValue, duration: totalDuration, catID: 0) { isDone in
if isDone{
K.GVar.reloadContinueAudioBooks = true
}else{
}
}
}
// case .games:
// <#code#>
// case .songs:
// <#code#>
case nil:
break
default:
break
}
}
// MARK: - Handle Back btn tap, and update clicks
func handleBackAction(){
self.vc.interfaceBehavior = .hidden
self.vc.player.stop()
if vc.contentType == .liveStream{
self.vc.dismissTapped?()
}
appDelegate.deviceOrientation = .portrait
updateClicks()
let value = UIInterfaceOrientation.portrait.rawValue
UIDevice.current.setValue(value, forKey: "orientation")
UIViewController.attemptRotationToDeviceOrientation()
}
func updateClicks(){
switch vc.contentType {
case .liveStream:
PersistentStorage.shared.addLiveTVCount()
// case .webSeries:
//// PersistentStorage.shared.addOthersCount()
case .trailer:
PersistentStorage.shared.addTrailerCount()
// case .continueWatching:
// <#code#>
// case .audioBooks:
// <#code#>
// case .games:
// <#code#>
// case .songs:
// <#code#>
case nil:
break
default:
break
}
}
// MARK: - Orientation check
func checkOrientation() {
let isPortrait = UIScreen.main.bounds.size.width < UIScreen.main.bounds.size.height
if isPortrait {
print("Device is in portrait mode")
Timer.scheduledTimer(withTimeInterval: 0.4, repeats: false) { _ in
self.vc.dismiss(animated: true)
}
} else {
print("Device is in landscape mode")
if vc.isFullScreenBtn{
appDelegate.deviceOrientation = .portrait
let value = UIInterfaceOrientation.portrait.rawValue
UIDevice.current.setValue(value, forKey: "orientation")
UIViewController.attemptRotationToDeviceOrientation()
}
}
}
}

View File

@@ -205,8 +205,6 @@ class ThemeOneVM{
vcPush.modalPresentationStyle = .fullScreen
vcPush.modalTransitionStyle = .crossDissolve
self.vc.present(vcPush, animated: true)
// PersistentStorage.shared.sendDataToServer()
}
/*
1 = series, 2 = season, 3= episode, 4 = video, 5 = paint, 6 = game, 7 = audio, 8 = kareoke video, 9 = shop product, 10 = parental video, 11 = article, 12 = live TV, 13 = FM, 14 = teaser, 15 others, 16 = Home
@@ -441,6 +439,9 @@ class ThemeOneVM{
vc.config = config
vc.dismissTapped = self.tapped
vc.contentType = .liveStream
if let streamID = AuthFunc.shareInstance.staticURLs?.liveData?.first?.id{
vc.vm.videoIDs = [streamID]
}
vc.modalPresentationStyle = .fullScreen
vc.modalTransitionStyle = .crossDissolve

View File

@@ -19,13 +19,45 @@ class WokaFMVC: UIViewController {
@IBOutlet weak var activityIndicator: UIActivityIndicatorView!
var vm = WokaFMVM()
deinit {
vm.playerItem.removeObserver(self, forKeyPath: "status")
vm.player.removeObserver(self, forKeyPath: "timeControlStatus")
vm.playerItem.removeObserver(self, forKeyPath: "isPlaybackBufferEmpty")
vm.playerItem.removeObserver(self, forKeyPath: "isPlaybackLikelyToKeepUp")
vm.player?.pause()
NotificationCenter.default.removeObserver(self,name: UIApplication.didEnterBackgroundNotification, object: nil)
// Deactivate the audio session if needed
do {
try AVAudioSession.sharedInstance().setActive(false, options: .notifyOthersOnDeactivation)
} catch {
print("Failed to deactivate audio session: \(error.localizedDescription)")
}
}
override func viewDidLoad() {
super.viewDidLoad()
vm.vc = self
vm.initView()
NotificationCenter.default.addObserver(self,selector: #selector(appDidEnterBackground),name: UIApplication.didEnterBackgroundNotification,object: nil)
}
// MARK: - App LifeCycle HAndler
@objc func appDidEnterBackground() {
if let postID = AuthFunc.shareInstance.staticURLs?.liveFmData?.id {
let duration = DateFormatterLib.dateDifferenceINT(date1: vm.startTimeStamp, date2: Date())
AuthFunc.shareInstance.userVideoView(postID: postID, postType: PostType.FM.rawValue, duration: duration, catID: 0) { [weak self] isDone in
guard let self else{return}
if isDone{
vm.startTimeStamp = Date()
}
}
}
}
@IBAction func playBtnTapped(_ sender: UIButton) {
PersistentStorage.shared.addRadioCount()
if sender == playBtn{
@@ -71,6 +103,10 @@ class WokaFMVC: UIViewController {
@IBAction func closeBtnTapped(_ sender: UIButton) {
PersistentStorage.shared.addRadioCount()
if let postID = AuthFunc.shareInstance.staticURLs?.liveFmData?.id {
let duration = DateFormatterLib.dateDifferenceINT(date1: vm.startTimeStamp, date2: Date())
AuthFunc.shareInstance.userVideoView(postID: postID, postType: PostType.FM.rawValue, duration: duration, catID: 0) { _ in}
}
self.dismiss(animated: true)
}
@@ -151,22 +187,6 @@ class WokaFMVC: UIViewController {
}
}
}
deinit {
vm.playerItem.removeObserver(self, forKeyPath: "status")
vm.player.removeObserver(self, forKeyPath: "timeControlStatus")
vm.playerItem.removeObserver(self, forKeyPath: "isPlaybackBufferEmpty")
vm.playerItem.removeObserver(self, forKeyPath: "isPlaybackLikelyToKeepUp")
vm.player?.pause()
// Deactivate the audio session if needed
do {
try AVAudioSession.sharedInstance().setActive(false, options: .notifyOthersOnDeactivation)
} catch {
print("Failed to deactivate audio session: \(error.localizedDescription)")
}
}
}

View File

@@ -15,7 +15,10 @@ class WokaFMVM{
var player: AVPlayer!
var playerItem: AVPlayerItem!
var startTimeStamp = Date()
func initView(){
startTimeStamp = Date()
vc.mainView.roundCorners(radius: 10, corners: [.topLeft, .topRight])
let color1 = #colorLiteral(red: 0.5921568627, green: 0.2588235294, blue: 0.8941176471, alpha: 1)
let color2 = #colorLiteral(red: 0.368627451, green: 0.1215686275, blue: 0.768627451, alpha: 1)

View File

@@ -81,7 +81,6 @@
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
<state key="normal" image="speaker.wave.1.fill" catalog="system"/>
<connections>
<action selector="playBtnTapped:" destination="Y6W-OH-hqX" eventType="touchUpInside" id="YJE-XF-HOm"/>
<action selector="volumeBtnTapped:" destination="Y6W-OH-hqX" eventType="touchUpInside" id="bZA-9P-p0X"/>
</connections>
</button>

View File

@@ -64,8 +64,8 @@ class ContinueWatchingVC: UIViewController {
}
@IBAction func watchBtnTapped(_ sender: LocalisedElementsButton) {
guard let watchData else{return}
if let showID = watchData.id, let catID = self.categoryID{
guard let watchData ,let showID = watchData.id else{return}
if let catID = self.categoryID{
PersistentStorage.shared.addWebSeries(catID: catID, postID: showID, postType: .episode)
}
@@ -88,7 +88,7 @@ class ContinueWatchingVC: UIViewController {
playerItem.url = url
}
JWPlayerManager.shared.presentPlayer(from: self, playerItems: [playerItem], startIndex: 0, contentType: .continueWatching)
JWPlayerManager.shared.presentPlayer(from: self, playerItems: [playerItem], startIndex: 0, contentType: .continueWatching,videoIDs: [showID], catID: categoryID)
}

View File

@@ -107,7 +107,7 @@ class WebSeriesSeasonVC: UIViewController {
playerItems.append(JwPlayerItemCreate(url: url, poster: seasonData.thumbnailPath, titles: hindiData.title))
}
JWPlayerManager.shared.presentPlayer(from: self, playerItems: playerItems, startIndex: 0, contentType: .trailer)
JWPlayerManager.shared.presentPlayer(from: self, playerItems: playerItems, startIndex: 0, contentType: .trailer, videoIDs: [0])
}
@IBAction func loadMoreBtnTapped(_ sender: LocalisedElementsButton) {
@@ -186,53 +186,7 @@ extension WebSeriesSeasonVC : TableViewSRC{
playerItems.append(JwPlayerItemCreate(url: url, poster: teaserData.thumbnailPath, titles: hindiData.title))
}
JWPlayerManager.shared.presentPlayer(from: self, playerItems: playerItems, startIndex: indexPath.row, contentType: .trailer)
// let builder = JWPlayerConfigurationBuilder()
//
// do {
// let playlist: [JSONObject] = [
// [
// "file": "https://cdn.jwplayer.com/manifests/gzIo9zlJ.m3u8",
// "title": "First Video Title"
// ],
// [
// "file": "https://cdn.jwplayer.com/manifests/pDu0xxUh.m3u8", // replace with the second video URL
// "title": "Second Video Title",
//
// ]
// ]
//
// let json: JSONObject = [
// "playlist": playlist,
// "playlistIndex": 1,
// "videoGravity" : "resize"
// ]
//
// try builder.configuration(json: json).build()
//
// let config = try builder.configuration(json: json).build()
// let sb = UIStoryboard(name: K.StoryBoard.theme, bundle: nil)
// let vc = sb.instantiateViewController(withIdentifier: K.StoryBoardID.Theme.playerVC) as! PlayerVC
//
// vc.config = config
// vc.contentType = .liveStream
// vc.modalPresentationStyle = .fullScreen
// vc.modalTransitionStyle = .crossDissolve
//
// DispatchQueue.main.async { [weak self] in
// guard let self else{return}
// // Present the PlayerVC
// self.present(vc, animated: false) { [weak self] in
//
// }
// }
//// player.configurePlayer(with: config)
// } catch {
// // Handle build errors
// print("Failed to build JWPlayer configuration: \(error.localizedDescription)")
// }
JWPlayerManager.shared.presentPlayer(from: self, playerItems: playerItems, startIndex: indexPath.row, contentType: .trailer, videoIDs: [0])
case self.episodeTableView:
let episodeData = vm.seasonEpisodeData
@@ -240,10 +194,15 @@ extension WebSeriesSeasonVC : TableViewSRC{
if let showID = episodeData[indexPath.row].id, let catID = self.vm.categoryID{
PersistentStorage.shared.addWebSeries(catID: catID, postID: showID, postType: .episode)
}
var videoIDs = [Int]()
for i in episodeData{
var url = String()
guard let englishData = i.contentMoreDetails?.filter({$0.languageMasterID == 1}).first, let hindiData = i.contentMoreDetails?.filter({$0.languageMasterID == 2}).first else{return}
if let id = i.id{
videoIDs.append(id)
}
/*
Based on selected Category language update the url
*/
@@ -263,7 +222,7 @@ extension WebSeriesSeasonVC : TableViewSRC{
}
}
JWPlayerManager.shared.presentPlayer(from: self, playerItems: playerItems, startIndex: indexPath.row, contentType: .webSeries)
JWPlayerManager.shared.presentPlayer(from: self, playerItems: playerItems, startIndex: indexPath.row, contentType: .webSeries, videoIDs: videoIDs, catID: vm.categoryID)
default:
break
}
@@ -317,11 +276,16 @@ extension WebSeriesSeasonVC : TableViewSRC{
}else{
playerItems.append(JwPlayerItemCreate(url: url, poster: teaserData.thumbnailPath, titles: hindiData.title))
}
JWPlayerManager.shared.presentPlayer(from: self, playerItems: playerItems,startIndex: indexPath.row, contentType: .trailer)
JWPlayerManager.shared.presentPlayer(from: self, playerItems: playerItems,startIndex: indexPath.row, contentType: .trailer, videoIDs: [0])
case self.episodeTableView:
let episodeData = vm.seasonEpisodeData
var videoIDs = [Int]()
for i in episodeData{
var url = String()
if let id = i.id{
videoIDs.append(id)
}
guard let englishData = i.contentMoreDetails?.filter({$0.languageMasterID == 1}).first, let hindiData = i.contentMoreDetails?.filter({$0.languageMasterID == 2}).first else{return}
/*
Based on selected Category language update the url
@@ -342,7 +306,7 @@ extension WebSeriesSeasonVC : TableViewSRC{
}
}
JWPlayerManager.shared.presentPlayer(from: self, playerItems: playerItems, startIndex: indexPath.row, contentType: .webSeries)
JWPlayerManager.shared.presentPlayer(from: self, playerItems: playerItems, startIndex: indexPath.row, contentType: .webSeries, videoIDs: videoIDs,catID: vm.categoryID)
default:
break
}

View File

@@ -38,6 +38,8 @@ class WebSeriesVC: UIViewController {
var vm = WebSeriesVM()
private var isFirstLoad = true
override func viewDidLoad() {
super.viewDidLoad()
vm.vc = self
@@ -45,6 +47,8 @@ class WebSeriesVC: UIViewController {
vm.initView()
navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
navigationController?.navigationBar.shadowImage = UIImage()
isFirstLoad = false
}
override func viewWillAppear(_ animated: Bool) {
@@ -70,6 +74,19 @@ class WebSeriesVC: UIViewController {
self.navigationController?.setColor(color: .black)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if !isFirstLoad{
if K.GVar.reloadContinueWebSeries{
K.GVar.reloadContinueWebSeries = false
vm.getContinueWatching()
}
}else{
K.GVar.reloadContinueWebSeries = false
}
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
vm.updateTableHeight()
@@ -78,7 +95,7 @@ class WebSeriesVC: UIViewController {
// MARK: - Tap Handler
@IBAction func playTrailer(_ sender: LocalisedElementsButton) {
let item = JwPlayerItemCreate(url: APIEndPoints.StaticURLs.masilaUrl, poster: nil, titles: "Masila")
JWPlayerManager.shared.presentPlayer(from: self, playerItems: [item], contentType: .trailer)
JWPlayerManager.shared.presentPlayer(from: self, playerItems: [item], contentType: .trailer, videoIDs: [0])
PersistentStorage.shared.addTrailerCount()
}

View File

@@ -29,7 +29,7 @@ class JWPlayerManager {
private init() {}
func presentPlayer(from viewController: UIViewController,playerItems : [JwPlayerItemCreate], startIndex: Int = 0, contentType : VideoContentType , completion: (() -> Void)? = nil) {
func presentPlayer(from viewController: UIViewController,playerItems : [JwPlayerItemCreate], startIndex: Int = 0, contentType : VideoContentType , videoIDs : [Int],catID : Int? = nil, completion: (() -> Void)? = nil) {
let sb = UIStoryboard(name: K.StoryBoard.theme, bundle: nil)
let playerVC = sb.instantiateViewController(identifier: K.StoryBoardID.Theme.playerVC) as! PlayerVC
@@ -133,7 +133,8 @@ class JWPlayerManager {
playerVC.videoIndex = startIndex
playerVC.contentType = contentType
playerVC.config = finalConfig
playerVC.vm.videoIDs = videoIDs
playerVC.vm.catID = catID
playerVC.modalPresentationStyle = .fullScreen
playerVC.modalTransitionStyle = .crossDissolve
// Present the PlayerVC