Files
Woka_Native_iOS/WOKA/Audio Books/AudioBookHomeVC.swift
2024-10-18 21:04:58 +05:30

544 lines
22 KiB
Swift

//
// AudioBookHomeVC.swift
// WOKA
//
// Created by MacBook Pro on 02/07/24.
//
import UIKit
import GoogleMobileAds
class AudioBookHomeVC: UIViewController {
var vm = AudioBookHomeVM()
@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!
@IBOutlet weak var topLabel: UILabel!
@IBOutlet weak var headerViewTopConstraint: NSLayoutConstraint!
@IBOutlet weak var continueWatchingStack: UIStackView!
@IBOutlet weak var headerView: ShimmerEffectView!
@IBOutlet weak var headerImage: UIImageView!
@IBOutlet weak var headerTitleLabel: UILabel!
@IBOutlet weak var listenView: ShimmerEffectView!
@IBOutlet weak var noDataView: UIView!
@IBOutlet weak var loadMoreActivityIndicator: UIActivityIndicatorView!
override func viewDidLoad() {
super.viewDidLoad()
vm.vc = self
self.title = "AUDIO BOOKS".localized(loc: AuthFunc.shareInstance.languageSelected.rawValue)
vm.initView()
scrollView.delegate = self
navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
navigationController?.navigationBar.shadowImage = UIImage()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationController?.setNavigationBarHidden(false, animated: animated)
self.navigationController?.setColor(color: .white)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.navigationController?.setNavigationBarHidden(true, animated: animated)
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
self.navigationController?.navigationBar.removeGradientBackground()
// Customize the navigation bar's appearance
self.navigationController?.setColor(color: .black)
if self.isMovingFromParent {
// Back button was pressed
PersistentStorage.shared.addOthersCount()
}
}
override func viewDidAppear(_ animated: Bool) {
if K.GVar.reloadContinueAudioBooks{
K.GVar.reloadContinueAudioBooks = false
vm.getContinueWatching()
}
/*
Check if ads is there to map impressions for local ads.
*/
if let adsData = AuthFunc.shareInstance.adsData{
// check if ads data contains ad for webseries
if let audioBooksAd = adsData.result?.filter({$0.slug == AdsEnum.audioBooks.rawValue}).first, let adID = audioBooksAd.advertisement?.id{
PersistentStorage.shared.addAdsCount(adID: adID ,impressions: 1)
}
}
}
override func viewDidLayoutSubviews() {
vm.updateTableHeight()
}
// @IBAction func loadMoreBtn(_ sender: LocalisedElementsButton) {
// PersistentStorage.shared.addOthersCount()
// if CheckReachability.reachability?.isReachable == false{
// self.toast(msg: K.ConstantString.noInternet , time: 2)
// return
// }
// loadMoreBtn.isHidden = true
// vm.pageNo += 1
// loadMoreActivityIndicator.startAnimating()
// vm.getShowListing()
// }
@IBAction func listenAudioBtnTapped(_ sender: LocalisedElementsButton) {
/*
MAke logic for ads
*/
if let adsData = AuthFunc.shareInstance.adsData, let audioBooksAd = adsData.result?.filter({$0.slug == AdsEnum.audioBooks.rawValue}).first{
// URL maybe null so handle it
if audioBooksAd.advertisement?.isActive == "1" && audioBooksAd.advertisement?.adLink == nil{
// it means local ad is active and url is null
return
}
// check if ads data contains ad for webseries
if let adLink = audioBooksAd.advertisement?.adLink, let adID = audioBooksAd.advertisement?.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]()
if AuthFunc.shareInstance.getDefaultLanguage() == .english{
if let englishData = data.contentMoreDetails?.filter({$0.languageMasterID == 1}).first, let url = englishData.url{
playerItems.append(JwPlayerItemCreate(url: url, poster: data.thumbnailPath, titles: englishData.title))
}
}else{
if let hindiData = data.contentMoreDetails?.filter({$0.languageMasterID == 2}).first, let url = hindiData.url{
playerItems.append(JwPlayerItemCreate(url: url, poster: data.thumbnailPath, titles: hindiData.title))
}
}
JWPlayerManager.shared.presentPlayer(from: self, playerItems: playerItems, startIndex: 0, contentType: .audioBooks, videoIDs: [postID])
}
@IBAction func retryBtnTapped(_ sender: LocalisedElementsButton) {
/*
make page 0 as its lazy loading, hide the no data stack as retry is tapped,
start the shimmer and reload tableview so that both header and table shimmer matches, get the karaoke listing
*/
vm.pageNo = 0
noDataView.isHidden = true
vm.startShimmer()
vm.getShowListing()
}
}
// MARK: - Delegate for reload
extension AudioBookHomeVC : ReloadSeriesFavLike{
func updateRows(index: Int, type: FavCellCLick, isFav: Bool?, isLike: Bool?, id: Int?) {
if let isFav{
if let continueDataIndex = vm.continueWatchingData.firstIndex(where:{$0.id == id}) {
vm.continueWatchingData[continueDataIndex].markAsFavourite = isFav
continueWatchingCV.reloadItems(at: [IndexPath(row: continueDataIndex, section: 0)])
}
if let audioListDataIndex = vm.audioListData.firstIndex(where:{$0.id == id}) {
vm.audioListData[audioListDataIndex].markAsFavourite = isFav
audioListingTableView.reloadRows(at: [IndexPath(row: audioListDataIndex, section: 0)],with: .none)
}
}
if let isLike{
if let continueDataIndex = vm.continueWatchingData.firstIndex(where:{$0.id == id}) {
vm.continueWatchingData[continueDataIndex].isLiked = isLike
if isLike{
vm.continueWatchingData[continueDataIndex].likesCount! += 1
}else{
vm.continueWatchingData[continueDataIndex].likesCount! -= 1
}
continueWatchingCV.reloadItems(at: [IndexPath(row: continueDataIndex, section: 0)])
}
if let audioListDataIndex = vm.audioListData.firstIndex(where:{$0.id == id}) {
vm.audioListData[audioListDataIndex].isLiked = isLike
if isLike{
vm.audioListData[audioListDataIndex].likesCount! += 1
}else{
vm.audioListData[audioListDataIndex].likesCount! -= 1
}
audioListingTableView.reloadRows(at: [IndexPath(row: audioListDataIndex, section: 0)],with: .none)
}
}
}
}
// MARK: - TableView DataSource , Delegates
extension AudioBookHomeVC : TableViewSRC{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return vm.audioListData.count == 0 ? 2 : vm.audioListData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: K.CellIdentifier.WebSeries.webSeriesShowListingCell) as! WebSeriesShowListingCell
if vm.audioListData.count == 0{
cell.showShimmer()
}else{
let data = vm.audioListData[indexPath.row]
cell.setAudioData(data: data)
cell.stopShimmer()
}
cell.btnTapped = { [weak self] (type) -> Void in
guard let self else{return}
HapticFeedbackGenerator.shared.simpleSelection()
let data = vm.audioListData[indexPath.row]
guard let postID = data.id ,let postType = data.contentMoreDetails?.first?.postType else{return}
let isFav = data.markAsFavourite
let isLiked = data.isLiked
PersistentStorage.shared.addAudioCount(postID: postID)
vm.updateFavLikes(type: type, isFav: isFav, isLiked: isLiked, postID: postID, postType: postType)
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let data = vm.audioListData[indexPath.row]
if let postID = data.id{
PersistentStorage.shared.addAudioCount(postID: postID)
}
/*
MAke logic for ads
*/
if let adsData = AuthFunc.shareInstance.adsData, let audioBooksAd = adsData.result?.filter({$0.slug == AdsEnum.audioBooks.rawValue}).first, (audioBooksAd.advertisement != nil || audioBooksAd.googleAd != nil){
// check if ads data contains ad for webseries
}else{
/*
Updated the top header data
*/
vm.headerData = data
vm.setHeaderData()
}
let sb = UIStoryboard(name: K.StoryBoard.audioBooks, bundle: nil)
let vcPush = sb.instantiateViewController(withIdentifier: K.StoryBoardID.AudioBooks.audioBookDetailsVC) as! AudioBookDetailsVC
vcPush.modalPresentationStyle = .overCurrentContext
vcPush.modalTransitionStyle = .crossDissolve
vcPush.audioData = data
vcPush.delegate = self
self.present(vcPush, animated: true)
}
}
// MARK: - CollectionView Delegate and Data Source
extension AudioBookHomeVC : CollectionViewSRC{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return vm.continueWatchingData.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: K.CellIdentifier.AudioBooks.continueAudioCell, for: indexPath) as! ContinueAudioCell
let data = vm.continueWatchingData[indexPath.row]
cell.setAudioData(data: data)
cell.btnTapped = { [self] (type) -> Void in
HapticFeedbackGenerator.shared.simpleSelection()
guard let postID = data.id ,let postType = data.contentMoreDetails?.first?.postType else{return}
let isFav = data.markAsFavourite
let isLiked = data.isLiked
PersistentStorage.shared.addAudioCount(postID: postID)
vm.updateFavLikes(type: type, isFav: isFav, isLiked: isLiked, postID: postID, postType: postType)
}
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let data = vm.continueWatchingData[indexPath.row]
if let postID = data.id{
PersistentStorage.shared.addAudioCount(postID: postID)
}
/*
MAke logic for ads
*/
if let adsData = AuthFunc.shareInstance.adsData, let audioBooksAd = adsData.result?.filter({$0.slug == AdsEnum.audioBooks.rawValue}).first, (audioBooksAd.advertisement != nil || audioBooksAd.googleAd != nil){
// check if ads data contains ad for webseries
}else{
/*
Updated the top header data
*/
vm.headerData = data
vm.setHeaderData()
}
let sb = UIStoryboard(name: K.StoryBoard.audioBooks, bundle: nil)
let vcPush = sb.instantiateViewController(withIdentifier: K.StoryBoardID.AudioBooks.audioBookDetailsVC) as! AudioBookDetailsVC
vcPush.modalPresentationStyle = .overCurrentContext
vcPush.modalTransitionStyle = .crossDissolve
vcPush.audioData = data
vcPush.delegate = self
self.present(vcPush, animated: true)
}
}
// MARK: - Collection Flow Layout
extension AudioBookHomeVC : UICollectionViewDelegateFlowLayout{
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 5
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
let inset: CGFloat = 10
return UIEdgeInsets(top: 0, left: inset, bottom: 0, right: inset)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 0 // Space between cells
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let widthPerItem = collectionView.frame.width - 30 // Adjust to your desired width
return CGSize(width: widthPerItem, height: 230)
}
}
// MARK: - Google Ad Banner Delegate
extension AudioBookHomeVC : GADBannerViewDelegate{
func bannerViewDidReceiveAd(_ bannerView: GADBannerView) {
switch bannerView{
case vm.headerBannerView:
headerView.stopShimmer()
case vm.headerBannerBottomView:
headerBtn.alpha = 0
headerBtn.isEnabled = false
listenView.stopShimmer()
default:
break
}
print("bannerViewDidReceiveAd")
bannerView.backgroundColor = #colorLiteral(red: 0.01960784314, green: 0, blue: 0.2196078431, alpha: 1)
}
func bannerView(_ bannerView: GADBannerView, didFailToReceiveAdWithError error: Error) {
switch bannerView{
case vm.headerBannerView:
headerView.stopShimmer()
vm.headerData = vm.audioListData.first
vm.setHeaderData()
case vm.headerBannerBottomView:
headerTitleLabel.isHidden = true
headerBtn.isHidden = true
listenView.stopShimmer()
default:
break
}
print("bannerView:didFailToReceiveAdWithError: \(error.localizedDescription)")
}
func bannerViewDidRecordImpression(_ bannerView: GADBannerView) {
print("bannerViewDidRecordImpression")
}
func bannerViewWillPresentScreen(_ bannerView: GADBannerView) {
print("bannerViewWillPresentScreen")
}
func bannerViewWillDismissScreen(_ bannerView: GADBannerView) {
print("bannerViewWillDIsmissScreen")
}
func bannerViewDidDismissScreen(_ bannerView: GADBannerView) {
print("bannerViewDidDismissScreen")
}
}
// MARK: - Animating scrollView
extension AudioBookHomeVC: UIScrollViewDelegate {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
// Get the current vertical offset of the scroll view
let y = scrollView.contentOffset.y
// 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 = vm.maxHeaderHeight
} else {
// Calculate the new height for the header view, ensuring it doesn't go below the minimum height
newHeaderHeight = max(minHeaderHeight, vm.maxHeaderHeight - y)
}
// Update the header view's height constraint with the new height
headerHeight.constant = newHeaderHeight
// Animate the layout changes to smoothly transition the header height
UIView.animate(withDuration: 0.3) {
self.view.layoutIfNeeded()
}
// dont do network call if the showdata count is same as the total count provided by api
// also check if already the api call is done
if vm.audioListData.count == vm.totalDataCount || vm.isAudioDataLoading == true {return}
let contentHeight = scrollView.contentSize.height
let height = scrollView.frame.size.height
// Check if the user scrolled to the bottom
if y > contentHeight - height - 50{
// check if internet is available
if CheckReachability.reachability?.isReachable == false{
return
}
//start the acitvity indicator
loadMoreActivityIndicator.startAnimating()
vm.isAudioDataLoading = true
vm.getShowListing(isBtnClick: true)
}
}
}
class UINavigationBarGradientView: UIView {
enum Point {
case topRight, topLeft
case bottomRight, bottomLeft
case left , right
case custom(point: CGPoint)
var point: CGPoint {
switch self {
case .topRight: return CGPoint(x: 1, y: 0)
case .topLeft: return CGPoint(x: 0, y: 0)
case .bottomRight: return CGPoint(x: 1, y: 1)
case .bottomLeft: return CGPoint(x: 0, y: 1)
case .left : return CGPoint(x: 0, y: 0)
case .right : return CGPoint(x: 0.8, y: 0)
case .custom(let point): return point
}
}
}
private weak var gradientLayer: CAGradientLayer!
convenience init(colors: [UIColor], startPoint: Point = .topLeft,
endPoint: Point = .bottomLeft, locations: [NSNumber] = [0, 1]) {
self.init(frame: .zero)
let gradientLayer = CAGradientLayer()
gradientLayer.frame = frame
layer.addSublayer(gradientLayer)
self.gradientLayer = gradientLayer
set(colors: colors, startPoint: startPoint, endPoint: endPoint, locations: locations)
backgroundColor = .clear
}
func set(colors: [UIColor], startPoint: Point = .topLeft,
endPoint: Point = .bottomLeft, locations: [NSNumber] = [0, 1]) {
gradientLayer.colors = colors.map { $0.cgColor }
gradientLayer.startPoint = startPoint.point
gradientLayer.endPoint = endPoint.point
gradientLayer.locations = locations
}
func setupConstraints() {
guard let parentView = superview else { return }
translatesAutoresizingMaskIntoConstraints = false
topAnchor.constraint(equalTo: parentView.topAnchor).isActive = true
leftAnchor.constraint(equalTo: parentView.leftAnchor).isActive = true
parentView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
parentView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
}
override func layoutSubviews() {
super.layoutSubviews()
guard let gradientLayer = gradientLayer else { return }
gradientLayer.frame = frame
superview?.addSubview(self)
}
}
extension UINavigationBar {
func setGradientBackground(colors: [UIColor],
startPoint: UINavigationBarGradientView.Point = .topLeft,
endPoint: UINavigationBarGradientView.Point = .bottomLeft,
locations: [NSNumber] = [0, 1]) {
guard let backgroundView = value(forKey: "backgroundView") as? UIView else { return }
guard let gradientView = backgroundView.subviews.first(where: { $0 is UINavigationBarGradientView }) as? UINavigationBarGradientView else {
let gradientView = UINavigationBarGradientView(colors: colors, startPoint: startPoint,
endPoint: endPoint, locations: locations)
backgroundView.addSubview(gradientView)
gradientView.setupConstraints()
return
}
gradientView.set(colors: colors, startPoint: startPoint, endPoint: endPoint, locations: locations)
}
func removeGradientBackground() {
guard let backgroundView = value(forKey: "backgroundView") as? UIView else { return }
if let gradientView = backgroundView.subviews.first(where: { $0 is UINavigationBarGradientView }) {
gradientView.removeFromSuperview()
}
}
}
extension CGPoint{
enum Point {
case topRight, topLeft
case bottomRight, bottomLeft
case left , right
case custom(point: CGPoint)
var point: CGPoint {
switch self {
case .topRight: return CGPoint(x: 1, y: 0)
case .topLeft: return CGPoint(x: 0, y: 0)
case .bottomRight: return CGPoint(x: 1, y: 1)
case .bottomLeft: return CGPoint(x: 0, y: 1)
case .left : return CGPoint(x: 0, y: 0)
case .right : return CGPoint(x: 0.8, y: 0)
case .custom(let point): return point
}
}
}
}