Files
Woka_Native_iOS/WOKA/DataSync&AdsManage/PersistentStorage.swift
BilalKhanWDI 129be7142a - Fixed a bug for logout, clearing cache for my list
- Made last data sync, will check in 1 hour if the last sync done time is past 1 hour, will give a sync in background
- 3-3:30 meeting with WOKA for ads
- Finalised the data sync when app goes in background.
- Muted google ads from splash.
- Completed Data sync from logout , it will now show first its syncing the data and then it will logout.
2024-09-24 20:10:45 +05:30

569 lines
22 KiB
Swift

//
// PersistentStorage.swift
// WOKA
//
// Created by MacBook Pro on 05/08/24.
//
import Foundation
import CoreData
enum PersistentStorageEnum : String{
case UserClicks
case click_counts
case category_id
case post_id
case post_type
}
enum PostType: Int {
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
let postId: Int
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"
}
}
final class PersistentStorage
{
private init(){}
static let shared = PersistentStorage()
// MARK: - Core Data stack
lazy var persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "WOKA")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved errorsss \(error), \(error.userInfo)")
}
})
return container
}()
lazy var context = persistentContainer.viewContext
// MARK: - Core Data Saving support
func saveContext() {
if context.hasChanges {
do {
try context.save()
} catch {
let nserror = error as NSError
fatalError("Unresolved errorsss \(nserror), \(nserror.userInfo)")
}
}
}
func createData(data : UserClickData){
//We need to create a context from this container
let managedContext = PersistentStorage.shared.context
let share = UserClicks(context: managedContext)
share.click_counts = Int64(data.clickCounts)
share.category_id = Int64(data.categoryId)
share.post_id = Int64(data.postId)
share.post_type = Int64(data.postType)
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 checkIfExist( key : PersistentStorageEnum , clicksData : UserClickData) {
let managedContext = PersistentStorage.shared.context
let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: PersistentStorageEnum.UserClicks.rawValue)
// fetchRequest.fetchLimit = 1
// fetchRequest.predicate = NSPredicate(format: "id == %d" ,id)
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, In Exist")
}else{
//update
let objectUpdate = result[0] as NSManagedObject
print("Update, In Exist")
objectUpdate.setValue(result.first!.click_counts + Int64(clicksData.clickCounts), forKey: "click_counts")
do{
try managedContext.save()
retrieveData(postID: clicksData.postId, catID: clicksData.categoryId, postType: clicksData.postType)
}
catch
{
print(error)
}
}
// result.forEach { clicks in
// print("Counts" , clicks.click_counts)
// }
}catch let error as NSError {
print("Could not fetch. \(error), \(error.userInfo)")
}
}
func checkWebSeries(clicksData : UserClickData) {
let managedContext = PersistentStorage.shared.context
let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: PersistentStorageEnum.UserClicks.rawValue)
fetchRequest.fetchLimit = 1
fetchRequest.predicate = NSPredicate(format: "post_id == %@ AND category_id == %@" ,clicksData.postId.toString(), clicksData.categoryId.toString())
do {
guard let result = try managedContext.fetch(fetchRequest) as? [UserClicks] else {return}
if result.isEmpty{
//create
PersistentStorage.shared.createData(data: clicksData)
print("create Main")
}else{
//update
let objectUpdate = result[0] as NSManagedObject
print("Update Main")
objectUpdate.setValue(result.first!.click_counts + Int64(clicksData.clickCounts), forKey: "click_counts")
do{
try managedContext.save()
retrieveData(postID: clicksData.postId, catID: clicksData.categoryId, postType: clicksData.postType)
}
catch
{
print(error)
}
}
}catch let error as NSError {
print("Could not fetch. \(error), \(error.userInfo)")
}
}
func retrieveData(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: "UserClicks")
fetchRequest.predicate = NSPredicate(format: "post_id == %@ AND category_id == %@ AND post_type == %@" ,postID?.toString() ?? "0", catID?.toString() ?? "0" ,postType.toString())
// fetchRequests.fetchLimit = 1
// fetchRequests.sortDescriptors = [NSSortDescriptor.init(key: "uuid", ascending: false)]
do {
guard let result = try managedContext.fetch(fetchRequest) as? [UserClicks] else {return}
result.forEach { clicks in
print("ID:-" , PostType(rawValue: Int(clicks.post_type))!, "CatID:- ", clicks.category_id, "PostID:- ", clicks.post_id , "Count:-", clicks.click_counts)
}
}
catch let error
{
debugPrint(error)
}
}
//Sending Clicks data to our server
func sendDataToServer(isLogout : Bool = false) {
//We need to create a context from this container
let managedContext = PersistentStorage.shared.context
let fetchRequest:NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "UserClicks")
fetchRequest.fetchLimit = 15
do {
guard let result = try managedContext.fetch(fetchRequest) as? [UserClicks] else {return}
var userClicks = [ClicksAnalytics]()
print("UserClicks Count from SendData to server :- ", result.count)
//if data is less , dont keep sending the data to server
if isLogout == false,result.count < 3 {
print("Not Enough Clicks Data")
return
}
result.forEach { clicks in
// device type 1- android , 2 - iOS
userClicks.append(ClicksAnalytics(postID: Int(clicks.post_id), postType: Int(clicks.post_type), numberOfClicks: Int(clicks.click_counts), deviceType: 2, categoryID: Int(clicks.category_id)))
print("ID:-" , PostType(rawValue: Int(clicks.post_type))!, "CatID:- ", clicks.category_id, "PostID:- ", clicks.post_id , "Count:-", clicks.click_counts)
}
// send data to server
NetworkManager.shareInstance.nwCallRawJSON(clicksData: userClicks) { isDone in
if isDone{ // if data is send to server and we get success callback then delete that data from coredata entity.
self.deleteData(result,isLogout: isLogout)
}
}
}
catch let error
{
debugPrint(error)
}
}
//Delete data from CoreData
func deleteData(_ data: [UserClicks],isLogout : Bool = false) {
let managedContext = PersistentStorage.shared.context
data.forEach { clicks in
managedContext.delete(clicks)
}
do {
try managedContext.save()
//after deleting check if more data exist.
getAllData(isLogout: isLogout)
print("Deleted data")
} catch let error {
debugPrint("Failed to delete data:", error)
}
}
//Get all data from DB
func getAllData(isLogout : Bool = false) {
//We need to create a context from this container
let managedContext = PersistentStorage.shared.context
let fetchRequest:NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "UserClicks")
fetchRequest.fetchLimit = 15
do {
guard let result = try managedContext.fetch(fetchRequest) as? [UserClicks] else {return}
print("UserClicks Count from getAllData :- ", result.count)
//if data is less , dont keep sending the data to server
if isLogout == false,result.count < 5 {
print("Not Enough Data")
return
} else{
// send data again to server
sendDataToServer()
print("Data sent Again.")
}
result.forEach { clicks in
// device type 1- android , 2 - iOS
print("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 UserClicks
func addOthersCount(){
let userClicks = UserClickData(clickCounts: 1, categoryId: 0, postId: 0, postType: PostType.others.rawValue)
PersistentStorage.shared.checkIfExist( key: .post_type,clicksData: userClicks)
}
func addKaraokeCount(postID : Int){
let userClicks = UserClickData(clickCounts: 1, categoryId: 0, postId: postID, postType: PostType.karaokeVideo.rawValue)
PersistentStorage.shared.checkIfExist( key: .post_type,clicksData: userClicks)
}
func addAudioCount(postID : Int){
let userClicks = UserClickData(clickCounts: 1, categoryId: 0, postId: postID, postType: PostType.audio.rawValue)
PersistentStorage.shared.checkIfExist( key: .post_type,clicksData: userClicks)
}
func addGamesCount(postID : Int, count : Int = 1){
let userClicks = UserClickData(clickCounts: count, categoryId: 0, postId: postID, postType: PostType.game.rawValue)
PersistentStorage.shared.checkIfExist( key: .post_type,clicksData: userClicks)
}
func addShopCount(postID : Int){
let userClicks = UserClickData(clickCounts: 1, categoryId: 0, postId: postID, postType: PostType.shopProduct.rawValue)
PersistentStorage.shared.checkIfExist( key: .post_type,clicksData: userClicks)
}
func addRadioCount(){
guard let postID = AuthFunc.shareInstance.staticURLs?.liveFmData?.id else{return}
let userClicks = UserClickData(clickCounts: 1, categoryId: 0, postId: postID, postType: PostType.FM.rawValue)
PersistentStorage.shared.checkIfExist( key: .post_type,clicksData: userClicks)
}
func addLiveTVCount(){
guard let postID = AuthFunc.shareInstance.staticURLs?.liveData?.first?.id else{return}
let userClicks = UserClickData(clickCounts: 1, categoryId: 0, postId: postID, postType: PostType.liveTV.rawValue)
PersistentStorage.shared.checkIfExist( key: .post_type,clicksData: userClicks)
}
func addTrailerCount(){
let userClicks = UserClickData(clickCounts: 1, categoryId: 0, postId: 0, postType: PostType.teaser.rawValue)
PersistentStorage.shared.checkIfExist( key: .post_type,clicksData: userClicks)
}
func addWebSeries(catID : Int, postID : Int, postType : PostType){
let userClicks = UserClickData(clickCounts: 1, categoryId: catID, postId: postID, postType: postType.rawValue)
PersistentStorage.shared.checkWebSeries(clicksData: userClicks)
}
}
// MARK: - Handling ADS
extension PersistentStorage{
func sendAdsData(isLogout : Bool = false) {
//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}
print("userImpressions Count from SendAdsData to server :- ", result.count)
//if data is less , dont keep sending the data to server
if isLogout == false,result.count < 2 {
print("Not Enough Ads Data")
return
}
var userImpressions = [AdsClickImpressionsData]()
//map the impressions
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("ADs Data :- ","ID:-" , ads.ad_id, "No Of Clicks :- ", ads.no_of_click, "Impressions :- ", ads.no_of_impression)
}
//Send it to server and delete from our DB
NetworkManager.shareInstance.nwCallRawJSONAds(adsData: userImpressions) { isDone in
if isDone{
self.deleteAdsData(result)
}
}
}
catch let error
{
debugPrint(error)
}
}
func deleteAdsData(_ data: [AdClicksImpressions],isLogout : Bool = false) {
let managedContext = PersistentStorage.shared.context
data.forEach { clicks in
managedContext.delete(clicks)
}
do {
try managedContext.save()
getAllAdsData(isLogout: isLogout)
print("Deleted data")
} catch let error {
debugPrint("Failed to delete data:", error)
}
}
func getAllAdsData(isLogout : Bool = false) {
//We need to create a context from this container
let managedContext = PersistentStorage.shared.context
let fetchRequest:NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "AdClicksImpressions")
do {
guard let result = try managedContext.fetch(fetchRequest) as? [AdClicksImpressions] else {return}
print("UserClicks Count from getAllData :- ", result.count)
//if data is less , dont keep sending the data to server
if isLogout == false,result.count < 2 {
print("Not Enough Ads Data")
return
}else{
// send ads data again to server
sendAdsData()
print("Ads Data sent Again.")
}
// result.forEach { clicks in
// // device type 1- android , 2 - iOS
// print("ID:-" , PostType(rawValue: Int(clicks.post_type))!, "CatID:- ", clicks.category_id, "PostID:- ", clicks.post_id , "Count:-", clicks.click_counts)
// }
} catch let error{
debugPrint(error)
}
}
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)")
}
}
// MARK: - Add Ads to CoreData
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()
//show the ad saved in cored data
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)
}
}
// MARK: - Sync CoreData to server
extension PersistentStorage{
func getEntityDataCount() -> (Int,Int){
let managedContext = PersistentStorage.shared.context
let adsFetchReq:NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "AdClicksImpressions")
let clicksFetchReq:NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "UserClicks")
do {
// Perform the count request
let adsCount = try managedContext.count(for: adsFetchReq)
let clicksCount = try managedContext.count(for: clicksFetchReq)
return (adsCount,clicksCount)
} catch let error as NSError {
print("Error fetching count: \(error), \(error.userInfo)")
return (0,0)
}
}
func checkLastSync(){
/*
check ad timestamp from gvar
show ads if the saved timestamp time and current time has diffrenece of 30 minutes
*/
if let timeStamp = K.GVar.lastDataSync{
/*
check if timestamp difference is equal and greater than 60 minutes i.e 3600 seconds
*/
let duration = DateFormatterLib.dateDifferenceINT(date1: timeStamp, date2: Date())
print("Last Sync Duration :- ", duration, " Seconds.")
if duration <= 3600{ //if last data sync has not
// dont sync data.
print("Last sync has not passed 1 hour")
}else{
//Sync data to server if the last sync time has been changed.
syncData()
}
}else{
/*
Assign the date and sync the data to server
*/
syncData()
}
}
func syncData(){
K.GVar.lastDataSync = Date()
self.sendAdsData()
self.sendDataToServer()
print("Data Synced to Server.")
}
}