Toggle navigation
Toggle navigation
This project
Loading...
Sign in
open-source
/
warply_sdk_framework
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Graphs
Network
Create a new issue
Commits
Issue Boards
Authored by
Manos Chorianopoulos
2026-03-18 14:27:48 +0200
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
3f967f23184a547ec093594b8074b4398d2f0cea
3f967f23
1 parent
f1adb8ee
add new CarouselContent at MyRewardsViewController
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
189 additions
and
28 deletions
SwiftWarplyFramework/Pods/Pods.xcodeproj/xcuserdata/manoschorianopoulos.xcuserdatad/xcschemes/xcschememanagement.plist
SwiftWarplyFramework/SwiftWarplyFramework.xcodeproj/project.pbxproj
SwiftWarplyFramework/SwiftWarplyFramework.xcodeproj/xcuserdata/manoschorianopoulos.xcuserdatad/xcschemes/xcschememanagement.plist
SwiftWarplyFramework/SwiftWarplyFramework.xcworkspace/xcuserdata/manoschorianopoulos.xcuserdatad/UserInterfaceState.xcuserstate
SwiftWarplyFramework/SwiftWarplyFramework/Core/WarplySDK.swift
SwiftWarplyFramework/SwiftWarplyFramework/Network/Endpoints.swift
SwiftWarplyFramework/SwiftWarplyFramework/cells/MyRewardsBannerOfferCollectionViewCell/MyRewardsBannerOfferCollectionViewCell.swift
SwiftWarplyFramework/SwiftWarplyFramework/cells/MyRewardsBannerOffersScrollTableViewCell/MyRewardsBannerOffersScrollTableViewCell.swift
SwiftWarplyFramework/SwiftWarplyFramework/models/CarouselItemModel.swift
SwiftWarplyFramework/SwiftWarplyFramework/screens/MyRewardsViewController/MyRewardsViewController.swift
SwiftWarplyFramework/Pods/Pods.xcodeproj/xcuserdata/manoschorianopoulos.xcuserdatad/xcschemes/xcschememanagement.plist
View file @
3f967f2
...
...
@@ -7,7 +7,7 @@
<key>
Pods-SwiftWarplyFramework.xcscheme_^#shared#^_
</key>
<dict>
<key>
orderHint
</key>
<integer>
1
</integer>
<integer>
0
</integer>
</dict>
</dict>
</dict>
...
...
SwiftWarplyFramework/SwiftWarplyFramework.xcodeproj/project.pbxproj
View file @
3f967f2
...
...
@@ -76,6 +76,7 @@
626AF6DB2F698FF1008BCA08 /* MerchantAnnotation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 626AF6DA2F698FF1008BCA08 /* MerchantAnnotation.swift */; };
626AF6DE2F699081008BCA08 /* MapViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 626AF6DC2F699081008BCA08 /* MapViewController.swift */; };
626AF6DF2F699081008BCA08 /* MapViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 626AF6DD2F699081008BCA08 /* MapViewController.xib */; };
626DC8012F6ACA3B00CFC8C2 /* CarouselItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 626DC8002F6ACA3B00CFC8C2 /* CarouselItemModel.swift */; };
62A0A6D32F67FEDC00508534 /* MyCouponsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62A0A6D12F67FEDC00508534 /* MyCouponsViewController.swift */; };
62A0A6D42F67FEDC00508534 /* MyCouponsViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 62A0A6D22F67FEDC00508534 /* MyCouponsViewController.xib */; };
62A0A6D82F680C6A00508534 /* MyCouponsHeaderTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62A0A6D62F680C6A00508534 /* MyCouponsHeaderTableViewCell.swift */; };
...
...
@@ -160,6 +161,7 @@
626AF6DA2F698FF1008BCA08 /* MerchantAnnotation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MerchantAnnotation.swift; sourceTree = "<group>"; };
626AF6DC2F699081008BCA08 /* MapViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapViewController.swift; sourceTree = "<group>"; };
626AF6DD2F699081008BCA08 /* MapViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MapViewController.xib; sourceTree = "<group>"; };
626DC8002F6ACA3B00CFC8C2 /* CarouselItemModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarouselItemModel.swift; sourceTree = "<group>"; };
62A0A6D12F67FEDC00508534 /* MyCouponsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyCouponsViewController.swift; sourceTree = "<group>"; };
62A0A6D22F67FEDC00508534 /* MyCouponsViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MyCouponsViewController.xib; sourceTree = "<group>"; };
62A0A6D62F680C6A00508534 /* MyCouponsHeaderTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyCouponsHeaderTableViewCell.swift; sourceTree = "<group>"; };
...
...
@@ -212,6 +214,7 @@
1E089DF42DF87C39007459F1 /* Response.swift */,
1E089DF52DF87C39007459F1 /* SectionModel.swift */,
1E116F6A2DE86CAD009AE791 /* Models.swift */,
626DC8002F6ACA3B00CFC8C2 /* CarouselItemModel.swift */,
);
path = models;
sourceTree = "<group>";
...
...
@@ -733,6 +736,7 @@
1E089E0A2DF87D16007459F1 /* EventDispatcher.swift in Sources */,
1E116F692DE845B1009AE791 /* ProfileFilterCollectionViewCell.swift in Sources */,
1E0E72472E0C3B1200BC926F /* DatabaseManager.swift in Sources */,
626DC8012F6ACA3B00CFC8C2 /* CarouselItemModel.swift in Sources */,
1EDBAF0D2DE8441000911E79 /* ProfileQuestionnaireTableViewCell.swift in Sources */,
1E64E1842DE48E0600543217 /* MyRewardsOfferCollectionViewCell.swift in Sources */,
E6A77955282933E70045BBA8 /* ViewControllerExtensions.swift in Sources */,
...
...
SwiftWarplyFramework/SwiftWarplyFramework.xcodeproj/xcuserdata/manoschorianopoulos.xcuserdatad/xcschemes/xcschememanagement.plist
View file @
3f967f2
...
...
@@ -7,7 +7,7 @@
<key>
SwiftWarplyFramework.xcscheme_^#shared#^_
</key>
<dict>
<key>
orderHint
</key>
<integer>
0
</integer>
<integer>
1
</integer>
</dict>
</dict>
</dict>
...
...
SwiftWarplyFramework/SwiftWarplyFramework.xcworkspace/xcuserdata/manoschorianopoulos.xcuserdatad/UserInterfaceState.xcuserstate
View file @
3f967f2
No preview for this file type
SwiftWarplyFramework/SwiftWarplyFramework/Core/WarplySDK.swift
View file @
3f967f2
...
...
@@ -4335,3 +4335,66 @@ public final class WarplySDK {
setCarouselList
(
carouselArray
)
}
}
// MARK: - Carousel Content
extension
WarplySDK
{
/// Get carousel content
/// - Parameters:
/// - completion: Completion handler with array of CarouselItemModel
/// - failureCallback: Failure callback with error code
public
func
getCarouselContent
(
completion
:
@escaping
([
CarouselItemModel
]?)
->
Void
,
failureCallback
:
@escaping
(
Int
)
->
Void
)
{
Task
{
do
{
let
endpoint
=
Endpoint
.
getCarouselContent
let
response
=
try
await
networkService
.
requestRaw
(
endpoint
)
await
MainActor
.
run
{
if
response
[
"status"
]
as?
Int
==
1
{
let
dynatraceEvent
=
LoyaltySDKDynatraceEventModel
()
dynatraceEvent
.
_eventName
=
"custom_success_get_carousel_content_loyalty"
dynatraceEvent
.
_parameters
=
nil
self
.
postFrameworkEvent
(
"dynatrace"
,
sender
:
dynatraceEvent
)
var
items
:
[
CarouselItemModel
]
=
[]
if
let
resultArray
=
response
[
"result"
]
as?
[[
String
:
Any
]]
{
for
itemDict
in
resultArray
{
items
.
append
(
CarouselItemModel
(
dictionary
:
itemDict
))
}
}
print
(
"✅ [getCarouselContent] Parsed
\(
items
.
count
)
carousel items"
)
completion
(
items
)
}
else
{
let
dynatraceEvent
=
LoyaltySDKDynatraceEventModel
()
dynatraceEvent
.
_eventName
=
"custom_error_get_carousel_content_loyalty"
dynatraceEvent
.
_parameters
=
nil
self
.
postFrameworkEvent
(
"dynatrace"
,
sender
:
dynatraceEvent
)
failureCallback
(
-
1
)
}
}
}
catch
{
await
MainActor
.
run
{
self
.
handleError
(
error
,
context
:
"getCarouselContent"
,
endpoint
:
"getCarouselContent"
,
failureCallback
:
failureCallback
)
}
}
}
}
/// Get carousel content (async/await variant)
/// - Returns: Array of CarouselItemModel
/// - Throws: WarplyError if the request fails
public
func
getCarouselContent
()
async
throws
->
[
CarouselItemModel
]
{
return
try
await
withCheckedThrowingContinuation
{
continuation
in
getCarouselContent
(
completion
:
{
result
in
if
let
result
=
result
{
continuation
.
resume
(
returning
:
result
)
}
else
{
continuation
.
resume
(
throwing
:
WarplyError
.
networkError
)
}
},
failureCallback
:
{
errorCode
in
continuation
.
resume
(
throwing
:
WarplyError
.
unknownError
(
errorCode
))
})
}
}
}
...
...
SwiftWarplyFramework/SwiftWarplyFramework/Network/Endpoints.swift
View file @
3f967f2
...
...
@@ -78,6 +78,9 @@ public enum Endpoint {
// Articles
case
getArticles
(
language
:
String
,
categories
:
[
String
]?)
// Carousel Content
case
getCarouselContent
// Card Management
case
addCard
(
cardNumber
:
String
,
cardIssuer
:
String
,
cardHolder
:
String
,
expirationMonth
:
String
,
expirationYear
:
String
)
case
getCards
...
...
@@ -139,7 +142,7 @@ public enum Endpoint {
return
"/api/mobile/v2/{appUUID}/context/"
// Authenticated Context endpoints - /oauth/{appUUID}/context
case
.
getCampaignsPersonalized
,
.
getCoupons
,
.
getMarketPassDetails
,
.
getProfile
,
.
addCard
,
.
getCards
,
.
deleteCard
,
.
getTransactionHistory
,
.
getPointsHistory
,
.
validateCoupon
,
.
redeemCoupon
,
.
retrieveCoupon
:
case
.
getCampaignsPersonalized
,
.
getCoupons
,
.
getMarketPassDetails
,
.
getProfile
,
.
addCard
,
.
getCards
,
.
deleteCard
,
.
getTransactionHistory
,
.
getPointsHistory
,
.
validateCoupon
,
.
redeemCoupon
,
.
retrieveCoupon
,
.
getCarouselContent
:
return
"/oauth/{appUUID}/context"
// Session endpoints - /api/session/{sessionUuid}
...
...
@@ -168,7 +171,7 @@ public enum Endpoint {
switch
self
{
case
.
register
,
.
changePassword
,
.
resetPassword
,
.
requestOtp
,
.
verifyTicket
,
.
refreshToken
,
.
logout
,
.
getCampaigns
,
.
getCampaignsPersonalized
,
.
getCoupons
,
.
getCouponSets
,
.
getAvailableCoupons
,
.
getMarketPassDetails
,
.
getProfile
,
.
addCard
,
.
getCards
,
.
deleteCard
,
.
getTransactionHistory
,
.
getPointsHistory
,
.
validateCoupon
,
.
redeemCoupon
,
.
retrieveCoupon
,
.
getMerchants
,
.
getMerchantCategories
,
.
getStores
,
.
getArticles
,
.
sendEvent
,
.
sendDeviceInfo
,
.
getCosmoteUser
,
.
deiLogin
:
.
getMarketPassDetails
,
.
getProfile
,
.
addCard
,
.
getCards
,
.
deleteCard
,
.
getTransactionHistory
,
.
getPointsHistory
,
.
validateCoupon
,
.
redeemCoupon
,
.
retrieveCoupon
,
.
getMerchants
,
.
getMerchantCategories
,
.
getStores
,
.
getArticles
,
.
sendEvent
,
.
sendDeviceInfo
,
.
getCosmoteUser
,
.
deiLogin
,
.
getCarouselContent
:
return
.
POST
case
.
getSingleCampaign
,
.
getNetworkStatus
:
return
.
GET
...
...
@@ -438,6 +441,14 @@ public enum Endpoint {
"content"
:
contentParams
]
// Carousel Content - using content structure with get_carousel action
case
.
getCarouselContent
:
return
[
"content"
:
[
"action"
:
"get_carousel"
]
]
// Analytics endpoints - events structure
case
.
sendEvent
(
let
eventName
,
let
priority
):
return
[
...
...
@@ -494,7 +505,7 @@ public enum Endpoint {
return
.
standardContext
// Authenticated Context - /oauth/{appUUID}/context
case
.
getCampaignsPersonalized
,
.
getCoupons
,
.
getMarketPassDetails
,
.
getProfile
,
.
addCard
,
.
getCards
,
.
deleteCard
,
.
getTransactionHistory
,
.
getPointsHistory
,
.
validateCoupon
,
.
redeemCoupon
,
.
retrieveCoupon
:
case
.
getCampaignsPersonalized
,
.
getCoupons
,
.
getMarketPassDetails
,
.
getProfile
,
.
addCard
,
.
getCards
,
.
deleteCard
,
.
getTransactionHistory
,
.
getPointsHistory
,
.
validateCoupon
,
.
redeemCoupon
,
.
retrieveCoupon
,
.
getCarouselContent
:
return
.
authenticatedContext
// Authentication - /oauth/{appUUID}/login, /oauth/{appUUID}/token
...
...
@@ -536,7 +547,7 @@ public enum Endpoint {
return
.
standard
// Bearer Token Authentication (loyalty headers + Authorization: Bearer)
case
.
changePassword
,
.
getCampaignsPersonalized
,
.
getCoupons
,
.
getMarketPassDetails
,
.
getProfile
,
.
addCard
,
.
getCards
,
.
deleteCard
,
.
getTransactionHistory
,
.
getPointsHistory
,
.
validateCoupon
,
.
redeemCoupon
,
.
retrieveCoupon
:
case
.
changePassword
,
.
getCampaignsPersonalized
,
.
getCoupons
,
.
getMarketPassDetails
,
.
getProfile
,
.
addCard
,
.
getCards
,
.
deleteCard
,
.
getTransactionHistory
,
.
getPointsHistory
,
.
validateCoupon
,
.
redeemCoupon
,
.
retrieveCoupon
,
.
getCarouselContent
:
return
.
bearerToken
// Basic Authentication (loyalty headers + Authorization: Basic)
...
...
SwiftWarplyFramework/SwiftWarplyFramework/cells/MyRewardsBannerOfferCollectionViewCell/MyRewardsBannerOfferCollectionViewCell.swift
View file @
3f967f2
...
...
@@ -38,13 +38,17 @@ public class MyRewardsBannerOfferCollectionViewCell: UICollectionViewCell {
contentView
.
layer
.
masksToBounds
=
true
}
func
configureCell
(
data
:
CampaignItemModel
)
{
// Use campaign's banner image - no hardcoded defaults
self
.
postImageURL
=
data
.
_banner_img_mobile
??
""
}
func
configureCell
(
data
:
ArticleModel
)
{
// Use article's preview image - same visual treatment as campaigns
self
.
postImageURL
=
data
.
_img_preview
.
isEmpty
?
nil
:
data
.
_img_preview
// func configureCell(data: CampaignItemModel) {
// // Use campaign's banner image - no hardcoded defaults
// self.postImageURL = data._banner_img_mobile ?? ""
// }
// func configureCell(data: ArticleModel) {
// // Use article's preview image - same visual treatment as campaigns
// self.postImageURL = data._img_preview.isEmpty ? nil : data._img_preview
// }
func
configureCell
(
data
:
CarouselItemModel
)
{
self
.
postImageURL
=
data
.
_app_img
}
}
...
...
SwiftWarplyFramework/SwiftWarplyFramework/cells/MyRewardsBannerOffersScrollTableViewCell/MyRewardsBannerOffersScrollTableViewCell.swift
View file @
3f967f2
...
...
@@ -10,6 +10,7 @@ import UIKit
protocol
MyRewardsBannerOffersScrollTableViewCellDelegate
:
AnyObject
{
func
didSelectBannerOffer
(
_
index
:
Int
)
func
didSelectBannerArticle
(
_
index
:
Int
)
func
didSelectBannerCarouselItem
(
_
index
:
Int
)
}
@objc(MyRewardsBannerOffersScrollTableViewCell)
...
...
@@ -96,7 +97,7 @@ extension MyRewardsBannerOffersScrollTableViewCell: UICollectionViewDataSource,
public
func
collectionView
(
_
collectionView
:
UICollectionView
,
cellForItemAt
indexPath
:
IndexPath
)
->
UICollectionViewCell
{
let
cell
=
collectionView
.
dequeueReusableCell
(
withReuseIdentifier
:
"MyRewardsBannerOfferCollectionViewCell"
,
for
:
indexPath
)
as!
MyRewardsBannerOfferCollectionViewCell
// Handle
both CampaignItemModel and Article
Model
// Handle
CarouselItem
Model
guard
let
data
=
self
.
data
,
let
items
=
data
.
items
,
indexPath
.
row
<
items
.
count
else
{
...
...
@@ -105,10 +106,13 @@ extension MyRewardsBannerOffersScrollTableViewCell: UICollectionViewDataSource,
let
item
=
items
[
indexPath
.
row
]
if
let
campaign
=
item
as?
CampaignItemModel
{
cell
.
configureCell
(
data
:
campaign
)
}
else
if
let
article
=
item
as?
ArticleModel
{
cell
.
configureCell
(
data
:
article
)
// if let campaign = item as? CampaignItemModel {
// cell.configureCell(data: campaign)
// } else if let article = item as? ArticleModel {
// cell.configureCell(data: article)
// }
if
let
carouselItem
=
item
as?
CarouselItemModel
{
cell
.
configureCell
(
data
:
carouselItem
)
}
return
cell
...
...
@@ -124,10 +128,13 @@ extension MyRewardsBannerOffersScrollTableViewCell: UICollectionViewDataSource,
let
item
=
items
[
indexPath
.
row
]
if
item
is
CampaignItemModel
{
delegate
?
.
didSelectBannerOffer
(
indexPath
.
row
)
}
else
if
item
is
ArticleModel
{
delegate
?
.
didSelectBannerArticle
(
indexPath
.
row
)
// if item is CampaignItemModel {
// delegate?.didSelectBannerOffer(indexPath.row)
// } else if item is ArticleModel {
// delegate?.didSelectBannerArticle(indexPath.row)
// }
if
item
is
CarouselItemModel
{
delegate
?
.
didSelectBannerCarouselItem
(
indexPath
.
row
)
}
}
...
...
SwiftWarplyFramework/SwiftWarplyFramework/models/CarouselItemModel.swift
0 → 100644
View file @
3f967f2
//
// CarouselItemModel.swift
// SwiftWarplyFramework
//
// Created by Manos Chorianopoulos on 18/3/26.
//
import
Foundation
public
class
CarouselItemModel
:
NSObject
{
private
var
uuid
:
String
?
private
var
name
:
String
?
private
var
entity
:
String
?
private
var
app_img
:
String
?
private
var
app_url
:
String
?
private
var
url
:
String
?
private
var
web_img
:
String
?
private
var
web_img_responsive
:
String
?
public
override
init
()
{
super
.
init
()
}
public
init
(
dictionary
:
[
String
:
Any
])
{
self
.
uuid
=
dictionary
[
"uuid"
]
as?
String
??
""
self
.
name
=
dictionary
[
"name"
]
as?
String
??
""
self
.
entity
=
dictionary
[
"entity"
]
as?
String
??
""
self
.
app_img
=
dictionary
[
"app_img"
]
as?
String
self
.
app_url
=
dictionary
[
"app_url"
]
as?
String
self
.
url
=
dictionary
[
"url"
]
as?
String
self
.
web_img
=
dictionary
[
"web_img"
]
as?
String
self
.
web_img_responsive
=
dictionary
[
"web_img_responsive"
]
as?
String
}
public
var
_uuid
:
String
{
get
{
return
self
.
uuid
??
""
}
}
public
var
_name
:
String
{
get
{
return
self
.
name
??
""
}
}
public
var
_entity
:
String
{
get
{
return
self
.
entity
??
""
}
}
public
var
_app_img
:
String
?
{
get
{
return
self
.
app_img
}
}
public
var
_app_url
:
String
?
{
get
{
return
self
.
app_url
}
}
public
var
_url
:
String
?
{
get
{
return
self
.
url
}
}
public
var
_web_img
:
String
?
{
get
{
return
self
.
web_img
}
}
public
var
_web_img_responsive
:
String
?
{
get
{
return
self
.
web_img_responsive
}
}
}
SwiftWarplyFramework/SwiftWarplyFramework/screens/MyRewardsViewController/MyRewardsViewController.swift
View file @
3f967f2
...
...
@@ -42,6 +42,9 @@ import UIKit
// Dynamic sections array - populated by API calls
var
sections
:
[
SectionModel
]
=
[]
// carouselItems data for banners
var
carouselItems
:
[
CarouselItemModel
]
=
[]
// Campaign data for banners
var
bannerCampaigns
:
[
CampaignItemModel
]
=
[]
...
...
@@ -87,7 +90,8 @@ import UIKit
// Load data
loadProfile
()
// Load Profile
loadCampaigns
()
// Load campaigns
loadCarouselContent
()
// loadCampaigns() // Load campaigns
loadCouponSets
()
// Load couponsets
loadCoupons
()
...
...
@@ -160,6 +164,23 @@ import UIKit
self
.
navigationController
?
.
setNavigationBarHidden
(
false
,
animated
:
animated
)
}
// MARK: - CarouselContent Loading
private
func
loadCarouselContent
()
{
// Load CarouselContent from WarplySDK
WarplySDK
.
shared
.
getCarouselContent
{
[
weak
self
]
carouselContent
in
guard
let
self
=
self
,
let
carouselContent
=
carouselContent
else
{
return
}
self
.
carouselItems
=
carouselContent
self
.
createBannerSection
()
print
(
"=== getCarouselContent ✅ [MyRewardsViewController] Loaded
\(
carouselContent
.
count
)
carouselContent"
)
}
failureCallback
:
{
[
weak
self
]
errorCode
in
print
(
"=== getCarouselContent Failed to load carouselContent:
\(
errorCode
)
"
)
}
}
// MARK: - Campaign Loading
private
func
loadCampaigns
()
{
...
...
@@ -220,11 +241,14 @@ import UIKit
// Combine campaigns and articles for banner section
var
bannerItems
:
[
Any
]
=
[]
// Add campaigns first
bannerItems
.
append
(
contentsOf
:
self
.
bannerCampaigns
)
//
//
Add campaigns first
//
bannerItems.append(contentsOf: self.bannerCampaigns)
// Add articles after campaigns
bannerItems
.
append
(
contentsOf
:
self
.
articles
)
// // Add articles after campaigns
// bannerItems.append(contentsOf: self.articles)
// // Add articles after campaigns
bannerItems
.
append
(
contentsOf
:
self
.
carouselItems
)
// Create banner section if we have any items
if
!
bannerItems
.
isEmpty
{
...
...
@@ -779,6 +803,10 @@ extension MyRewardsViewController: MyRewardsBannerOffersScrollTableViewCellDeleg
openArticleViewController
(
with
:
index
)
}
func
didSelectBannerCarouselItem
(
_
index
:
Int
)
{
// TODO: handle carousel item tap
}
// func didTapProfileButton() {
// // Navigate to ProfileViewController
// openProfileViewController()
...
...
Please
register
or
login
to post a comment