- Implemented ADs with api for getting the app.

- Added impressions and click count on the given ads with id.
- - TC 62
- TC 64
- TC 65, 63
- TC 59 fixed
This commit is contained in:
2024-09-04 20:17:33 +05:30
parent d136a59680
commit 9f5bc313a1
35 changed files with 769 additions and 153 deletions

View File

@@ -94,6 +94,8 @@
526A43752C36AA4A00AE148F /* GamesListVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 526A43742C36AA4A00AE148F /* GamesListVC.swift */; };
5272FCE32BDFDB05000ECB1D /* UserDetailsRegisterVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5272FCE22BDFDB05000ECB1D /* UserDetailsRegisterVC.swift */; };
5272FCE52BDFDC8C000ECB1D /* UserDetailsRegisterVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5272FCE42BDFDC8C000ECB1D /* UserDetailsRegisterVM.swift */; };
5276865F2C8879FD001A5496 /* AdClicksImpressions+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5276865D2C8879FD001A5496 /* AdClicksImpressions+CoreDataClass.swift */; };
527686602C8879FD001A5496 /* AdClicksImpressions+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5276865E2C8879FD001A5496 /* AdClicksImpressions+CoreDataProperties.swift */; };
527A2BC62C576EAF0080DF9B /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 527A2BC52C576EAF0080DF9B /* GoogleService-Info.plist */; };
527A2BC82C5777360080DF9B /* VerifyAddressPincodeVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 527A2BC72C5777360080DF9B /* VerifyAddressPincodeVC.swift */; };
527A2BCA2C57776A0080DF9B /* AddNewAddressVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 527A2BC92C57776A0080DF9B /* AddNewAddressVC.swift */; };
@@ -230,6 +232,7 @@
52CA28FA2BE119F500708B49 /* UserIntrestVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA28F92BE119F500708B49 /* UserIntrestVC.swift */; };
52CA28FC2BE11A0400708B49 /* UserIntrestVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA28FB2BE11A0400708B49 /* UserIntrestVM.swift */; };
52CC38C32BDF812F00B74C3E /* LocalisedElements.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CC38C22BDF812F00B74C3E /* LocalisedElements.swift */; };
52CC4A742C883B3F001BE47C /* AdsDM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CC4A732C883B3F001BE47C /* AdsDM.swift */; };
52CC85542C5BABD40084030E /* WokaFMVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CC85532C5BABD40084030E /* WokaFMVM.swift */; };
52D23F112C465E6F003E743A /* LogoutPopupVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52D23F102C465E6F003E743A /* LogoutPopupVC.swift */; };
52D2F3D82C24043D009E52FF /* ShimmerEffectView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52D2F3D72C24043D009E52FF /* ShimmerEffectView.swift */; };
@@ -493,6 +496,8 @@
526A43742C36AA4A00AE148F /* GamesListVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GamesListVC.swift; sourceTree = "<group>"; };
5272FCE22BDFDB05000ECB1D /* UserDetailsRegisterVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDetailsRegisterVC.swift; sourceTree = "<group>"; };
5272FCE42BDFDC8C000ECB1D /* UserDetailsRegisterVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDetailsRegisterVM.swift; sourceTree = "<group>"; };
5276865D2C8879FD001A5496 /* AdClicksImpressions+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AdClicksImpressions+CoreDataClass.swift"; sourceTree = "<group>"; };
5276865E2C8879FD001A5496 /* AdClicksImpressions+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AdClicksImpressions+CoreDataProperties.swift"; sourceTree = "<group>"; };
527A2BC52C576EAF0080DF9B /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
527A2BC72C5777360080DF9B /* VerifyAddressPincodeVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VerifyAddressPincodeVC.swift; sourceTree = "<group>"; };
527A2BC92C57776A0080DF9B /* AddNewAddressVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddNewAddressVC.swift; sourceTree = "<group>"; };
@@ -629,6 +634,7 @@
52CA28F92BE119F500708B49 /* UserIntrestVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserIntrestVC.swift; sourceTree = "<group>"; };
52CA28FB2BE11A0400708B49 /* UserIntrestVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserIntrestVM.swift; sourceTree = "<group>"; };
52CC38C22BDF812F00B74C3E /* LocalisedElements.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalisedElements.swift; sourceTree = "<group>"; };
52CC4A732C883B3F001BE47C /* AdsDM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdsDM.swift; sourceTree = "<group>"; };
52CC85532C5BABD40084030E /* WokaFMVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WokaFMVM.swift; sourceTree = "<group>"; };
52D23F102C465E6F003E743A /* LogoutPopupVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogoutPopupVC.swift; sourceTree = "<group>"; };
52D2F3D72C24043D009E52FF /* ShimmerEffectView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShimmerEffectView.swift; sourceTree = "<group>"; };
@@ -923,6 +929,8 @@
523ED25C2BDA2BC700CFED02 /* WOKA */ = {
isa = PBXGroup;
children = (
5276865D2C8879FD001A5496 /* AdClicksImpressions+CoreDataClass.swift */,
5276865E2C8879FD001A5496 /* AdClicksImpressions+CoreDataProperties.swift */,
52ACC1232C610CBC00791528 /* UserClicks+CoreDataClass.swift */,
52ACC1242C610CBC00791528 /* UserClicks+CoreDataProperties.swift */,
5255C3FB2C5B67C90030BB22 /* WOKAFM */,
@@ -1683,6 +1691,7 @@
525327D82BFCDDF700F64283 /* AuthFuncStartupSoundHandling.swift */,
52FDBA7A2BFF2712009D7AC7 /* AuthFuncTimeHandling.swift */,
9CC0D2F92C6F33BE0019DF73 /* AuthFuncUserVideoView.swift */,
52CC4A732C883B3F001BE47C /* AdsDM.swift */,
);
path = AuthFunc;
sourceTree = "<group>";
@@ -2375,6 +2384,7 @@
9C7939132C0EFCAE00F5D6E6 /* FaqVM.swift in Sources */,
52D774ED2BDFC13F001D87DE /* OTPVM.swift in Sources */,
52D23F112C465E6F003E743A /* LogoutPopupVC.swift in Sources */,
52CC4A742C883B3F001BE47C /* AdsDM.swift in Sources */,
527A2BD22C57B40A0080DF9B /* CartDataCache.swift in Sources */,
525327D62BFCC23600F64283 /* SideMenuVM.swift in Sources */,
525861D22C4FC6C000C33C79 /* CartPaymentOptionsVC.swift in Sources */,
@@ -2512,6 +2522,8 @@
9CA7C6C22C1095B600D73742 /* ProfileVM.swift in Sources */,
9CB3D0912C37D6930062869D /* KaraokeDetailsVC.swift in Sources */,
52E214C72C2AD47F00BC2D29 /* EpisodeDetailsVC.swift in Sources */,
5276865F2C8879FD001A5496 /* AdClicksImpressions+CoreDataClass.swift in Sources */,
527686602C8879FD001A5496 /* AdClicksImpressions+CoreDataProperties.swift in Sources */,
52D774F12BDFC53B001D87DE /* StringSubScript.swift in Sources */,
9C9BE46E2C663B1600C48D6A /* JWKaraokePlayerVM.swift in Sources */,
9CBE1B3F2C0F37B300CA6E61 /* DPDConstants.swift in Sources */,

View File

@@ -0,0 +1,15 @@
//
// AdClicksImpressions+CoreDataClass.swift
// WOKA
//
// Created by MacBook Pro on 04/09/24.
//
//
import Foundation
import CoreData
@objc(AdClicksImpressions)
public class AdClicksImpressions: NSManagedObject {
}

View File

@@ -0,0 +1,27 @@
//
// AdClicksImpressions+CoreDataProperties.swift
// WOKA
//
// Created by MacBook Pro on 04/09/24.
//
//
import Foundation
import CoreData
extension AdClicksImpressions {
@nonobjc public class func fetchRequest() -> NSFetchRequest<AdClicksImpressions> {
return NSFetchRequest<AdClicksImpressions>(entityName: "AdClicksImpressions")
}
@NSManaged public var ad_id: Int64
@NSManaged public var no_of_click: Int64
@NSManaged public var no_of_impression: Int64
}
extension AdClicksImpressions : Identifiable {
}

View File

@@ -101,8 +101,10 @@ class AddressListVM{
func checkForNoData(){
if CartDataCache.addressData.count == 0{
vc.useSelectedAddBtn.isHidden = true
vc.noDataStack.isHidden = false
}else{
vc.useSelectedAddBtn.isHidden = false
vc.noDataStack.isHidden = true
}
}

View File

@@ -13,6 +13,8 @@ class AudioBookHomeVC: UIViewController {
@IBOutlet weak var scrollView: UIScrollView!
@IBOutlet weak var headerHeight: NSLayoutConstraint!
@IBOutlet weak var headerBtn: LocalisedElementsButton!
@IBOutlet weak var headerTitleHeight: NSLayoutConstraint!
@IBOutlet weak var continueWatchingCV: UICollectionView!
@IBOutlet weak var audioListingTableView: UITableView!
@IBOutlet weak var tableHeight: NSLayoutConstraint!
@@ -71,6 +73,16 @@ class AudioBookHomeVC: UIViewController {
K.GVar.reloadContinueAudioBooks = false
vm.getContinueWatching()
}
/*
Check if ads is there to map impressions
*/
if let adsData = AuthFunc.shareInstance.adsData{
// check if ads data contains ad for webseries
if let audioBooksAd = adsData.result?.filter({$0.forPage == AdsEnum.audioBooks.rawValue}).first, let adID = audioBooksAd.id{
PersistentStorage.shared.addAdsCount(adID: adID ,impressions: 1)
}
}
}
override func viewDidLayoutSubviews() {
@@ -85,6 +97,20 @@ class AudioBookHomeVC: UIViewController {
}
@IBAction func listenAudioBtnTapped(_ sender: LocalisedElementsButton) {
/*
MAke logic for ads
*/
if let adsData = AuthFunc.shareInstance.adsData{
// check if ads data contains ad for webseries
if let audioBooksAd = adsData.result?.filter({$0.forPage == AdsEnum.audioBooks.rawValue}).first, let adLink = audioBooksAd.adLink, let adID = audioBooksAd.id{
PersistentStorage.shared.addAdsCount(adID: adID,clicks: 1)
if let url = URL(string: adLink), UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url)
}
return
}
}
guard let data = vm.headerData, let postID = data.id else{return}
PersistentStorage.shared.addAudioCount(postID: postID)
var playerItems = [JwPlayerItemCreate]()
@@ -279,16 +305,16 @@ extension AudioBookHomeVC: UIScrollViewDelegate {
// Define the height range for the header view
let minHeaderHeight: CGFloat = 0.0 // Height at which the header becomes invisible
let maxHeaderHeight: CGFloat = 200.0 // Maximum height when fully visible
// let maxHeaderHeight: CGFloat = 200.0 // Maximum height when fully visible
// Calculate the new height for the header view based on the scroll position
let newHeaderHeight: CGFloat
if y < 0 {
// When scrolling up beyond the top, ensure the header view is fully expanded
newHeaderHeight = maxHeaderHeight
newHeaderHeight = vm.maxHeaderHeight
} else {
// Calculate the new height for the header view, ensuring it doesn't go below the minimum height
newHeaderHeight = max(minHeaderHeight, maxHeaderHeight - y)
newHeaderHeight = max(minHeaderHeight, vm.maxHeaderHeight - y)
}
// Update the header view's height constraint with the new height

View File

@@ -18,6 +18,7 @@ class AudioBookHomeVM{
// var indexToLoad = 0
var pageNo = 0
var maxHeaderHeight = 0.0
func initView(){
vc.scrollView.indicatorStyle = .white // or .white
@@ -25,6 +26,10 @@ class AudioBookHomeVM{
setupCell()
getContinueWatching()
getShowListing()
//Set banner height
maxHeaderHeight = UIScreen.main.bounds.width * 0.55
vc.headerHeight.constant = maxHeaderHeight
}
func startShimmer(){
@@ -141,10 +146,31 @@ class AudioBookHomeVM{
self.vc.tableHeight.constant = self.vc.audioListingTableView.contentSize.height + 100
self.vc.audioListingTableView.layoutIfNeeded()
self.vc.tableHeight.constant = self.vc.audioListingTableView.contentSize.height
if !isBtnClick{
self.headerData = self.audioListData.first
self.setHeaderData()
/*
MAke logic for ads
*/
if let adsData = AuthFunc.shareInstance.adsData{
// check if ads data contains ad for webseries
if let audioBooksAd = adsData.result?.filter({$0.forPage == AdsEnum.audioBooks.rawValue}).first, let bannerImage = audioBooksAd.bannerImage, let buttonImage = audioBooksAd.buttonImage{
vc.headerImage.imageURL(bannerImage, color: .white)
vc.headerBtn.setTitle("", for: .normal)
vc.headerTitleLabel.text = ""
vc.headerTitleHeight.constant = 10
vc.headerBtn.backgroundColor = .clear
vc.headerBtn.sd_setBackgroundImage(with: URL(string:buttonImage), for: .normal)
}else{
if !isBtnClick{
self.headerData = self.audioListData.first
self.setHeaderData()
}
}
}else{
if !isBtnClick{
self.headerData = self.audioListData.first
self.setHeaderData()
}
}
self.stopShimmer()
self.vc.loadMoreActivityIndicator.stopAnimating()

View File

@@ -225,8 +225,10 @@
<outlet property="audioListingTableView" destination="2hg-bQ-s8S" id="zNi-4V-7ZX"/>
<outlet property="continueWatchingCV" destination="GjK-nD-NIP" id="noB-jL-jX9"/>
<outlet property="continueWatchingStack" destination="wjN-Eq-Uv8" id="K3b-KD-IhI"/>
<outlet property="headerBtn" destination="X2b-oH-h8S" id="BsM-b2-aoJ"/>
<outlet property="headerHeight" destination="bLW-xt-Ji5" id="ifD-sE-vZI"/>
<outlet property="headerImage" destination="upA-oa-YmU" id="5nk-X3-Ik1"/>
<outlet property="headerTitleHeight" destination="vuS-va-hGV" id="DvS-Rf-KjO"/>
<outlet property="headerTitleLabel" destination="gVU-VB-fhU" id="IdJ-vA-fbU"/>
<outlet property="headerView" destination="Y14-44-gYV" id="iEI-3T-DaP"/>
<outlet property="headerViewTopConstraint" destination="1nk-Sb-8DA" id="0WC-Ao-ddY"/>

View File

@@ -31,6 +31,7 @@ class UserDetailsRegisterVC : UIViewController{
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationController?.setNavigationBarHidden(false, animated: animated)
self.navigationController?.setColor(color: .black)
}
override func viewWillDisappear(_ animated: Bool) {

View File

@@ -14,6 +14,8 @@ class GamesListVC: UIViewController {
@IBOutlet weak var gamesListingTableView: UITableView!
@IBOutlet weak var tableHeight: NSLayoutConstraint!
@IBOutlet weak var headerView: ShimmerEffectView!
@IBOutlet weak var headerTitleHeight: NSLayoutConstraint!
@IBOutlet weak var headerBtn: LocalisedElementsButton!
@IBOutlet weak var headerImage: UIImageView!
@IBOutlet weak var headerTitleLabel: UILabel!
@IBOutlet weak var gamesLoadingView: ShimmerEffectView!
@@ -55,6 +57,18 @@ class GamesListVC: UIViewController {
self.navigationController?.setColor(color: .black)
}
override func viewDidAppear(_ animated: Bool) {
/*
Check if ads is there to map impressions
*/
if let adsData = AuthFunc.shareInstance.adsData{
// check if ads data contains ad for webseries
if let gamesAd = adsData.result?.filter({$0.forPage == AdsEnum.games.rawValue}).first, let adID = gamesAd.id{
PersistentStorage.shared.addAdsCount(adID: adID ,impressions: 1)
}
}
}
override func viewDidLayoutSubviews() {
vm.updateTableHeight()
}
@@ -63,6 +77,20 @@ class GamesListVC: UIViewController {
@IBAction func gameBtnTapped(_ sender: LocalisedElementsButton) {
/*
MAke logic for ads
*/
if let adsData = AuthFunc.shareInstance.adsData{
// check if ads data contains ad for webseries
if let gamesAd = adsData.result?.filter({$0.forPage == AdsEnum.games.rawValue}).first, let adLink = gamesAd.adLink, let adID = gamesAd.id{
PersistentStorage.shared.addAdsCount(adID: adID,clicks: 1)
if let url = URL(string: adLink), UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url)
}
return
}
}
let sb = UIStoryboard(name: K.StoryBoard.Games, bundle: nil)
let vcPush = sb.instantiateViewController(withIdentifier: K.StoryBoardID.Games.gamesWebViewVC) as! GamesWebViewVC
let gameData = vm.gameData[vm.indexToLoad]
@@ -176,16 +204,16 @@ extension GamesListVC: UIScrollViewDelegate {
// Define the height range for the header view
let minHeaderHeight: CGFloat = 0.0 // Height at which the header becomes invisible
let maxHeaderHeight: CGFloat = 200.0 // Maximum height when fully visible
// let maxHeaderHeight: CGFloat = 200.0 // Maximum height when fully visible
// Calculate the new height for the header view based on the scroll position
let newHeaderHeight: CGFloat
if y < 0 {
// When scrolling up beyond the top, ensure the header view is fully expanded
newHeaderHeight = maxHeaderHeight
newHeaderHeight = vm.maxHeaderHeight
} else {
// Calculate the new height for the header view, ensuring it doesn't go below the minimum height
newHeaderHeight = max(minHeaderHeight, maxHeaderHeight - y)
newHeaderHeight = max(minHeaderHeight, vm.maxHeaderHeight - y)
}
// Update the header view's height constraint with the new height

View File

@@ -40,12 +40,16 @@ class GamesWebViewVC: UIViewController, WKNavigationDelegate,UIGestureRecognizer
override func viewDidLoad() {
super.viewDidLoad()
if let orientation, orientation == .landscape{
appDelegate.deviceOrientation = .landscapeRight
let value = UIInterfaceOrientation.landscapeRight.rawValue
UIDevice.current.setValue(value, forKey: "orientation")
// rotateToLandsScapeDevice()
DispatchQueue.main.async { [weak self] in
guard let self else{return}
if let orientation, orientation == .landscape{
appDelegate.deviceOrientation = .landscapeRight
let value = UIInterfaceOrientation.landscapeRight.rawValue
UIDevice.current.setValue(value, forKey: "orientation")
// rotateToLandsScapeDevice()
}
}
guard let url else{return}

View File

@@ -192,8 +192,10 @@
<connections>
<outlet property="gamesListingTableView" destination="pP6-WY-FP2" id="mWN-yu-zs1"/>
<outlet property="gamesLoadingView" destination="mTn-30-lIq" id="5bF-uk-ObF"/>
<outlet property="headerBtn" destination="2MA-Jr-TEh" id="lJ4-lX-e0t"/>
<outlet property="headerHeight" destination="eU7-Gn-MJi" id="nBh-iw-8tI"/>
<outlet property="headerImage" destination="Kgv-cB-NPV" id="HPo-R5-rj0"/>
<outlet property="headerTitleHeight" destination="RBd-ac-t4j" id="BYz-Id-Zdc"/>
<outlet property="headerTitleLabel" destination="7BL-Zy-PFm" id="kro-hg-bg7"/>
<outlet property="headerView" destination="mer-q0-6Vp" id="Ni3-qe-8Ud"/>
<outlet property="loadMoreActivityIndicator" destination="ulX-KY-9er" id="jGf-y1-HQw"/>

View File

@@ -14,7 +14,8 @@ class GamesListVM{
var gameData = [GamesListDM.GameDatum]()
var indexToLoad = 0
var pageNo = 0
var maxHeaderHeight = 0.0
func initView(){
setupCell()
vc.scrollView.indicatorStyle = .white // or .white
@@ -23,6 +24,11 @@ class GamesListVM{
self.vc.view.applyGradient(colors: [color1,color2], startPoint: .Point.left.point , endPoint: .Point.right.point)
startShimmer()
getGamesListing()
//Set banner height
maxHeaderHeight = UIScreen.main.bounds.width * 0.55
vc.headerHeight.constant = maxHeaderHeight
}
func setupCell(){
@@ -96,9 +102,29 @@ class GamesListVM{
self.vc.gamesListingTableView.layoutIfNeeded()
self.vc.tableHeight.constant = self.vc.gamesListingTableView.contentSize.height
if !isBtnClick{
setHeaderData()
/*
MAke logic for ads
*/
if let adsData = AuthFunc.shareInstance.adsData{
// check if ads data contains ad for webseries
if let gamesAd = adsData.result?.filter({$0.forPage == AdsEnum.games.rawValue}).first, let bannerImage = gamesAd.bannerImage, let buttonImage = gamesAd.buttonImage{
vc.headerImage.imageURL(bannerImage, color: .white)
vc.headerBtn.setTitle("", for: .normal)
vc.headerTitleLabel.text = ""
vc.headerTitleHeight.constant = 10
vc.headerBtn.backgroundColor = .clear
vc.headerBtn.sd_setBackgroundImage(with: URL(string:buttonImage), for: .normal)
}else{
if !isBtnClick{
setHeaderData()
}
}
}else{
if !isBtnClick{
setHeaderData()
}
}
self.stopShimmer()

View File

@@ -39,3 +39,45 @@ extension UIImageView {
}
}
}
extension UIButton {
func setImage(from url: String, for state: UIControl.State, color: UIColor = .black) {
// Ensure the button's background is clear
self.backgroundColor = .clear
// Ensure the button's image view background is clear
self.imageView?.backgroundColor = .clear
let activityIndicator = UIActivityIndicatorView(style: .medium)
activityIndicator.tintColor = .darkGray
activityIndicator.color = color
activityIndicator.frame = CGRect(x: 0, y: 0, width: 64, height: 64)
activityIndicator.hidesWhenStopped = true
DispatchQueue.main.async {
activityIndicator.startAnimating()
}
activityIndicator.translatesAutoresizingMaskIntoConstraints = true
activityIndicator.center = CGPoint(x: self.frame.size.width / 2, y: self.frame.size.height / 2)
// Resizing the indicator to be perfectly centered
activityIndicator.autoresizingMask = [
.flexibleRightMargin,
.flexibleLeftMargin,
.flexibleBottomMargin,
.flexibleTopMargin
]
self.addSubview(activityIndicator)
// Setting the image using SDWebImage
self.sd_setImage(with: URL(string: url.replacingOccurrences(of: " ", with: "%20")), for: state) { (image, error, cacheType, url) in
DispatchQueue.main.async {
activityIndicator.stopAnimating()
activityIndicator.removeFromSuperview()
}
}
}
}

View File

@@ -10,8 +10,10 @@ import UIKit
class KaraokeListingVC: UIViewController {
@IBOutlet weak var headerView: ShimmerEffectView!
@IBOutlet weak var headerBtn: LocalisedElementsButton!
@IBOutlet weak var selectedShowView: ShimmerEffectView!
@IBOutlet weak var headerHeight: NSLayoutConstraint!
@IBOutlet weak var headerViewLabelHeight: NSLayoutConstraint!
@IBOutlet weak var headerImage: UIImageView!
@IBOutlet weak var headerTitleLabel: UILabel!
@@ -69,6 +71,16 @@ class KaraokeListingVC: UIViewController {
K.GVar.reloadContinueKaraoke = false
self.vm.getContinueWatching()
}
/*
Check if ads is there to map impressions
*/
if let adsData = AuthFunc.shareInstance.adsData{
// check if ads data contains ad for webseries
if let karaokeAd = adsData.result?.filter({$0.forPage == AdsEnum.karaoke.rawValue}).first, let adID = karaokeAd.id{
PersistentStorage.shared.addAdsCount(adID: adID ,impressions: 1)
}
}
}
@IBAction func loadMoreBtnTapped(_ sender: LocalisedElementsButton) {
@@ -80,6 +92,22 @@ class KaraokeListingVC: UIViewController {
}
@IBAction func singBtnTapped(_ sender: LocalisedElementsButton) {
/*
MAke logic for ads
*/
if let adsData = AuthFunc.shareInstance.adsData{
// check if ads data contains ad for webseries
if let karaokeAd = adsData.result?.filter({$0.forPage == AdsEnum.karaoke.rawValue}).first, let adLink = karaokeAd.adLink, let adID = karaokeAd.id{
PersistentStorage.shared.addAdsCount(adID: adID ,clicks: 1)
if let url = URL(string: adLink), UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url)
}
return
}
}
if let id = vm.headerData?.id{
PersistentStorage.shared.addKaraokeCount(postID: id)
}
@@ -268,16 +296,15 @@ extension KaraokeListingVC: UIScrollViewDelegate {
// Define the height range for the header view
let minHeaderHeight: CGFloat = 0.0 // Height at which the header becomes invisible
let maxHeaderHeight: CGFloat = 200.0 // Maximum height when fully visible
// Calculate the new height for the header view based on the scroll position
let newHeaderHeight: CGFloat
if y < 0 {
// When scrolling up beyond the top, ensure the header view is fully expanded
newHeaderHeight = maxHeaderHeight
newHeaderHeight = vm.maxHeaderHeight
} else {
// Calculate the new height for the header view, ensuring it doesn't go below the minimum height
newHeaderHeight = max(minHeaderHeight, maxHeaderHeight - y)
newHeaderHeight = max(minHeaderHeight, vm.maxHeaderHeight - y)
}
// Update the header view's height constraint with the new height

View File

@@ -233,10 +233,12 @@
<connections>
<outlet property="continueWatchingCV" destination="Dty-MN-L9A" id="A3d-Vy-ObE"/>
<outlet property="continueWatchingStack" destination="CKh-Ui-Z3R" id="LPT-Y3-630"/>
<outlet property="headerBtn" destination="gwc-TP-cJR" id="hJG-tY-LIQ"/>
<outlet property="headerHeight" destination="bn9-gt-j6P" id="ZJh-vu-Mfq"/>
<outlet property="headerImage" destination="uTJ-KB-jeA" id="z8L-VL-5Ay"/>
<outlet property="headerTitleLabel" destination="fQH-gr-lSI" id="vjR-Yu-eZO"/>
<outlet property="headerView" destination="V10-F3-AfA" id="gZb-F6-pQ2"/>
<outlet property="headerViewLabelHeight" destination="Dm6-9O-x7v" id="chh-we-0BP"/>
<outlet property="karaokeListingTableView" destination="haV-Gw-hD2" id="1En-mN-yVg"/>
<outlet property="loadMoreActivityIndicator" destination="OhD-ec-2sW" id="yfU-R6-UbS"/>
<outlet property="loadMoreBtn" destination="ims-Sc-C3R" id="WEX-0M-lBp"/>

View File

@@ -17,6 +17,7 @@ class KaraokeListingVM{
var headerData : KaraokeListingDM.KaraokeDatum?
var pageNo = 0
var maxHeaderHeight = 0.0
func initView(){
setupCell()
@@ -28,6 +29,10 @@ class KaraokeListingVM{
startShimmer()
getContinueWatching()
getKaraokeListing()
//Set banner height
maxHeaderHeight = UIScreen.main.bounds.width * 0.55
vc.headerHeight.constant = maxHeaderHeight
}
func setupCell(){
@@ -139,9 +144,29 @@ class KaraokeListingVM{
self.vc.karaokeListingTableView.layoutIfNeeded()
self.vc.tableHeight.constant = self.vc.karaokeListingTableView.contentSize.height + 10
if !isBtnClick{
self.headerData = self.karaokeListData.first
setHeaderData()
/*
MAke logic for ads
*/
if let adsData = AuthFunc.shareInstance.adsData{
// check if ads data contains ad for webseries
if let karaokeAd = adsData.result?.filter({$0.forPage == AdsEnum.karaoke.rawValue}).first, let bannerImage = karaokeAd.bannerImage, let buttonImage = karaokeAd.buttonImage{
vc.headerImage.imageURL(bannerImage, color: .white)
vc.headerBtn.setTitle("", for: .normal)
vc.headerTitleLabel.text = ""
vc.headerViewLabelHeight.constant = 10
vc.headerBtn.backgroundColor = .clear
vc.headerBtn.sd_setBackgroundImage(with: URL(string:buttonImage), for: .normal)
}else{
if !isBtnClick{
self.headerData = self.karaokeListData.first
setHeaderData()
}
}
}else{
if !isBtnClick{
self.headerData = self.karaokeListData.first
setHeaderData()
}
}
self.stopShimmer()

View File

@@ -0,0 +1,37 @@
//
// AdsDM.swift
// WOKA
//
// Created by MacBook Pro on 04/09/24.
//
import Foundation
// MARK: - AdsDM
struct AdsDM: Codable {
let result: [ResultData]?
let totalRecords: Int?
enum CodingKeys: String, CodingKey {
case result
case totalRecords = "total_records"
}
// MARK: - Result
struct ResultData: Codable {
let id: Int?
let title, adCompany: String?
let bannerImage, buttonImage: String?
let forPage: String?
let adLink: String?
enum CodingKeys: String, CodingKey {
case id, title
case adCompany = "ad_company"
case bannerImage = "banner_image"
case buttonImage = "button_image"
case forPage = "for_page"
case adLink = "ad_link"
}
}
}

View File

@@ -9,11 +9,23 @@ import Foundation
import AVFoundation
import UIKit
import OneSignalFramework
import Alamofire
enum GetSet{
case get
case set
}
enum AdsEnum : String{
case themeOne = "theme-1"
case themeTwo = "theme-2"
case shop_super_category = "shop-super-category"
case web_series = "web-series"
case karaoke = "karaoke"
case audioBooks = "audio-books"
case games = "games"
}
class AuthFunc{
/**
@@ -23,10 +35,31 @@ class AuthFunc{
var player: AVQueuePlayer?
var playerLooper: AVPlayerLooper?
/*
This will hold user type
*/
var userType = UserType.adult
/*
This will hold the user data
*/
var userData : UserDataDM.ResultData?
/*
This holds the live url and fm url
*/
var staticURLs : URLStaticDM?
/*
This holds the ads
*/
var adsData : AdsDM?
/*
This holds the language selected by user
*/
var languageSelected = LocalizedEnum.english {
didSet {
NotificationCenter.default.post(name: .languageDidChange, object: nil)
@@ -36,6 +69,9 @@ class AuthFunc{
var authID = String()
var authPass = String()
/*
This will hold the theme selected
*/
var selectedTheme = ThemeSelect.theme1
/*
@@ -156,6 +192,7 @@ class AuthFunc{
UserDefaults.standard.setValue(nil, forKey: K.UserDefaultsStruct.userAccessToken)
UserDefaults.standard.setValue(nil, forKey: K.UserDefaultsStruct.userType)
userData = nil
CartDataCache.shareInstance.removeAll()
selectedTheme = .theme1
}
@@ -184,7 +221,31 @@ class AuthFunc{
default:
onCompletion?(false)
}
case .failure(let error):
case .failure(_):
onCompletion?(false)
}
}
}
// MARK: - Get AD's
func getAds(onCompletion: ((Bool) -> Void)? = nil){
let params : Parameters = ["start" : "0",
"limit":"0"]
NetworkManager.shareInstance.apiRequest(url: APIEndPoints.Analytics.get_ad_data, method: .get,parameters: params) { (result : Result<BaseResponseModel<AdsDM>, NetworkManager.APIError>) in
switch result{
case .success(let data):
switch data.success{
case 0:
onCompletion?(false)
case 1:
guard let data = data.data else{return}
AuthFunc.shareInstance.adsData = data
onCompletion?(true)
default:
onCompletion?(false)
}
case .failure(_):
onCompletion?(false)
}
}

View File

@@ -156,6 +156,8 @@ struct APIEndPoints {
struct Analytics{
static let user_clicks = makeURL(path: "v2/user_clicks")
static let user_video_view = makeURL(path: "user_video_view")
static let get_ad_data = makeURL(path: "get_ad_data")
static let update_ad_count = makeURL(path: "update_ad_count")
}
// Helper method to construct full URL from base URL and path

View File

@@ -192,6 +192,42 @@ class NetworkManager{
}
}
}
func nwCallRawJSONAds(adsData : [AdsClickImpressionsData], onCompletion : @escaping (Bool) -> Void){
let loginCred = getLoginIDPass()
let encoder = JSONEncoder()
encoder.keyEncodingStrategy = .convertToSnakeCase
guard let jsonData = try? encoder.encode(adsData),
let jsonArray = try? JSONSerialization.jsonObject(with: jsonData, options: .allowFragments) as? [[String: Any]] else {
print("Failed to encode totalClicks array to JSON")
return
}
let url = APIEndPoints.Analytics.update_ad_count
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.headers = ["device-id" : AuthFunc.shareInstance.getDeviceUUID(),
"access-token" : AuthFunc.shareInstance.getAccessToken()]
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
do {
// Set the HTTP body with the JSON data
request.httpBody = try JSONSerialization.data(withJSONObject: jsonArray)
} catch let error {
print("Error: \(error.localizedDescription)")
return
}
AF.request(request).authenticate(username: loginCred.0, password: loginCred.1)
.validate(statusCode: 200..<300)
.responseDecodable(of: CommonResponseModel.self) { response in
switch response.result {
case .success(let data):
onCompletion(true)
case .failure(let error):
onCompletion(false)
}
}
}
}

View File

@@ -39,10 +39,13 @@ class SplashVC: UIViewController {
switch sender{
case hindiBtn:
UserDefaults.standard.setValue(LocalizedEnum.hindi.rawValue, forKey: K.UserDefaultsStruct.defaultLanguage)
AuthFunc.shareInstance.languageSelected = .hindi
case englishBtn:
UserDefaults.standard.setValue(LocalizedEnum.english.rawValue, forKey: K.UserDefaultsStruct.defaultLanguage)
AuthFunc.shareInstance.languageSelected = .english
default:
UserDefaults.standard.setValue(LocalizedEnum.english.rawValue, forKey: K.UserDefaultsStruct.defaultLanguage)
AuthFunc.shareInstance.languageSelected = .english
}

View File

@@ -19,6 +19,10 @@ class SplashVM{
if AuthFunc.shareInstance.staticURLs == nil{
AuthFunc.shareInstance.getStaticURLs()
}
if AuthFunc.shareInstance.adsData == nil{
AuthFunc.shareInstance.getAds()
}
vc.activityIndicator.hidesWhenStopped = true
let color1 = #colorLiteral(red: 0.144693464, green: 0.1426281333, blue: 0.6686832905, alpha: 1)
let color2 = #colorLiteral(red: 0.4862745098, green: 0.1960784314, blue: 0.7019607843, alpha: 1)
@@ -34,7 +38,6 @@ class SplashVM{
}else{
AuthFunc.shareInstance.setDefaultLanguage(language: .english)
}
}
// Play initial sound
@@ -67,6 +70,9 @@ class SplashVM{
if AuthFunc.shareInstance.getUserType() == 3{
//setusertype
AuthFunc.shareInstance.userData = UserDataDM.ResultData(id: nil, genderData: nil, birthdate: nil, email: nil, avtar: nil, avtarURL: nil, userType: "3", languageMasterID: nil, lastLogin: nil, rememberToken: nil, childDetail: nil, language: nil, alreadyLoggedIn: nil, isDeactive: nil)
if AuthFunc.shareInstance.adsData == nil{
AuthFunc.shareInstance.getAds()
}
if AuthFunc.shareInstance.staticURLs == nil{
AuthFunc.shareInstance.getStaticURLs { isDone in
if isDone == true{
@@ -108,6 +114,10 @@ class SplashVM{
if AuthFunc.shareInstance.staticURLs == nil{
AuthFunc.shareInstance.getStaticURLs()
}
if AuthFunc.shareInstance.adsData == nil{
AuthFunc.shareInstance.getAds()
}
DispatchQueue.main.async {
UIApplication.setRootView(SideMenuController.instantiate(from: .Home))
}

View File

@@ -47,6 +47,31 @@ struct UserClickData {
let postType: Int
}
// MARK: - Clicks
struct ClicksAnalytics : Codable {
let postID, postType, numberOfClicks, deviceType: Int?
let categoryID: Int?
enum CodingKeys: String, CodingKey {
case postID = "post_id"
case postType = "post_type"
case numberOfClicks = "number_of_clicks"
case deviceType = "device_type"
case categoryID = "category_id"
}
}
// MARK: - ADs Impressions & Clicks
struct AdsClickImpressionsData : Codable {
let adID, noOfClick, noOfOmpression: Int
enum CodingKeys: String, CodingKey {
case adID = "ad_id"
case noOfClick = "no_of_click"
case noOfOmpression = "no_of_impression"
}
}
//struct UserVideoViewData {
// let postId: Int
// let postType: Int
@@ -246,7 +271,7 @@ final class PersistentStorage
debugPrint(error)
}
}
func deleteData(_ data: [UserClicks]) {
let managedContext = PersistentStorage.shared.context
@@ -263,6 +288,8 @@ final class PersistentStorage
}
}
// MARK: - Handle Clicks For UserClicks
func addOthersCount(){
@@ -311,51 +338,120 @@ final class PersistentStorage
let userClicks = UserClickData(clickCounts: 1, categoryId: catID, postId: postID, postType: postType.rawValue)
PersistentStorage.shared.checkWebSeries(clicksData: userClicks)
}
// MARK: - Handling ADS
func sendAdsData() {
//create a context from this container
let managedContext = PersistentStorage.shared.context
let fetchRequest:NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "AdClicksImpressions")
fetchRequest.fetchLimit = 15
do {
guard let result = try managedContext.fetch(fetchRequest) as? [AdClicksImpressions] else {return}
var userImpressions = [AdsClickImpressionsData]()
result.forEach { ads in
// device type 1- android , 2 - iOS
userImpressions.append(AdsClickImpressionsData(adID: Int(ads.ad_id), noOfClick: Int(ads.no_of_click), noOfOmpression: Int(ads.no_of_impression)))
print("ID:-" , ads.ad_id, "No Of Clicks :- ", ads.no_of_click, "Impressions :- ", ads.no_of_impression)
}
NetworkManager.shareInstance.nwCallRawJSONAds(adsData: userImpressions) { isDone in
if isDone{
self.deleteAdsData(result)
}
}
}
catch let error
{
debugPrint(error)
}
}
// MARK: - Handling UserViewView CRUD
func checkIfAdExist(adsData : AdsClickImpressionsData) {
let managedContext = PersistentStorage.shared.context
let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: "AdClicksImpressions")
fetchRequest.predicate = NSPredicate(format: "ad_id == %@" ,adsData.adID.toString())
do {
guard let result = try managedContext.fetch(fetchRequest) as? [AdClicksImpressions] else {return}
if result.isEmpty{
//create
PersistentStorage.shared.createAdsData(data: adsData)
print("create, In Exist")
}else{
//update
let objectUpdate = result[0] as NSManagedObject
print("Update, In Exist")
objectUpdate.setValue(result.first!.no_of_click + Int64(adsData.noOfClick), forKey: "no_of_click")
objectUpdate.setValue(result.first!.no_of_impression + Int64(adsData.noOfOmpression), forKey: "no_of_impression")
do{
try managedContext.save()
retrieveAdsData(adID: adsData.adID)
}
catch
{
print(error)
}
}
}catch let error as NSError {
print("Could not fetch. \(error), \(error.userInfo)")
}
}
func createAdsData(data : AdsClickImpressionsData){
//We need to create a context from this container
let managedContext = PersistentStorage.shared.context
let share = AdClicksImpressions(context: managedContext)
share.ad_id = Int64(data.adID)
share.no_of_click = Int64(data.noOfClick)
share.no_of_impression = Int64(data.noOfOmpression)
do {
try managedContext.save()
retrieveAdsData(adID: data.adID)
} catch let error as NSError {
print("Could not save. \(error), \(error.userInfo)")
}
}
func retrieveAdsData(adID : Int?) {
let managedContext = PersistentStorage.shared.context
let fetchRequest:NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "AdClicksImpressions")
fetchRequest.predicate = NSPredicate(format: "ad_id == %@",adID?.toString() ?? 0)
do {
guard let result = try managedContext.fetch(fetchRequest) as? [AdClicksImpressions] else {return}
result.forEach { ads in
print("ID:-" , ads.ad_id, "No Of Clicks :- ", ads.no_of_click, "Impressions :- ", ads.no_of_impression)
}
}
catch let error
{
debugPrint(error)
}
}
func addAdsCount(adID : Int, impressions : Int = 0, clicks : Int = 0){
let adsData = AdsClickImpressionsData(adID: adID, noOfClick: clicks, noOfOmpression: impressions)
PersistentStorage.shared.checkIfAdExist( adsData: adsData)
}
func deleteAdsData(_ data: [AdClicksImpressions]) {
let managedContext = PersistentStorage.shared.context
// 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
data.forEach { clicks in
managedContext.delete(clicks)
}
do {
try managedContext.save()
getAllData()
print("Deleted data")
} catch let error {
debugPrint("Failed to delete data:", error)
}
}
}

View File

@@ -50,6 +50,18 @@ class ShopListingVC: UIViewController {
self.navigationController?.setColor(color: .black)
}
override func viewDidAppear(_ animated: Bool) {
/*
Check if ads is there to map impressions
*/
if let adsData = AuthFunc.shareInstance.adsData{
// check if ads data contains ad for webseries
if let shopSuperCatAd = adsData.result?.filter({$0.forPage == AdsEnum.shop_super_category.rawValue}).first, let adID = shopSuperCatAd.id{
PersistentStorage.shared.addAdsCount(adID: adID ,impressions: 1)
}
}
}
@IBAction func retryBtnTapped(_ sender: LocalisedElementsButton) {
noDataStack.isHidden = true
tableView.isHidden = false
@@ -78,20 +90,48 @@ extension ShopListingVC : TableViewSRC{
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if vm.superCatData.count == 0 {return}
let superCatID = vm.superCatData[indexPath.row].id
if let superCatID{
PersistentStorage.shared.addShopCount(postID: superCatID)
/*
MAke logic for ads
*/
if vm.superCatData[indexPath.row].isAD == true{
if let adsData = AuthFunc.shareInstance.adsData{
// check if ads data contains ad for webseries
if let shopSuperCatAd = adsData.result?.filter({$0.forPage == AdsEnum.shop_super_category.rawValue}).first,let adLink = shopSuperCatAd.adLink, let adID = shopSuperCatAd.id{
PersistentStorage.shared.addAdsCount(adID: adID,clicks: 1)
if let url = URL(string: adLink), UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url)
}
return
}
}
}
if vm.superCatData.count == 0 {return}
if let adsData = AuthFunc.shareInstance.adsData, (adsData.result?.filter({$0.forPage == AdsEnum.shop_super_category.rawValue}).first) != nil{
// check if ads data contains ad for webseries
let superCatID = vm.superCatData[indexPath.row - 1].id
if let superCatID{
PersistentStorage.shared.addShopCount(postID: superCatID)
}
let sb = UIStoryboard(name: K.StoryBoard.shop, bundle: nil)
let vcPush = sb.instantiateViewController(withIdentifier: K.StoryBoardID.Shop.shopCategoryVC) as! ShopCategoryVC
vcPush.vm.superCatID = superCatID
self.navigationController?.pushViewController(vcPush, animated: true)
return
}else{
let superCatID = vm.superCatData[indexPath.row].id
if let superCatID{
PersistentStorage.shared.addShopCount(postID: superCatID)
}
let sb = UIStoryboard(name: K.StoryBoard.shop, bundle: nil)
let vcPush = sb.instantiateViewController(withIdentifier: K.StoryBoardID.Shop.shopCategoryVC) as! ShopCategoryVC
vcPush.vm.superCatID = superCatID
self.navigationController?.pushViewController(vcPush, animated: true)
}
let sb = UIStoryboard(name: K.StoryBoard.shop, bundle: nil)
let vcPush = sb.instantiateViewController(withIdentifier: K.StoryBoardID.Shop.shopCategoryVC) as! ShopCategoryVC
vcPush.vm.superCatID = superCatID
self.navigationController?.pushViewController(vcPush, animated: true)
}
}
//extension UIViewController {
//
// func createCartButton(imageName: String,

View File

@@ -22,11 +22,12 @@ struct ShopSuperCategoryDM: Codable {
let id: Int?
let superCategoryName: String?
let superCategoryThumbnail: String?
var isAD : Bool? = false
enum CodingKeys: String, CodingKey {
case id
case superCategoryName = "super_category_name"
case superCategoryThumbnail = "super_category_thumbnail"
case isAD
}
}

View File

@@ -84,7 +84,17 @@ class ShopListingVM{
vc.noDataStack.isHidden = true
vc.tableView.isHidden = false
self.superCatData = data
/*
MAke logic for ads
*/
if let adsData = AuthFunc.shareInstance.adsData{
// check if ads data contains ad for webseries
if let shopSuperCatAd = adsData.result?.filter({$0.forPage == AdsEnum.shop_super_category.rawValue}).first, let bannerImage = shopSuperCatAd.bannerImage{
self.superCatData.append(ShopSuperCategoryDM.ResultData(id: shopSuperCatAd.id, superCategoryName: shopSuperCatAd.title, superCategoryThumbnail: bannerImage,isAD: true))
}
}
self.superCatData.append(contentsOf: data)
self.vc.tableView.reloadData()
default:
vc.noDataStack.isHidden = false

View File

@@ -415,7 +415,7 @@
<constraint firstItem="GGC-rX-Pyw" firstAttribute="centerY" secondItem="feU-AA-gLO" secondAttribute="centerY" constant="30" id="vSh-CJ-Awg"/>
</constraints>
</view>
<imageView hidden="YES" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="HomeTestBanner" translatesAutoresizingMaskIntoConstraints="NO" id="0qL-H2-cMA">
<imageView hidden="YES" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="0qL-H2-cMA">
<rect key="frame" x="304" y="742" width="100" height="100"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
@@ -1388,7 +1388,6 @@
<image name="Games" width="164" height="130.5"/>
<image name="HomeGrassDay" width="570.66668701171875" height="641.33331298828125"/>
<image name="HomeIcon" width="26.5" height="26.5"/>
<image name="HomeTestBanner" width="85.333335876464844" height="85.333335876464844"/>
<image name="Karaoke" width="172" height="137"/>
<image name="LiveHindi" width="326.66665649414062" height="176.66667175292969"/>
<image name="LiveTV" width="172" height="122.5"/>

View File

@@ -73,12 +73,17 @@ class PlayerVC: JWPlayerViewController, JWPlayerViewControllerDelegate {
if #available(iOS 16.0, *) {
// Code for iOS 15.0 and above
print("Running on iOS 15.0 or later")
appDelegate.deviceOrientation = .landscapeRight
let value = UIInterfaceOrientation.landscapeRight.rawValue
UIDevice.current.setValue(value, forKey: "orientation")
DispatchQueue.main.async {
appDelegate.deviceOrientation = .landscapeRight
let value = UIInterfaceOrientation.landscapeRight.rawValue
UIDevice.current.setValue(value, forKey: "orientation")
}
} else {
// Fallback code for earlier iOS versions
rotateView(to: .pi / 2) // Example: 90 degrees rotation
DispatchQueue.main.async { [weak self] in
guard let self else{return}
rotateView(to: .pi / 2) // Example: 90 degrees rotation
}
print("Running on a version earlier than iOS 15.0")
}
@@ -409,13 +414,17 @@ extension PlayerVC {
if #available(iOS 16.0, *) {
// Code for iOS 16.0 and above
appDelegate.deviceOrientation = .portrait
let value = UIInterfaceOrientation.portrait.rawValue
UIDevice.current.setValue(value, forKey: "orientation")
UIViewController.attemptRotationToDeviceOrientation()
DispatchQueue.main.async {
appDelegate.deviceOrientation = .portrait
let value = UIInterfaceOrientation.portrait.rawValue
UIDevice.current.setValue(value, forKey: "orientation")
UIViewController.attemptRotationToDeviceOrientation()
}
} else {
// Fallback code for earlier iOS versions
self.dismiss(animated: true)
DispatchQueue.main.async {
self.dismiss(animated: true)
}
}
}

View File

@@ -55,6 +55,8 @@ class ThemeOneVC: UIViewController {
NotificationCenter.default.removeObserver(self, name: UIApplication.willEnterForegroundNotification, object: nil)
NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: K.NotificationCenterReloads.reloadTheme), object: nil)
NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: K.NotificationCenterReloads.themeOnePush), object: nil)
NotificationCenter.default.removeObserver(self, name: .languageDidChange, object: nil)
// NotificationCenter.default.removeObserver(self, name: NSNotification.Name.connectivityStatus, object: nil)
if let playerItem = vm.playerItem{
playerItem.removeObserver(self, forKeyPath: "status")
@@ -80,6 +82,7 @@ class ThemeOneVC: UIViewController {
MyListDataTemp.shareInstance.favListingData = FavouriteListingDM.ResultData(totalRecords: nil, showData: FavouriteListingDM.ResultData.ShowData(hindi: [],english: []),videoData: [],gameData: [],singKaraokeData: [],audioData: [])
}
vm.setupAvPlayer()
}
override func viewWillAppear(_ animated: Bool) {
@@ -106,6 +109,16 @@ class ThemeOneVC: UIViewController {
if let player = vm.avPlayer{
player.play()
}
/*
Check if ads is there to map impressions
*/
if let adsData = AuthFunc.shareInstance.adsData{
// check if ads data contains ad for webseries
if let themeOneAd = adsData.result?.filter({$0.forPage == AdsEnum.themeOne.rawValue}).first, let adID = themeOneAd.id{
PersistentStorage.shared.addAdsCount(adID: adID ,impressions: 1)
}
}
}
override func viewDidLayoutSubviews() {
@@ -139,6 +152,8 @@ class ThemeOneVC: UIViewController {
self.navigationController?.pushViewController(vcPush, animated: true)
PersistentStorage.shared.sendDataToServer()
PersistentStorage.shared.sendAdsData()
}
@IBAction func radioBtnTapped(_ sender: UIButton) {

View File

@@ -119,17 +119,18 @@ class PlayerVM{
}
updateClicks()
if #available(iOS 16.0, *) {
// Code for iOS 15.0 and above
appDelegate.deviceOrientation = .portrait
let value = UIInterfaceOrientation.portrait.rawValue
UIDevice.current.setValue(value, forKey: "orientation")
UIViewController.attemptRotationToDeviceOrientation()
} else {
// Fallback code for earlier iOS versions
self.vc.dismiss(animated: true)
DispatchQueue.main.async {
if #available(iOS 16.0, *) {
// Code for iOS 15.0 and above
appDelegate.deviceOrientation = .portrait
let value = UIInterfaceOrientation.portrait.rawValue
UIDevice.current.setValue(value, forKey: "orientation")
UIViewController.attemptRotationToDeviceOrientation()
} else {
// Fallback code for earlier iOS versions
self.vc.dismiss(animated: true)
}
}
}
func updateClicks(){
@@ -167,11 +168,13 @@ class PlayerVM{
} 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()
DispatchQueue.main.async {
appDelegate.deviceOrientation = .portrait
let value = UIInterfaceOrientation.portrait.rawValue
UIDevice.current.setValue(value, forKey: "orientation")
UIViewController.attemptRotationToDeviceOrientation()
}
}
}
}

View File

@@ -48,9 +48,16 @@ class ThemeOneVM{
UIView.animate(withDuration: 0.7, delay: 0, options: [], animations: {
self.vc.allIconView.transform = CGAffineTransform.identity // Reset the transform to original size
}, completion: {_ in
self.vc.adBanner.isHidden = false
})
}
if let adsData = AuthFunc.shareInstance.adsData{
// check if ads data contains ad for webseries
if let themeOneAd = adsData.result?.filter({$0.forPage == AdsEnum.themeOne.rawValue}).first, let bannerImage = themeOneAd.bannerImage{
vc.adBanner.imageURL(bannerImage, color: .textDarkBlue)
vc.adBanner.isHidden = false
}
}
}
private func handleNotificationCenter(){
@@ -60,9 +67,14 @@ class ThemeOneVM{
NotificationCenter.default.addObserver(self, selector: #selector(self.reloadTheme), name: NSNotification.Name(rawValue: K.NotificationCenterReloads.reloadTheme), object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(handleRouteChange(_:)), name: AVAudioSession.routeChangeNotification, object: nil)
// NotificationCenter.default.addObserver(self, selector: #selector(showOfflineDeviceUI(notification:)), name: NSNotification.Name.connectivityStatus, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(languageDidChange), name: .languageDidChange, object: nil)
// NotificationCenter.default.addObserver(self, selector: #selector(showOfflineDeviceUI(notification:)), name: NSNotification.Name.connectivityStatus, object: nil)
}
@objc private func languageDidChange() {
print("Language Change")
}
// @objc func showOfflineDeviceUI(notification: Notification) {
// if NetworkMonitor.shared.isConnected {
// NetworkMonitor.shared.stopMonitoring()
@@ -275,11 +287,18 @@ class ThemeOneVM{
*/
vc.adBanner.addTapGesture {
ViewButtonAnimation.sharedInstance.btnTapped(in: self.vc, view: self.vc.adBanner) { [weak self] in
guard let self else{return}
ViewButtonAnimation.sharedInstance.btnTapped(in: self.vc, view: self.vc.adBanner) {
//check url from api
if let url = URL(string: "https://miniklub.in/?utm_source=Kids+video+channel&utm_medium=banner&utm_campaign=Trial&utm_id=Woka"), UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url)
if let adsData = AuthFunc.shareInstance.adsData{
// check if ads data contains ad for webseries
if let themeOneAd = adsData.result?.filter({$0.forPage == AdsEnum.themeOne.rawValue}).first, let adLink = themeOneAd.adLink, let adID = themeOneAd.id{
PersistentStorage.shared.addAdsCount(adID: adID,clicks: 1)
if let url = URL(string: adLink), UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url)
}
}
}
}
}
@@ -651,16 +670,4 @@ class ThemeOneVM{
// }
//}
// MARK: - StaticURLs
struct ClicksAnalytics : Codable {
let postID, postType, numberOfClicks, deviceType: Int?
let categoryID: Int?
enum CodingKeys: String, CodingKey {
case postID = "post_id"
case postType = "post_type"
case numberOfClicks = "number_of_clicks"
case deviceType = "device_type"
case categoryID = "category_id"
}
}

View File

@@ -1,5 +1,10 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="22758" systemVersion="23F79" minimumToolsVersion="Automatic" sourceLanguage="Swift" usedWithSwiftData="YES" userDefinedModelVersionIdentifier="">
<entity name="AdClicksImpressions" representedClassName="AdClicksImpressions" syncable="YES">
<attribute name="ad_id" optional="YES" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="no_of_click" optional="YES" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="no_of_impression" optional="YES" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
</entity>
<entity name="UserClicks" representedClassName="UserClicks" syncable="YES">
<attribute name="category_id" optional="YES" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="click_counts" optional="YES" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>

View File

@@ -90,6 +90,16 @@ class WebSeriesVC: UIViewController {
}else{
K.GVar.reloadContinueWebSeries = false
}
/*
Check if ads is there to map impressions
*/
if let adsData = AuthFunc.shareInstance.adsData{
// check if ads data contains ad for webseries
if let webSeriesAd = adsData.result?.filter({$0.forPage == AdsEnum.web_series.rawValue}).first, let adID = webSeriesAd.id{
PersistentStorage.shared.addAdsCount(adID: adID ,impressions: 1)
}
}
}
override func viewDidLayoutSubviews() {
@@ -99,6 +109,19 @@ class WebSeriesVC: UIViewController {
// MARK: - Tap Handler
@IBAction func playTrailer(_ sender: LocalisedElementsButton) {
//If its ads then nav user to webview
if let adsData = AuthFunc.shareInstance.adsData{
// check if ads data contains ad for webseries
if let webSeriesAd = adsData.result?.filter({$0.forPage == AdsEnum.web_series.rawValue}).first, let adLink = webSeriesAd.adLink,let adID = webSeriesAd.id{
PersistentStorage.shared.addAdsCount(adID: adID ,clicks: 1)
if let url = URL(string: adLink), UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url)
}
return
}
}
let item = JwPlayerItemCreate(url: APIEndPoints.StaticURLs.masilaUrl, poster: nil, titles: "Masila")
JWPlayerManager.shared.presentPlayer(from: self, playerItems: [item], contentType: .trailer, videoIDs: [0])
PersistentStorage.shared.addTrailerCount()
@@ -405,7 +428,6 @@ extension WebSeriesVC: UIScrollViewDelegate {
// Define the height range for the header view
let minHeaderHeight: CGFloat = 0.0 // Height at which the header becomes invisible
// let maxHeaderHeight: CGFloat = self.headerView.frame.height // Maximum height when fully visible
// Calculate the new height for the header view based on the scroll position
let newHeaderHeight: CGFloat
@@ -424,16 +446,6 @@ extension WebSeriesVC: UIScrollViewDelegate {
UIView.animate(withDuration: 0.3) {
self.view.layoutIfNeeded()
}
// if headerHeight.constant == maxHeaderHeight {
// UIView.transition(with: headerViewImage, duration: 0.3, options: .transitionCrossDissolve, animations: {
// self.headerViewImage.contentMode = .scaleToFill
// }, completion: nil)
// } else {
// UIView.transition(with: headerViewImage, duration: 0.3, options: .transitionCrossDissolve, animations: {
// self.headerViewImage.contentMode = .scaleAspectFill
// }, completion: nil)
// }
}
}

View File

@@ -31,15 +31,16 @@ class WebSeriesVM{
func initView(){
// let heightMultiplier: CGFloat = 0.257511
let heightMultiplier: CGFloat = 0.29
// let heightMultiplier: CGFloat = 0.29
// Get the current screen height
let currentScreenHeight = UIScreen.main.bounds.height
// let currentScreenHeight = UIScreen.main.bounds.height
// Calculate the new view height based on the multiplier
// maxHeaderHeight = currentScreenHeight * heightMultiplier
maxHeaderHeight = UIScreen.main.bounds.width * 0.55
//Set banner height
maxHeaderHeight = UIScreen.main.bounds.width * 0.55
vc.headerHeight.constant = maxHeaderHeight
setupCell()
@@ -67,14 +68,16 @@ class WebSeriesVM{
/*
MAke logic for ads
*/
if 1 == 1{
vc.headerViewImage.image = UIImage(named: "KaraokeTestBanner")
vc.headerBtn.setTitle("", for: .normal)
vc.headerViewLabel.text = ""
vc.headerViewLabelHeight.constant = 10
vc.headerBtn.backgroundColor = .clear
vc.headerBtn.setImage(UIImage(named: "ButtonTestBanner"), for: .normal)
// vc.headerViewLabel.isHidden = true
if let adsData = AuthFunc.shareInstance.adsData{
// check if ads data contains ad for webseries
if let webSeriesAd = adsData.result?.filter({$0.forPage == AdsEnum.web_series.rawValue}).first, let bannerImage = webSeriesAd.bannerImage, let buttonImage = webSeriesAd.buttonImage{
vc.headerViewImage.imageURL(bannerImage, color: .white)
vc.headerBtn.setTitle("", for: .normal)
vc.headerViewLabel.text = ""
vc.headerViewLabelHeight.constant = 10
vc.headerBtn.backgroundColor = .clear
vc.headerBtn.sd_setBackgroundImage(with: URL(string:buttonImage), for: .normal)
}
}
}

View File

@@ -32,7 +32,7 @@
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="bTO-Ql-tyN" customClass="ShimmerEffectView" customModule="WOKA" customModuleProvider="target">
<rect key="frame" x="0.0" y="59" width="430" height="240"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="KaraokeTestBanner" translatesAutoresizingMaskIntoConstraints="NO" id="wnB-dE-0v3">
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="MasilaComingSoon" translatesAutoresizingMaskIntoConstraints="NO" id="wnB-dE-0v3">
<rect key="frame" x="0.0" y="0.0" width="430" height="240"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</imageView>
@@ -476,7 +476,7 @@
<rect key="frame" x="377.66666666666669" y="0.0" width="32.333333333333314" height="49"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="hand.thumbsup.fill" catalog="system" translatesAutoresizingMaskIntoConstraints="NO" id="eng-oC-d9H">
<rect key="frame" x="0.0" y="0.50000000000000178" width="20" height="47.999999999999986"/>
<rect key="frame" x="0.0" y="0.66666666666666785" width="20" height="47.666666666666671"/>
<color key="tintColor" red="0.035294117649999998" green="0.0" blue="0.36470588240000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="0" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Egv-Cu-aPK">
@@ -530,7 +530,7 @@
<rect key="frame" x="0.0" y="0.0" width="40" height="50"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" image="heart" catalog="system" translatesAutoresizingMaskIntoConstraints="NO" id="QkS-fP-ADo">
<rect key="frame" x="5" y="1.5000000000000018" width="30" height="33.5"/>
<rect key="frame" x="5" y="2" width="30" height="33"/>
<color key="tintColor" name="ImageDarkBlue"/>
<constraints>
<constraint firstAttribute="width" constant="30" id="MvO-j1-tEk"/>
@@ -614,7 +614,7 @@
<rect key="frame" x="0.0" y="0.0" width="40" height="50"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" image="hand.thumbsup" catalog="system" translatesAutoresizingMaskIntoConstraints="NO" id="f9M-ON-9gL">
<rect key="frame" x="7.6666666666666856" y="-0.5" width="25" height="36.5"/>
<rect key="frame" x="7.6666666666666856" y="-0.33333333333333215" width="25" height="36"/>
<color key="tintColor" name="ImageDarkBlue"/>
<constraints>
<constraint firstAttribute="width" constant="25" id="UAK-v9-EKA"/>
@@ -1244,7 +1244,7 @@
</scenes>
<resources>
<image name="CloseIconEmpty" width="30" height="30"/>
<image name="KaraokeTestBanner" width="266.66665649414062" height="146.66667175292969"/>
<image name="MasilaComingSoon" width="200" height="100"/>
<image name="PlayButtonSmall" width="28.333333969116211" height="28.333333969116211"/>
<image name="ShareImage" width="18" height="18"/>
<image name="SupportBottomArrow" width="16.333333969116211" height="16.333333969116211"/>