// // MyListVC.swift // // Created by Bilal on 19/05/2024. // import UIKit class MyListVC: UIViewController{ @IBOutlet weak var webSeriesCV: UICollectionView! @IBOutlet weak var webSeriesEnglishStack: UIStackView! @IBOutlet weak var webSeriesHindiCV: UICollectionView! @IBOutlet weak var webSeriesHindiStack: UIStackView! @IBOutlet weak var audioBooksCV: UICollectionView! @IBOutlet weak var audioBooksStack: UIStackView! @IBOutlet weak var karaokeCV: UICollectionView! @IBOutlet weak var karaokeStack: UIStackView! @IBOutlet weak var gamesCV: UICollectionView! @IBOutlet weak var gamesStack: UIStackView! @IBOutlet weak var noDataStack: UIStackView! @IBOutlet weak var scrollView: UIScrollView! @IBOutlet weak var gradientView: UIView! @IBOutlet weak var guestLoginView: UIView! @IBOutlet weak var guestLoginStack: UIStackView! var vm = MyListVM() override func viewDidLoad() { super.viewDidLoad() vm.vc = self vm.initView() vm.refreshControl.attributedTitle = NSAttributedString(string: "Refreshing...",attributes: [.foregroundColor: UIColor.appColor(.TextDarkBlue)!]) vm.refreshControl.tintColor = UIColor.appColor(.TextDarkBlue)! vm.refreshControl.addTarget(self, action: #selector(self.refresh(_:)), for: .valueChanged) scrollView.addSubview(vm.refreshControl) } @objc func refresh(_ sender: AnyObject) { Timer.scheduledTimer(withTimeInterval: 1, repeats: false) { [unowned self] _ in vm.getFavouriteListing() } } override func viewWillAppear(_ animated: Bool) { } override func viewWillDisappear(_ animated: Bool) { } override func viewDidLayoutSubviews() { vm.addGradient() } override func viewDidAppear(_ animated: Bool) { if K.GVar.reloadMyList{ K.GVar.reloadMyList = false Utilities.startProgressHUD() vm.getFavouriteListing() } } @IBAction func sideBarBtnTapped(_ sender: UIButton) { self.sideMenuController?.revealMenu() } @IBAction func backBtntapped(_ sender: UIButton) { self.tabBarController?.selectedIndex = 0 } @IBAction func freeSignIn(_ sender: LocalisedElementsButton) { UIApplication.setRootView(LoginNavVC.instantiate(from: .AuthenticationSB)) } } // MARK: - CollectionView Delegate extension MyListVC : CollectionViewSRC{ func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { switch collectionView{ case webSeriesCV: if vm.favListingData?.showData?.count == 0 || vm.favListingData == nil{ webSeriesEnglishStack.isHidden = true }else{ webSeriesEnglishStack.isHidden = false } return vm.favListingData?.showData?.count ?? 0 case audioBooksCV: if vm.favListingData?.audioData?.count == 0 || vm.favListingData == nil{ audioBooksStack.isHidden = true }else{ audioBooksStack.isHidden = false } return vm.favListingData?.audioData?.count ?? 0 case karaokeCV: if vm.favListingData?.singKaraokeData?.count == 0 || vm.favListingData == nil{ karaokeStack.isHidden = true }else{ karaokeStack.isHidden = false } return vm.favListingData?.singKaraokeData?.count ?? 0 case gamesCV: if vm.favListingData?.gameData?.count == 0 || vm.favListingData == nil{ gamesStack.isHidden = true }else{ gamesStack.isHidden = false } return vm.favListingData?.gameData?.count ?? 0 case webSeriesHindiCV: if vm.webSeriesHindi.count == 0 || vm.favListingData == nil{ webSeriesHindiStack.isHidden = true }else{ webSeriesHindiStack.isHidden = false } return vm.webSeriesHindi.count default: return 0 } } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: K.CellIdentifier.Home.favouriteCell, for: indexPath) as! FavouriteCell switch collectionView{ case webSeriesCV: if let data = vm.favListingData?.showData?[indexPath.row]{ cell.setData(data: data) } case webSeriesHindiCV: let data = vm.webSeriesHindi[indexPath.row] cell.setData(data: data) case audioBooksCV: if let data = vm.favListingData?.audioData?[indexPath.row]{ cell.setAudioData(data: data) } case karaokeCV: if let data = vm.favListingData?.singKaraokeData?[indexPath.row]{ cell.setOtherData(data: data) } case gamesCV: if let data = vm.favListingData?.gameData?[indexPath.row]{ cell.setOtherData(data: data) } default: if let data = vm.favListingData?.showData?[indexPath.row]{ cell.setData(data: data) } } cell.btnTapped = { [self] (type) -> Void in updateFavLikes(cv: collectionView, type: type, index: indexPath.row) } return cell } func updateFavLikes(cv : UICollectionView , type : FavCellCLick, index : Int){ switch cv{ case webSeriesCV: guard let data = vm.favListingData?.showData?[index] else{return} switch type { case .favourite: guard let isFav = data.markAsFavourite ,let postID = data.id,let postType = data.contentMoreDetails?.first?.postType,let categoryID = data.bookmarkCategoryIDS else{return} if isFav{ vm.removeFavourite(postID: postID, postType: postType, categoryID: categoryID, index: index) { [unowned self] isDone in if isDone{ vm.favListingData?.showData?.remove(at: index) webSeriesCV.reloadData() vm.checkNil() } } } case .liked: guard let isLiked = data.isLiked ,let postID = data.id,let postType = data.contentMoreDetails?.first?.postType else{return} if isLiked{ vm.unlikePost(postID: postID, postType: postType, index: index) { [unowned self] isDone in if isDone{ vm.favListingData?.showData?[index].isLiked = false vm.favListingData?.showData?[index].likesCount! -= 1 webSeriesCV.reloadItems(at: [IndexPath(row: index, section: 0)]) for (i,element) in vm.webSeriesHindi.enumerated(){ if element.id == vm.favListingData?.showData?[index].id{ vm.webSeriesHindi[i].isLiked = false vm.webSeriesHindi[i].likesCount! -= 1 webSeriesHindiCV.reloadItems(at: [IndexPath(row: i, section: 0)]) } } } } }else{ vm.likePost(postID: postID, postType: postType, index: index){ [unowned self] isDone in if isDone{ vm.favListingData?.showData?[index].isLiked = true vm.favListingData?.showData?[index].likesCount! += 1 webSeriesCV.reloadItems(at: [IndexPath(row: index, section: 0)]) for (i,element) in vm.webSeriesHindi.enumerated(){ if element.id == vm.favListingData?.showData?[index].id{ vm.webSeriesHindi[i].isLiked = true vm.webSeriesHindi[i].likesCount! += 1 webSeriesHindiCV.reloadItems(at: [IndexPath(row: i, section: 0)]) } } } } } } case webSeriesHindiCV: let data = vm.webSeriesHindi[index] switch type { case .favourite: guard let isFav = data.markAsFavourite ,let postID = data.id,let postType = data.contentMoreDetails?.first?.postType,let categoryID = data.bookmarkCategoryIDS else{return} if isFav{ vm.removeFavourite(postID: postID, postType: postType, categoryID: categoryID, index: index) { [unowned self] isDone in if isDone{ vm.webSeriesHindi.remove(at: index) webSeriesHindiCV.reloadData() vm.checkNil() } } } case .liked: // Hindi Data guard let isLiked = data.isLiked ,let postID = data.id,let postType = data.contentMoreDetails?.first?.postType else{return} if isLiked{ vm.unlikePost(postID: postID, postType: postType, index: index) { [unowned self] isDone in if isDone{ vm.webSeriesHindi[index].isLiked = false vm.webSeriesHindi[index].likesCount! -= 1 webSeriesHindiCV.reloadItems(at: [IndexPath(row: index, section: 0)]) vm.checkNil() guard let showData = vm.favListingData?.showData else{return} for (i,element) in showData.enumerated(){ if element.id == vm.webSeriesHindi[index].id{ vm.favListingData?.showData?[i].isLiked = false vm.favListingData?.showData?[i].likesCount! -= 1 webSeriesCV.reloadItems(at: [IndexPath(row: i, section: 0)]) } } } } }else{ vm.likePost(postID: postID, postType: postType, index: index){ [unowned self] isDone in if isDone{ vm.webSeriesHindi[index].isLiked = true vm.webSeriesHindi[index].likesCount! += 1 webSeriesHindiCV.reloadItems(at: [IndexPath(row: index, section: 0)]) vm.checkNil() guard let showData = vm.favListingData?.showData else{return} for (i,element) in showData.enumerated(){ if element.id == vm.webSeriesHindi[index].id{ vm.favListingData?.showData?[i].isLiked = true vm.favListingData?.showData?[i].likesCount! += 1 webSeriesCV.reloadItems(at: [IndexPath(row: i, section: 0)]) } } } } } } case audioBooksCV: guard let data = vm.favListingData?.audioData?[index] else{return} switch type { case .favourite: guard let isFav = data.markAsFavourite ,let postID = data.id,let postType = data.contentMoreDetails?.first?.postType else{return} if isFav{ vm.removeFavourite(postID: postID, postType: postType, categoryID: "", index: index) { [unowned self] isDone in if isDone{ vm.favListingData?.audioData?.remove(at: index) audioBooksCV.reloadData() vm.checkNil() } } } case .liked: guard let isLiked = data.isLiked ,let postID = data.id,let postType = data.contentMoreDetails?.first?.postType else{return} if isLiked{ vm.unlikePost(postID: postID, postType: postType, index: index) { [unowned self] isDone in if isDone{ vm.favListingData?.audioData?[index].isLiked = false vm.favListingData?.audioData?[index].likesCount! -= 1 audioBooksCV.reloadItems(at: [IndexPath(row: index, section: 0)]) vm.checkNil() } } }else{ vm.likePost(postID: postID, postType: postType, index: index){ [unowned self] isDone in if isDone{ vm.favListingData?.audioData?[index].isLiked = true vm.favListingData?.audioData?[index].likesCount! += 1 audioBooksCV.reloadItems(at: [IndexPath(row: index, section: 0)]) vm.checkNil() } } } } case karaokeCV: guard let data = vm.favListingData?.singKaraokeData?[index] else{return} switch type { case .favourite: guard let isFav = data.markAsFavourite ,let postID = data.id,let postType = data.contentMoreDetails?.first?.postType else{return} if isFav{ vm.removeFavourite(postID: postID, postType: postType, categoryID: "", index: index) { [unowned self] isDone in if isDone{ vm.favListingData?.singKaraokeData?.remove(at: index) karaokeCV.reloadData() vm.checkNil() } } } case .liked: guard let isLiked = data.isLiked ,let postID = data.id,let postType = data.contentMoreDetails?.first?.postType else{return} if isLiked{ vm.unlikePost(postID: postID, postType: postType, index: index) { [unowned self] isDone in if isDone{ vm.favListingData?.singKaraokeData?[index].isLiked = false vm.favListingData?.singKaraokeData?[index].likesCount! -= 1 karaokeCV.reloadItems(at: [IndexPath(row: index, section: 0)]) vm.checkNil() } } }else{ vm.likePost(postID: postID, postType: postType, index: index){ [unowned self] isDone in if isDone{ vm.favListingData?.singKaraokeData?[index].isLiked = true vm.favListingData?.singKaraokeData?[index].likesCount! += 1 karaokeCV.reloadItems(at: [IndexPath(row: index, section: 0)]) vm.checkNil() } } } } case gamesCV: guard let data = vm.favListingData?.gameData?[index] else{return} switch type { case .favourite: guard let isFav = data.markAsFavourite ,let postID = data.id,let postType = data.contentMoreDetails?.first?.postType else{return} if isFav{ vm.removeFavourite(postID: postID, postType: postType, categoryID: "", index: index) { [unowned self] isDone in if isDone{ vm.favListingData?.gameData?.remove(at: index) gamesCV.reloadData() vm.checkNil() } } } case .liked: guard let isLiked = data.isLiked ,let postID = data.id,let postType = data.contentMoreDetails?.first?.postType else{return} if isLiked{ vm.unlikePost(postID: postID, postType: postType, index: index) { [unowned self] isDone in if isDone{ vm.favListingData?.gameData?[index].isLiked = false vm.favListingData?.gameData?[index].likesCount! -= 1 gamesCV.reloadItems(at: [IndexPath(row: index, section: 0)]) vm.checkNil() } } }else{ vm.likePost(postID: postID, postType: postType, index: index){ [unowned self] isDone in if isDone{ vm.favListingData?.gameData?[index].isLiked = true vm.favListingData?.gameData?[index].likesCount! += 1 gamesCV.reloadItems(at: [IndexPath(row: index, section: 0)]) vm.checkNil() } } } } default: break } } func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { switch collectionView{ case webSeriesCV: guard let showData = vm.favListingData?.showData?[indexPath.row] else{return} let showDataModified = WebSeriesShowListDM.ShowDatum(id: showData.id, title: showData.title, description: showData.description, thumbnailPath: showData.thumbnailPath, showType: showData.showType, totalSeasons: showData.totalSeasons, totalEpisodes: showData.totalEpisodes, categoryMasterID: nil, ageRangeMasterID: nil, genderMasterID: showData.genderMasterID, contentMoreDetails: showData.contentMoreDetails, seasonData: nil, categoryData: nil, ageRangeData: nil, genderData: nil, markAsFavourite: showData.markAsFavourite, isLiked: showData.isLiked, likedCategoryIDS: nil, favouriteCategoryIDS: ValueWrapper.stringValue(showData.bookmarkCategoryIDS ?? "1") , likesCount: showData.likesCount, viewsCount: showData.viewsCount, bookmarkCount: showData.bookmarkCount) let sb = UIStoryboard(name: K.StoryBoard.webSeries, bundle: nil) let vcPush = sb.instantiateViewController(withIdentifier: K.StoryBoardID.WebSeries.webSeriesSeasonVC) as! WebSeriesSeasonVC vcPush.vm.showData = showDataModified vcPush.vm.indexSelected = indexPath.row vcPush.likeFavDelegate = self vcPush.vm.categoryID = 1 self.navigationController?.pushViewController(vcPush, animated: true) self.vm.selectedCollection = .webSeriesCV case webSeriesHindiCV: let showData = vm.webSeriesHindi[indexPath.row] let showDataModified = WebSeriesShowListDM.ShowDatum(id: showData.id, title: showData.title, description: showData.description, thumbnailPath: showData.thumbnailPath, showType: showData.showType, totalSeasons: showData.totalSeasons, totalEpisodes: showData.totalEpisodes, categoryMasterID: nil, ageRangeMasterID: nil, genderMasterID: showData.genderMasterID, contentMoreDetails: showData.contentMoreDetails, seasonData: nil, categoryData: nil, ageRangeData: nil, genderData: nil, markAsFavourite: showData.markAsFavourite, isLiked: showData.isLiked, likedCategoryIDS: nil, favouriteCategoryIDS: ValueWrapper.stringValue(showData.bookmarkCategoryIDS ?? "1") , likesCount: showData.likesCount, viewsCount: showData.viewsCount, bookmarkCount: showData.bookmarkCount) let sb = UIStoryboard(name: K.StoryBoard.webSeries, bundle: nil) let vcPush = sb.instantiateViewController(withIdentifier: K.StoryBoardID.WebSeries.webSeriesSeasonVC) as! WebSeriesSeasonVC vcPush.vm.showData = showDataModified vcPush.vm.indexSelected = indexPath.row vcPush.likeFavDelegate = self vcPush.vm.categoryID = 18 self.navigationController?.pushViewController(vcPush, animated: true) self.vm.selectedCollection = .webSeriesHindiCV case audioBooksCV: guard let audioData = vm.favListingData?.audioData?[indexPath.row] else{return} 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 = audioData vcPush.delegate = self self.present(vcPush, animated: true) default: print(indexPath.row) } } } // MARK: - Delegate for reload extension MyListVC : ReloadAudioBooksFavLike{ func updateAudioRows(id: Int, type: FavCellCLick, isFav: Bool?, isLike: Bool?) { if let isFav{ if let audioListDataIndex = vm.favListingData?.audioData?.firstIndex(where:{$0.id == id}) { vm.favListingData?.audioData?[audioListDataIndex].markAsFavourite = isFav audioBooksCV.reloadItems(at: [IndexPath(row: audioListDataIndex, section: 0)]) K.GVar.reloadMyList = true } } if let isLike{ if let audioListDataIndex = vm.favListingData?.audioData?.firstIndex(where:{$0.id == id}) { vm.favListingData?.audioData?[audioListDataIndex].isLiked = isLike audioBooksCV.reloadItems(at: [IndexPath(row: audioListDataIndex, section: 0)]) K.GVar.reloadMyList = true } } } } extension MyListVC : ReloadSeriesFavLike{ func updateRows(index: Int, type: FavCellCLick, isFav: Bool?, isLike: Bool?) { switch vm.selectedCollection { case .webSeriesCV: // if let isFav{ // let categoryID = vm.categoryListingData[vm.dropDownModule.indexForSelectedRow ?? 0].id ?? 0 // switch isFav{ // case true: // vm.showData[index].markAsFavourite = true // vm.showData[index].favouriteCategoryIDS = ValueWrapper.stringValue(categoryID.toString()) // showListingTableView.reloadRows(at: [IndexPath(row: index, section: 0)],with: .none) // case false: // vm.showData[index].markAsFavourite = false // vm.showData[index].favouriteCategoryIDS = ValueWrapper.stringValue("") // showListingTableView.reloadRows(at: [IndexPath(row: index, section: 0)],with: .none) // } // K.GVar.reloadMyList = true // } if let isLike{ switch isLike{ case true: vm.favListingData?.showData?[index].isLiked = true vm.favListingData?.showData?[index].likesCount! += 1 webSeriesCV.reloadItems(at: [IndexPath(row: index, section: 0)]) for (i,element) in vm.webSeriesHindi.enumerated(){ if element.id == vm.favListingData?.showData?[index].id{ vm.webSeriesHindi[i].isLiked = true vm.webSeriesHindi[i].likesCount! += 1 webSeriesHindiCV.reloadItems(at: [IndexPath(row: i, section: 0)]) } } case false: vm.favListingData?.showData?[index].isLiked = false vm.favListingData?.showData?[index].likesCount! -= 1 webSeriesCV.reloadItems(at: [IndexPath(row: index, section: 0)]) for (i,element) in vm.webSeriesHindi.enumerated(){ if element.id == vm.favListingData?.showData?[index].id{ vm.webSeriesHindi[i].isLiked = false vm.webSeriesHindi[i].likesCount! -= 1 webSeriesHindiCV.reloadItems(at: [IndexPath(row: i, section: 0)]) } } } } case .webSeriesHindiCV: if let isLike{ switch isLike{ case true: vm.webSeriesHindi[index].isLiked = true vm.webSeriesHindi[index].likesCount! += 1 webSeriesHindiCV.reloadItems(at: [IndexPath(row: index, section: 0)]) vm.checkNil() guard let showData = vm.favListingData?.showData else{return} for (i,element) in showData.enumerated(){ if element.id == vm.webSeriesHindi[index].id{ vm.favListingData?.showData?[i].isLiked = true vm.favListingData?.showData?[i].likesCount! += 1 webSeriesCV.reloadItems(at: [IndexPath(row: i, section: 0)]) } } case false: vm.webSeriesHindi[index].isLiked = false vm.webSeriesHindi[index].likesCount! -= 1 webSeriesHindiCV.reloadItems(at: [IndexPath(row: index, section: 0)]) vm.checkNil() guard let showData = vm.favListingData?.showData else{return} for (i,element) in showData.enumerated(){ if element.id == vm.webSeriesHindi[index].id{ vm.favListingData?.showData?[i].isLiked = false vm.favListingData?.showData?[i].likesCount! -= 1 webSeriesCV.reloadItems(at: [IndexPath(row: i, section: 0)]) } } } } default: break } // print(index , type , isFav, isLike) } func updateFavLikes(type : FavCellCLick, index : Int){ switch vm.selectedCollection { case .webSeriesCV: guard let data = vm.favListingData?.showData?[index] else{return} let categoryID = 1 switch type { case .favourite: guard let isFav = data.markAsFavourite ,let postID = data.id,let postType = data.contentMoreDetails?.first?.postType else{return} if let categoryIds = data.bookmarkCategoryIDS { let components = categoryIds.components(separatedBy: ",") if isFav == true && (components.first == categoryID.toString() || components.last == categoryID.toString()){ LikeFavCommonFunc.shareInstance.removeFavourite(postID: postID, postType: postType, categoryID: categoryID, vc: self) { [unowned self] isDone in if isDone{ vm.favListingData?.showData?.remove(at: index) webSeriesCV.reloadItems(at: [IndexPath(row: index, section: 0)]) } } } return } case .liked: break // guard let isLiked = data.isLiked ,let postID = data.id,let postType = data.contentMoreDetails?.first?.postType else{return} // if isLiked{ // LikeFavCommonFunc.shareInstance.unlikePost(postID: postID, postType: postType, index: index, vc: self) { [unowned self] isDone in // if isDone{ // vm.showData[index].isLiked = false // vm.showData[index].likesCount! -= 1 // showListingTableView.reloadRows(at: [IndexPath(row: index, section: 0)],with: .none) // } // } // }else{ // LikeFavCommonFunc.shareInstance.likePost(postID: postID, postType: postType, index: index, vc: self){ [unowned self] isDone in // if isDone{ // vm.showData[index].isLiked = true // vm.showData[index].likesCount! += 1 // showListingTableView.reloadRows(at: [IndexPath(row: index, section: 0)],with: .none) // } // } // } } case .webSeriesHindiCV: let data = vm.webSeriesHindi[index] let categoryID = 18 switch type { case .favourite: guard let isFav = data.markAsFavourite ,let postID = data.id,let postType = data.contentMoreDetails?.first?.postType else{return} if let categoryIds = data.bookmarkCategoryIDS { let components = categoryIds.components(separatedBy: ",") if isFav == true && (components.first == categoryID.toString() || components.last == categoryID.toString()){ LikeFavCommonFunc.shareInstance.removeFavourite(postID: postID, postType: postType, categoryID: categoryID, vc: self) { [unowned self] isDone in if isDone{ vm.webSeriesHindi.remove(at: index) // vm.webSeriesHindi[index].markAsFavourite = false // vm.webSeriesHindi[index].bookmarkCategoryIDS = "" webSeriesHindiCV.reloadItems(at: [IndexPath(row: index, section: 0)]) } } }else{ LikeFavCommonFunc.shareInstance.addFavourite(postID: postID, postType: postType, categoryID: categoryID, vc: self) { [unowned self] isDone in if isDone{ vm.webSeriesHindi[index].markAsFavourite = false vm.webSeriesHindi[index].bookmarkCategoryIDS = categoryID.toString() webSeriesHindiCV.reloadItems(at: [IndexPath(row: index, section: 0)]) } } } return } case .liked: break // guard let isLiked = data.isLiked ,let postID = data.id,let postType = data.contentMoreDetails?.first?.postType else{return} // if isLiked{ // LikeFavCommonFunc.shareInstance.unlikePost(postID: postID, postType: postType, index: index, vc: self) { [unowned self] isDone in // if isDone{ // vm.showData[index].isLiked = false // vm.showData[index].likesCount! -= 1 // showListingTableView.reloadRows(at: [IndexPath(row: index, section: 0)],with: .none) // } // } // }else{ // LikeFavCommonFunc.shareInstance.likePost(postID: postID, postType: postType, index: index, vc: self){ [unowned self] isDone in // if isDone{ // vm.showData[index].isLiked = true // vm.showData[index].likesCount! += 1 // showListingTableView.reloadRows(at: [IndexPath(row: index, section: 0)],with: .none) // } // } // } } case .audioBooksCV: break case .karaokeCV: break case .gamesCV: break case .none: break } } } // MARK: - Collection Flow Layout extension MyListVC : 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) } }