Manos Chorianopoulos

MyCouponsViewController part1

Showing 18 changed files with 681 additions and 0 deletions
...@@ -73,6 +73,10 @@ ...@@ -73,6 +73,10 @@
73 1EDD0AC62E0D68B6005E162B /* SQLite in Frameworks */ = {isa = PBXBuildFile; productRef = 1EDD0AC52E0D68B6005E162B /* SQLite */; }; 73 1EDD0AC62E0D68B6005E162B /* SQLite in Frameworks */ = {isa = PBXBuildFile; productRef = 1EDD0AC52E0D68B6005E162B /* SQLite */; };
74 622DA0AE2F51CAEE00308AB8 /* CouponsetViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 622DA0AD2F51CAEE00308AB8 /* CouponsetViewController.xib */; }; 74 622DA0AE2F51CAEE00308AB8 /* CouponsetViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 622DA0AD2F51CAEE00308AB8 /* CouponsetViewController.xib */; };
75 622DA0AF2F51CAEE00308AB8 /* CouponsetViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 622DA0AC2F51CAEE00308AB8 /* CouponsetViewController.swift */; }; 75 622DA0AF2F51CAEE00308AB8 /* CouponsetViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 622DA0AC2F51CAEE00308AB8 /* CouponsetViewController.swift */; };
76 + 62A0A6D32F67FEDC00508534 /* MyCouponsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62A0A6D12F67FEDC00508534 /* MyCouponsViewController.swift */; };
77 + 62A0A6D42F67FEDC00508534 /* MyCouponsViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 62A0A6D22F67FEDC00508534 /* MyCouponsViewController.xib */; };
78 + 62A0A6D82F680C6A00508534 /* MyCouponsHeaderTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62A0A6D62F680C6A00508534 /* MyCouponsHeaderTableViewCell.swift */; };
79 + 62A0A6D92F680C6A00508534 /* MyCouponsHeaderTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 62A0A6D72F680C6A00508534 /* MyCouponsHeaderTableViewCell.xib */; };
76 7630AD9A6242D60846D6750C /* Pods_SwiftWarplyFramework.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C0D5F56DD4E5371A50AD2D87 /* Pods_SwiftWarplyFramework.framework */; }; 80 7630AD9A6242D60846D6750C /* Pods_SwiftWarplyFramework.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C0D5F56DD4E5371A50AD2D87 /* Pods_SwiftWarplyFramework.framework */; };
77 A07936762885E9CC00064122 /* UIColorExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A07936752885E9CC00064122 /* UIColorExtensions.swift */; }; 81 A07936762885E9CC00064122 /* UIColorExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A07936752885E9CC00064122 /* UIColorExtensions.swift */; };
78 E6A77853282933340045BBA8 /* SwiftWarplyFramework.docc in Sources */ = {isa = PBXBuildFile; fileRef = E6A77852282933340045BBA8 /* SwiftWarplyFramework.docc */; }; 82 E6A77853282933340045BBA8 /* SwiftWarplyFramework.docc in Sources */ = {isa = PBXBuildFile; fileRef = E6A77852282933340045BBA8 /* SwiftWarplyFramework.docc */; };
...@@ -150,6 +154,10 @@ ...@@ -150,6 +154,10 @@
150 1EDD0ABC2E0D308A005E162B /* XIBLoader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XIBLoader.swift; sourceTree = "<group>"; }; 154 1EDD0ABC2E0D308A005E162B /* XIBLoader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XIBLoader.swift; sourceTree = "<group>"; };
151 622DA0AC2F51CAEE00308AB8 /* CouponsetViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CouponsetViewController.swift; sourceTree = "<group>"; }; 155 622DA0AC2F51CAEE00308AB8 /* CouponsetViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CouponsetViewController.swift; sourceTree = "<group>"; };
152 622DA0AD2F51CAEE00308AB8 /* CouponsetViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = CouponsetViewController.xib; sourceTree = "<group>"; }; 156 622DA0AD2F51CAEE00308AB8 /* CouponsetViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = CouponsetViewController.xib; sourceTree = "<group>"; };
157 + 62A0A6D12F67FEDC00508534 /* MyCouponsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyCouponsViewController.swift; sourceTree = "<group>"; };
158 + 62A0A6D22F67FEDC00508534 /* MyCouponsViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MyCouponsViewController.xib; sourceTree = "<group>"; };
159 + 62A0A6D62F680C6A00508534 /* MyCouponsHeaderTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyCouponsHeaderTableViewCell.swift; sourceTree = "<group>"; };
160 + 62A0A6D72F680C6A00508534 /* MyCouponsHeaderTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MyCouponsHeaderTableViewCell.xib; sourceTree = "<group>"; };
153 A07936752885E9CC00064122 /* UIColorExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIColorExtensions.swift; sourceTree = "<group>"; }; 161 A07936752885E9CC00064122 /* UIColorExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIColorExtensions.swift; sourceTree = "<group>"; };
154 A9B7BE01A4E812DE49866EF8 /* Pods-SwiftWarplyFramework.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwiftWarplyFramework.debug.xcconfig"; path = "Target Support Files/Pods-SwiftWarplyFramework/Pods-SwiftWarplyFramework.debug.xcconfig"; sourceTree = "<group>"; }; 162 A9B7BE01A4E812DE49866EF8 /* Pods-SwiftWarplyFramework.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwiftWarplyFramework.debug.xcconfig"; path = "Target Support Files/Pods-SwiftWarplyFramework/Pods-SwiftWarplyFramework.debug.xcconfig"; sourceTree = "<group>"; };
155 B9EB8A451EF0C5AD75094EEE /* Pods-SwiftWarplyFramework.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwiftWarplyFramework.release.xcconfig"; path = "Target Support Files/Pods-SwiftWarplyFramework/Pods-SwiftWarplyFramework.release.xcconfig"; sourceTree = "<group>"; }; 163 B9EB8A451EF0C5AD75094EEE /* Pods-SwiftWarplyFramework.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwiftWarplyFramework.release.xcconfig"; path = "Target Support Files/Pods-SwiftWarplyFramework/Pods-SwiftWarplyFramework.release.xcconfig"; sourceTree = "<group>"; };
...@@ -328,6 +336,7 @@ ...@@ -328,6 +336,7 @@
328 1E917CD32DDF6472002221D8 /* MyRewardsViewController */, 336 1E917CD32DDF6472002221D8 /* MyRewardsViewController */,
329 1E917CD82DDF687E002221D8 /* CouponViewController */, 337 1E917CD82DDF687E002221D8 /* CouponViewController */,
330 1E917CDD2DDF68D8002221D8 /* ProfileViewController */, 338 1E917CDD2DDF68D8002221D8 /* ProfileViewController */,
339 + 62A0A6D02F67FE8100508534 /* MyCouponsViewController */,
331 ); 340 );
332 path = screens; 341 path = screens;
333 sourceTree = "<group>"; 342 sourceTree = "<group>";
...@@ -335,6 +344,7 @@ ...@@ -335,6 +344,7 @@
335 1EA8E5BC2DDF34FB00CD3418 /* cells */ = { 344 1EA8E5BC2DDF34FB00CD3418 /* cells */ = {
336 isa = PBXGroup; 345 isa = PBXGroup;
337 children = ( 346 children = (
347 + 62A0A6D52F680C1E00508534 /* MyCouponsHeaderTableViewCell */,
338 1EDBAF122DE844C500911E79 /* ProfileFilterCollectionViewCell */, 348 1EDBAF122DE844C500911E79 /* ProfileFilterCollectionViewCell */,
339 1EDBAF012DE8439000911E79 /* ProfileCouponTableViewCell */, 349 1EDBAF012DE8439000911E79 /* ProfileCouponTableViewCell */,
340 1EDBAF002DE842A700911E79 /* ProfileCouponFiltersTableViewCell */, 350 1EDBAF002DE842A700911E79 /* ProfileCouponFiltersTableViewCell */,
...@@ -439,6 +449,24 @@ ...@@ -439,6 +449,24 @@
439 path = CouponsetViewController; 449 path = CouponsetViewController;
440 sourceTree = "<group>"; 450 sourceTree = "<group>";
441 }; 451 };
452 + 62A0A6D02F67FE8100508534 /* MyCouponsViewController */ = {
453 + isa = PBXGroup;
454 + children = (
455 + 62A0A6D12F67FEDC00508534 /* MyCouponsViewController.swift */,
456 + 62A0A6D22F67FEDC00508534 /* MyCouponsViewController.xib */,
457 + );
458 + path = MyCouponsViewController;
459 + sourceTree = "<group>";
460 + };
461 + 62A0A6D52F680C1E00508534 /* MyCouponsHeaderTableViewCell */ = {
462 + isa = PBXGroup;
463 + children = (
464 + 62A0A6D62F680C6A00508534 /* MyCouponsHeaderTableViewCell.swift */,
465 + 62A0A6D72F680C6A00508534 /* MyCouponsHeaderTableViewCell.xib */,
466 + );
467 + path = MyCouponsHeaderTableViewCell;
468 + sourceTree = "<group>";
469 + };
442 98AD36FA62350CEABCD961A7 /* Frameworks */ = { 470 98AD36FA62350CEABCD961A7 /* Frameworks */ = {
443 isa = PBXGroup; 471 isa = PBXGroup;
444 children = ( 472 children = (
...@@ -611,12 +639,14 @@ ...@@ -611,12 +639,14 @@
611 E6A77A38282BC3530045BBA8 /* Media.xcassets in Resources */, 639 E6A77A38282BC3530045BBA8 /* Media.xcassets in Resources */,
612 1E116F682DE845B1009AE791 /* ProfileFilterCollectionViewCell.xib in Resources */, 640 1E116F682DE845B1009AE791 /* ProfileFilterCollectionViewCell.xib in Resources */,
613 1EB4F4252DE09AAC00D934C0 /* MyRewardsBannerOffersScrollTableViewCell.xib in Resources */, 641 1EB4F4252DE09AAC00D934C0 /* MyRewardsBannerOffersScrollTableViewCell.xib in Resources */,
642 + 62A0A6D92F680C6A00508534 /* MyCouponsHeaderTableViewCell.xib in Resources */,
614 1EA8E5C02DDF427A00CD3418 /* PingLCG-Bold.otf in Resources */, 643 1EA8E5C02DDF427A00CD3418 /* PingLCG-Bold.otf in Resources */,
615 622DA0AE2F51CAEE00308AB8 /* CouponsetViewController.xib in Resources */, 644 622DA0AE2F51CAEE00308AB8 /* CouponsetViewController.xib in Resources */,
616 1E64E1832DE48E0600543217 /* MyRewardsOfferCollectionViewCell.xib in Resources */, 645 1E64E1832DE48E0600543217 /* MyRewardsOfferCollectionViewCell.xib in Resources */,
617 1EA8E5C12DDF427A00CD3418 /* PingLCG-Light.otf in Resources */, 646 1EA8E5C12DDF427A00CD3418 /* PingLCG-Light.otf in Resources */,
618 1EA8E5C22DDF427A00CD3418 /* PingLCG-Regular.otf in Resources */, 647 1EA8E5C22DDF427A00CD3418 /* PingLCG-Regular.otf in Resources */,
619 1EB4F42B2DE0A0AF00D934C0 /* MyRewardsOffersScrollTableViewCell.xib in Resources */, 648 1EB4F42B2DE0A0AF00D934C0 /* MyRewardsOffersScrollTableViewCell.xib in Resources */,
649 + 62A0A6D42F67FEDC00508534 /* MyCouponsViewController.xib in Resources */,
620 1E66E4972E30F9F200BCEF9D /* MyRewardsProfileInfoTableViewCell.xib in Resources */, 650 1E66E4972E30F9F200BCEF9D /* MyRewardsProfileInfoTableViewCell.xib in Resources */,
621 1EDBAF102DE8443B00911E79 /* ProfileHeaderTableViewCell.xib in Resources */, 651 1EDBAF102DE8443B00911E79 /* ProfileHeaderTableViewCell.xib in Resources */,
622 1E917CDB2DDF68C7002221D8 /* CouponViewController.xib in Resources */, 652 1E917CDB2DDF68C7002221D8 /* CouponViewController.xib in Resources */,
...@@ -678,6 +708,7 @@ ...@@ -678,6 +708,7 @@
678 622DA0AF2F51CAEE00308AB8 /* CouponsetViewController.swift in Sources */, 708 622DA0AF2F51CAEE00308AB8 /* CouponsetViewController.swift in Sources */,
679 1E089DFE2DF87C39007459F1 /* Coupon.swift in Sources */, 709 1E089DFE2DF87C39007459F1 /* Coupon.swift in Sources */,
680 1E089DFF2DF87C39007459F1 /* OfferModel.swift in Sources */, 710 1E089DFF2DF87C39007459F1 /* OfferModel.swift in Sources */,
711 + 62A0A6D82F680C6A00508534 /* MyCouponsHeaderTableViewCell.swift in Sources */,
681 1ED41E4C2DE0C24D00836ABA /* MyRewardsBannerOfferCollectionViewCell.swift in Sources */, 712 1ED41E4C2DE0C24D00836ABA /* MyRewardsBannerOfferCollectionViewCell.swift in Sources */,
682 E6A778E6282933E60045BBA8 /* MyEmptyClass.swift in Sources */, 713 E6A778E6282933E60045BBA8 /* MyEmptyClass.swift in Sources */,
683 1E917CE12DDF6909002221D8 /* ProfileViewController.swift in Sources */, 714 1E917CE12DDF6909002221D8 /* ProfileViewController.swift in Sources */,
...@@ -689,6 +720,7 @@ ...@@ -689,6 +720,7 @@
689 E6A77955282933E70045BBA8 /* ViewControllerExtensions.swift in Sources */, 720 E6A77955282933E70045BBA8 /* ViewControllerExtensions.swift in Sources */,
690 A07936762885E9CC00064122 /* UIColorExtensions.swift in Sources */, 721 A07936762885E9CC00064122 /* UIColorExtensions.swift in Sources */,
691 1EB4F42C2DE0A0AF00D934C0 /* MyRewardsOffersScrollTableViewCell.swift in Sources */, 722 1EB4F42C2DE0A0AF00D934C0 /* MyRewardsOffersScrollTableViewCell.swift in Sources */,
723 + 62A0A6D32F67FEDC00508534 /* MyCouponsViewController.swift in Sources */,
692 1E089E022DF87CCF007459F1 /* WarplySDK.swift in Sources */, 724 1E089E022DF87CCF007459F1 /* WarplySDK.swift in Sources */,
693 1E0E723B2E0C3AE400BC926F /* DatabaseConfiguration.swift in Sources */, 725 1E0E723B2E0C3AE400BC926F /* DatabaseConfiguration.swift in Sources */,
694 1E0E723C2E0C3AE400BC926F /* WarplyConfiguration.swift in Sources */, 726 1E0E723C2E0C3AE400BC926F /* WarplyConfiguration.swift in Sources */,
......
1 +{
2 + "images" : [
3 + {
4 + "filename" : "ic_forward.png",
5 + "idiom" : "universal",
6 + "scale" : "1x"
7 + },
8 + {
9 + "filename" : "ic_forward 1.png",
10 + "idiom" : "universal",
11 + "scale" : "2x"
12 + },
13 + {
14 + "filename" : "ic_forward 2.png",
15 + "idiom" : "universal",
16 + "scale" : "3x"
17 + }
18 + ],
19 + "info" : {
20 + "author" : "xcode",
21 + "version" : 1
22 + }
23 +}
1 +{
2 + "images" : [
3 + {
4 + "filename" : "search.png",
5 + "idiom" : "universal",
6 + "scale" : "1x"
7 + },
8 + {
9 + "filename" : "search 1.png",
10 + "idiom" : "universal",
11 + "scale" : "2x"
12 + },
13 + {
14 + "filename" : "search 2.png",
15 + "idiom" : "universal",
16 + "scale" : "3x"
17 + }
18 + ],
19 + "info" : {
20 + "author" : "xcode",
21 + "version" : 1
22 + }
23 +}
1 +{
2 + "images" : [
3 + {
4 + "filename" : "search_circle.png",
5 + "idiom" : "universal",
6 + "scale" : "1x"
7 + },
8 + {
9 + "filename" : "search_circle 1.png",
10 + "idiom" : "universal",
11 + "scale" : "2x"
12 + },
13 + {
14 + "filename" : "search_circle 2.png",
15 + "idiom" : "universal",
16 + "scale" : "3x"
17 + }
18 + ],
19 + "info" : {
20 + "author" : "xcode",
21 + "version" : 1
22 + }
23 +}
1 +//
2 +// MyCouponsHeaderTableViewCell.swift
3 +// SwiftWarplyFramework
4 +//
5 +// Created by Manos Chorianopoulos on 16/3/26.
6 +//
7 +
8 +import UIKit
9 +
10 +// protocol MyCouponsHeaderTableViewCellDelegate: AnyObject {
11 +// func didTapSearchButton()
12 +// }
13 +
14 +@objc(MyCouponsHeaderTableViewCell)
15 +public class MyCouponsHeaderTableViewCell: UITableViewCell {
16 +
17 + // MARK: - IBOutlets
18 + @IBOutlet weak var titleLabel: UILabel!
19 + @IBOutlet weak var searchButton: UIButton!
20 +
21 + // MARK: - Delegate
22 +
23 + // weak var delegate: MyCouponsHeaderTableViewCellDelegate?
24 +
25 + // MARK: - Lifecycle
26 +
27 + public override func awakeFromNib() {
28 + super.awakeFromNib()
29 +
30 + selectionStyle = .none
31 +
32 + // Title
33 + titleLabel.font = UIFont(name: "PingLCG-Bold", size: 26)
34 + ?? UIFont.boldSystemFont(ofSize: 26)
35 + titleLabel.textColor = UIColor(rgb: 0x1D2023)
36 + titleLabel.text = "My Coupons"
37 +
38 + // Gear button: render image as-is (no tint) so the gray circle style is preserved
39 + let gearImage = UIImage(named: "search_circle", in: Bundle.frameworkResourceBundle, compatibleWith: nil)?
40 + .withRenderingMode(.alwaysOriginal)
41 + searchButton.setImage(gearImage, for: .normal)
42 + searchButton.setTitle("", for: .normal)
43 + // searchButton.addTarget(self, action: #selector(searchButtonTapped), for: .touchUpInside)
44 + }
45 +
46 + public override func setSelected(_ selected: Bool, animated: Bool) {
47 + super.setSelected(selected, animated: animated)
48 + }
49 +
50 + // MARK: - Actions
51 +
52 + // @objc private func searchButtonTapped() {
53 + // delegate?.didTapSearchButton()
54 + // }
55 +}
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="24506" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
3 + <device id="retina6_12" orientation="portrait" appearance="light"/>
4 + <dependencies>
5 + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="24504"/>
6 + <capability name="Safe area layout guides" minToolsVersion="9.0"/>
7 + <capability name="System colors in document resources" minToolsVersion="11.0"/>
8 + <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
9 + </dependencies>
10 + <objects>
11 + <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
12 + <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
13 + <tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="KGk-i7-Jjw" customClass="MyCouponsHeaderTableViewCell" customModule="SwiftWarplyFramework" customModuleProvider="target">
14 + <rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
15 + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
16 + <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM">
17 + <rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
18 + <autoresizingMask key="autoresizingMask"/>
19 + <subviews>
20 + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="9zr-3O-Ndy" userLabel="ParentView">
21 + <rect key="frame" x="0.0" y="0.0" width="320" height="30"/>
22 + <subviews>
23 + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="My Coupons" textAlignment="natural" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="QuH-xv-rPx" userLabel="TitleLabel">
24 + <rect key="frame" x="18" y="-0.66666666666666607" width="156.33333333333334" height="31.333333333333329"/>
25 + <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
26 + <fontDescription key="fontDescription" name="HelveticaNeue-Bold" family="Helvetica Neue" pointSize="26"/>
27 + <color key="textColor" red="0.067000000000000004" green="0.067000000000000004" blue="0.067000000000000004" alpha="1" colorSpace="calibratedRGB"/>
28 + <nil key="highlightedColor"/>
29 + </label>
30 + <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="NOc-fo-goN" userLabel="SearchButton">
31 + <rect key="frame" x="254" y="0.0" width="48" height="30"/>
32 + <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
33 + <constraints>
34 + <constraint firstAttribute="width" constant="48" id="Ubc-A7-ncs"/>
35 + <constraint firstAttribute="height" constant="48" id="boQ-lu-bZd"/>
36 + </constraints>
37 + <state key="normal" title=""/>
38 + </button>
39 + </subviews>
40 + <color key="backgroundColor" systemColor="systemBackgroundColor"/>
41 + <constraints>
42 + <constraint firstItem="QuH-xv-rPx" firstAttribute="centerY" secondItem="NOc-fo-goN" secondAttribute="centerY" id="7Xg-4c-pen"/>
43 + <constraint firstItem="NOc-fo-goN" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="QuH-xv-rPx" secondAttribute="trailing" constant="8" id="Bd4-gD-OFp"/>
44 + <constraint firstItem="NOc-fo-goN" firstAttribute="top" secondItem="9zr-3O-Ndy" secondAttribute="top" id="G0c-Iw-ghG"/>
45 + <constraint firstAttribute="bottom" secondItem="NOc-fo-goN" secondAttribute="bottom" id="gG3-2v-iwZ"/>
46 + <constraint firstAttribute="trailing" secondItem="NOc-fo-goN" secondAttribute="trailing" constant="18" id="o71-Y7-vdQ"/>
47 + <constraint firstItem="QuH-xv-rPx" firstAttribute="leading" secondItem="9zr-3O-Ndy" secondAttribute="leading" constant="18" id="pLn-uL-UNA"/>
48 + </constraints>
49 + </view>
50 + </subviews>
51 + <constraints>
52 + <constraint firstAttribute="bottom" secondItem="9zr-3O-Ndy" secondAttribute="bottom" id="Icc-z0-HGG"/>
53 + <constraint firstAttribute="trailing" secondItem="9zr-3O-Ndy" secondAttribute="trailing" id="Inc-8d-l15"/>
54 + <constraint firstItem="9zr-3O-Ndy" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="top" id="UT5-S3-Caq"/>
55 + <constraint firstItem="9zr-3O-Ndy" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" id="xZK-RL-O9W"/>
56 + </constraints>
57 + </tableViewCellContentView>
58 + <viewLayoutGuide key="safeArea" id="njF-e1-oar"/>
59 + <connections>
60 + <outlet property="searchButton" destination="NOc-fo-goN" id="vyT-JX-Kgo"/>
61 + <outlet property="titleLabel" destination="QuH-xv-rPx" id="q9e-Nt-mZk"/>
62 + </connections>
63 + <point key="canvasLocation" x="141" y="154"/>
64 + </tableViewCell>
65 + </objects>
66 + <resources>
67 + <systemColor name="systemBackgroundColor">
68 + <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
69 + </systemColor>
70 + </resources>
71 +</document>
1 +//
2 +// MyCouponsViewController.swift
3 +// SwiftWarplyFramework
4 +//
5 +// Created by Manos Chorianopoulos on 16/3/26.
6 +//
7 +
8 +import UIKit
9 +
10 +@objc public class MyCouponsViewController: UIViewController {
11 + @IBOutlet weak var tableView: UITableView!
12 +
13 + // MARK: - Initializers
14 + public convenience init() {
15 + self.init(nibName: "MyCouponsViewController", bundle: Bundle.frameworkBundle)
16 + }
17 +
18 + public override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
19 + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
20 + }
21 +
22 + required init?(coder: NSCoder) {
23 + super.init(coder: coder)
24 + }
25 +
26 + // MARK: - Dynamic Data
27 + var allCoupons: [CouponItemModel] = []
28 +
29 + // MARK: - Loading State
30 + private var isLoading: Bool = true
31 + private var loadingIndicator: UIActivityIndicatorView?
32 +
33 + let couponFilters: [CouponFilterModel] = [
34 + CouponFilterModel(title: "Ενεργά"),
35 + CouponFilterModel(title: "Αγαπημένα"),
36 + CouponFilterModel(title: "Εξαργυρωμένα")
37 + ]
38 +
39 + var couponFilterSelected: CouponFilterModel = CouponFilterModel(title: "Ενεργά")
40 +
41 + var forYouOffersSection: SectionModel?
42 + var activeOffersSection: SectionModel?
43 + var favoriteOffersSection: SectionModel?
44 + var redeemedOffersSection: SectionModel?
45 + var filteredOffersSection: SectionModel?
46 +
47 + public override func viewDidLoad() {
48 + super.viewDidLoad()
49 +
50 + // Show navigation bar for this screen (with back button)
51 + self.navigationController?.setNavigationBarHidden(false, animated: false)
52 + setBackButton()
53 + setNavigationTitle("Το προφίλ μου")
54 +
55 + // UPDATED: Safe XIB registration with error handling
56 + registerTableViewCells()
57 +
58 + // Set up table view
59 + tableView.delegate = self
60 + tableView.dataSource = self
61 + tableView.separatorStyle = .none
62 + tableView.estimatedRowHeight = 200
63 + tableView.rowHeight = UITableView.automaticDimension
64 +
65 + // Set up loading indicator
66 + setupLoadingIndicator()
67 +
68 + // Fetch coupons from API
69 + fetchCoupons()
70 + }
71 +
72 + // NEW: Safe XIB registration method
73 + private func registerTableViewCells() {
74 + let cellConfigs = [
75 + ("MyCouponsHeaderTableViewCell", "MyCouponsHeaderTableViewCell"),
76 + ("ProfileQuestionnaireTableViewCell", "ProfileQuestionnaireTableViewCell"),
77 + ("MyRewardsOffersScrollTableViewCell", "MyRewardsOffersScrollTableViewCell"),
78 + ("ProfileCouponFiltersTableViewCell", "ProfileCouponFiltersTableViewCell"),
79 + ("ProfileCouponTableViewCell", "ProfileCouponTableViewCell")
80 + ]
81 +
82 + for (nibName, identifier) in cellConfigs {
83 + XIBLoader.registerTableViewCell(
84 + tableView,
85 + cellClass: UITableViewCell.self,
86 + nibName: nibName,
87 + identifier: identifier
88 + )
89 + }
90 +
91 + }
92 +
93 + // MARK: - Loading Indicator
94 +
95 + private func setupLoadingIndicator() {
96 + let indicator = UIActivityIndicatorView(style: .large)
97 + indicator.color = UIColor(rgb: 0x000F1E)
98 + indicator.translatesAutoresizingMaskIntoConstraints = false
99 + indicator.hidesWhenStopped = true
100 + view.addSubview(indicator)
101 +
102 + NSLayoutConstraint.activate([
103 + indicator.centerXAnchor.constraint(equalTo: view.centerXAnchor),
104 + indicator.centerYAnchor.constraint(equalTo: view.centerYAnchor)
105 + ])
106 +
107 + self.loadingIndicator = indicator
108 + }
109 +
110 + private func showLoading() {
111 + isLoading = true
112 + loadingIndicator?.startAnimating()
113 + tableView.alpha = 0.3
114 + tableView.isUserInteractionEnabled = false
115 + }
116 +
117 + private func hideLoading() {
118 + isLoading = false
119 + loadingIndicator?.stopAnimating()
120 + tableView.alpha = 1.0
121 + tableView.isUserInteractionEnabled = true
122 + }
123 +
124 + // MARK: - Data Fetching
125 +
126 + private func fetchCoupons() {
127 + showLoading()
128 +
129 + // Initialize sections with empty data first (so table view can render skeleton)
130 + initializeSections()
131 +
132 + WarplySDK.shared.getCouponsUniversal({ [weak self] couponsData in
133 + guard let self = self else { return }
134 +
135 + if let coupons = couponsData {
136 + self.allCoupons = coupons
137 + print("✅ [MyCouponsVC] Fetched \(coupons.count) coupons")
138 +
139 + // Debug: Print coupon statuses
140 + let activeCount = coupons.filter { $0.status == 1 }.count
141 + let redeemedCount = coupons.filter { $0.status == 0 }.count
142 + let expiredCount = coupons.filter { $0.status == -1 }.count
143 + print(" Active: \(activeCount), Redeemed: \(redeemedCount), Expired: \(expiredCount)")
144 + } else {
145 + self.allCoupons = []
146 + print("⚠️ [MyCouponsVC] No coupons received")
147 + }
148 +
149 + self.initializeSections()
150 + self.hideLoading()
151 + }, failureCallback: { [weak self] errorCode in
152 + guard let self = self else { return }
153 +
154 + print("❌ [MyCouponsVC] Failed to fetch coupons, error: \(errorCode)")
155 + self.allCoupons = []
156 + self.initializeSections()
157 + self.hideLoading()
158 + })
159 + }
160 +
161 + // MARK: - Section Initialization
162 +
163 + func initializeSections() {
164 + // Προτάσεις για εσένα — empty for now
165 + let forYouOffers: [CouponItemModel] = []
166 + forYouOffersSection = SectionModel(
167 + sectionType: .myRewardsHorizontalCouponsets,
168 + title: "Προτάσεις για εσένα",
169 + items: forYouOffers,
170 + itemType: .coupons
171 + )
172 +
173 + // Active Coupons — status == 1
174 + let activeCoupons = allCoupons.filter { $0.status == 1 }
175 + activeOffersSection = SectionModel(
176 + sectionType: .profileCoupon,
177 + title: "Ενεργά",
178 + items: activeCoupons,
179 + itemType: .coupons
180 + )
181 +
182 + // Set initial filtered section to active
183 + filteredOffersSection = activeOffersSection
184 +
185 + // Favorite Coupons — empty for now
186 + let favoriteCoupons: [CouponItemModel] = []
187 + favoriteOffersSection = SectionModel(
188 + sectionType: .profileCoupon,
189 + title: "Αγαπημένα",
190 + items: favoriteCoupons,
191 + itemType: .coupons
192 + )
193 +
194 + // Redeemed Coupons — status == 0
195 + let redeemedCoupons = allCoupons.filter { $0.status == 0 }
196 + redeemedOffersSection = SectionModel(
197 + sectionType: .profileCoupon,
198 + title: "Εξαργυρωμένα",
199 + items: redeemedCoupons,
200 + itemType: .coupons
201 + )
202 +
203 + self.tableView.reloadData()
204 + }
205 +
206 + private func openCouponViewController(with coupon: CouponItemModel) {
207 + let vc = SwiftWarplyFramework.CouponViewController(nibName: "CouponViewController", bundle: Bundle.frameworkBundle)
208 + vc.coupon = coupon
209 +
210 + self.navigationController?.pushViewController(vc, animated: true)
211 + }
212 +
213 + private func handleFilterPress(with filter: CouponFilterModel) {
214 + switch (filter.title) {
215 + case "Ενεργά":
216 + self.filteredOffersSection = activeOffersSection
217 + case "Αγαπημένα":
218 + self.filteredOffersSection = favoriteOffersSection
219 + case "Εξαργυρωμένα":
220 + self.filteredOffersSection = redeemedOffersSection
221 + default:
222 + self.filteredOffersSection = activeOffersSection
223 + }
224 + }
225 +
226 + // MARK: - Empty State Helper
227 +
228 + private func getEmptyStateMessage() -> String {
229 + switch couponFilterSelected.title {
230 + case "Ενεργά":
231 + return "Δεν υπάρχουν διαθέσιμα ενεργά κουπόνια"
232 + case "Αγαπημένα":
233 + return "Δεν υπάρχουν διαθέσιμα αγαπημένα κουπόνια"
234 + case "Εξαργυρωμένα":
235 + return "Δεν υπάρχουν διαθέσιμα εξαργυρωμένα κουπόνια"
236 + default:
237 + return "Δεν υπάρχουν διαθέσιμα κουπόνια"
238 + }
239 + }
240 +
241 + private func createEmptyStateCell(_ tableView: UITableView, indexPath: IndexPath) -> UITableViewCell {
242 + let cell = UITableViewCell(style: .default, reuseIdentifier: "EmptyStateCell")
243 + cell.selectionStyle = .none
244 + cell.backgroundColor = .clear
245 + cell.contentView.backgroundColor = .clear
246 +
247 + // Remove any existing subviews
248 + cell.contentView.subviews.forEach { $0.removeFromSuperview() }
249 +
250 + let label = UILabel()
251 + label.text = getEmptyStateMessage()
252 + label.font = UIFont(name: "PingLCG-Regular", size: 16)
253 + label.textColor = UIColor(rgb: 0x8B8B8B)
254 + label.textAlignment = .center
255 + label.numberOfLines = 0
256 + label.translatesAutoresizingMaskIntoConstraints = false
257 +
258 + cell.contentView.addSubview(label)
259 +
260 + NSLayoutConstraint.activate([
261 + label.topAnchor.constraint(equalTo: cell.contentView.topAnchor, constant: 40),
262 + label.bottomAnchor.constraint(equalTo: cell.contentView.bottomAnchor, constant: -40),
263 + label.leadingAnchor.constraint(equalTo: cell.contentView.leadingAnchor, constant: 24),
264 + label.trailingAnchor.constraint(equalTo: cell.contentView.trailingAnchor, constant: -24)
265 + ])
266 +
267 + return cell
268 + }
269 +}
270 +
271 +// MARK: - TableView
272 +extension MyCouponsViewController: UITableViewDelegate, UITableViewDataSource {
273 +
274 + public func numberOfSections(in tableView: UITableView) -> Int {
275 + // return 4 + (filteredOffersSection?.offers.count ?? 0)
276 + return 5
277 + }
278 +
279 + public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
280 + // return 1
281 + if (section == 2) {
282 + if (forYouOffersSection?.count ?? 0 > 0) {
283 + return 1
284 + } else {
285 + return 0
286 + }
287 + }
288 + if (section <= 3) {
289 + return 1
290 + } else {
291 + let itemCount = filteredOffersSection?.itemCount ?? 0
292 + // Show at least 1 row for empty state message when no coupons
293 + return itemCount > 0 ? itemCount : 1
294 + }
295 + }
296 +
297 + public func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
298 + return UITableView.automaticDimension
299 + }
300 +
301 + public func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
302 + return nil
303 + }
304 +
305 + public func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
306 + return 0.0
307 + }
308 +
309 + public func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
310 + return 0.0
311 + }
312 +
313 + public func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
314 + return nil
315 + }
316 +
317 + public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
318 + if (indexPath.section == 0) {
319 + let cell = tableView.dequeueReusableCell(withIdentifier: "MyCouponsHeaderTableViewCell", for: indexPath) as! MyCouponsHeaderTableViewCell
320 + return cell
321 +
322 + } else if (indexPath.section == 1) {
323 + let cell = tableView.dequeueReusableCell(withIdentifier: "ProfileQuestionnaireTableViewCell", for: indexPath) as! ProfileQuestionnaireTableViewCell
324 + return cell
325 +
326 + } else if (indexPath.section == 2) {
327 + let cell = tableView.dequeueReusableCell(withIdentifier: "MyRewardsOffersScrollTableViewCell", for: indexPath) as! MyRewardsOffersScrollTableViewCell
328 +
329 + cell.delegate = self // Set the offers delegate
330 + cell.configureCell(data: self.forYouOffersSection, isInProfile: true)
331 +
332 + return cell
333 +
334 + } else if (indexPath.section == 3) {
335 + let cell = tableView.dequeueReusableCell(withIdentifier: "ProfileCouponFiltersTableViewCell", for: indexPath) as! ProfileCouponFiltersTableViewCell
336 +
337 + cell.delegate = self // Set the offers delegate
338 + cell.configureCell(data: self.couponFilters, couponFilterSelected: self.couponFilterSelected)
339 +
340 + return cell
341 +
342 + } else {
343 + // Check if the filtered section is empty — show empty state
344 + let itemCount = filteredOffersSection?.itemCount ?? 0
345 + if itemCount == 0 {
346 + return createEmptyStateCell(tableView, indexPath: indexPath)
347 + }
348 +
349 + let cell = tableView.dequeueReusableCell(withIdentifier: "ProfileCouponTableViewCell", for: indexPath) as! ProfileCouponTableViewCell
350 + if let items = self.filteredOffersSection?.items,
351 + indexPath.row < items.count,
352 + let coupon = items[indexPath.row] as? CouponItemModel {
353 + cell.configureCell(data: coupon)
354 + }
355 + return cell
356 + }
357 +
358 + }
359 +
360 + public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
361 + if (indexPath.section <= 3) {
362 + // Do nothing
363 + } else {
364 + if let items = self.filteredOffersSection?.items,
365 + indexPath.row < items.count,
366 + let coupon = items[indexPath.row] as? CouponItemModel {
367 + openCouponViewController(with: coupon)
368 + }
369 + }
370 + }
371 +}
372 +
373 +// Add delegate conformance
374 +extension MyCouponsViewController: MyRewardsOffersScrollTableViewCellDelegate {
375 + func didSelectOffer(_ offer: OfferModel) {
376 + // Legacy OfferModel handling — no longer used but kept for protocol conformance
377 + print("⚠️ [MyCouponsVC] didSelectOffer called with legacy OfferModel — should not happen")
378 + }
379 +
380 + func didSelectCouponSet(_ couponSet: CouponSetItemModel) {
381 + // MyCouponsViewController doesn't handle coupon sets, so just log
382 + print("CouponSet selected in MyCouponsViewController: \(couponSet._name)")
383 + }
384 +}
385 +
386 +// Add delegate conformance
387 +extension MyCouponsViewController: ProfileCouponFiltersTableViewCellDelegate {
388 + func didSelectFilter(_ filter: CouponFilterModel) {
389 + self.couponFilterSelected = filter
390 + handleFilterPress(with: filter)
391 + self.tableView.reloadData()
392 + }
393 +}
...\ No newline at end of file ...\ No newline at end of file
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="24506" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
3 + <device id="retina6_12" orientation="portrait" appearance="light"/>
4 + <dependencies>
5 + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="24504"/>
6 + <capability name="Safe area layout guides" minToolsVersion="9.0"/>
7 + <capability name="System colors in document resources" minToolsVersion="11.0"/>
8 + <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
9 + </dependencies>
10 + <objects>
11 + <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="MyCouponsViewController" customModule="SwiftWarplyFramework" customModuleProvider="target">
12 + <connections>
13 + <outlet property="tableView" destination="5Lc-C5-PjX" id="pay-eD-2GR"/>
14 + <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
15 + </connections>
16 + </placeholder>
17 + <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
18 + <view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
19 + <rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
20 + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
21 + <subviews>
22 + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="3MR-Lq-Ca1" userLabel="Main View">
23 + <rect key="frame" x="0.0" y="118" width="393" height="734"/>
24 + <subviews>
25 + <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="none" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" estimatedSectionHeaderHeight="-1" sectionFooterHeight="28" estimatedSectionFooterHeight="-1" contentViewInsetsToSafeArea="NO" translatesAutoresizingMaskIntoConstraints="NO" id="5Lc-C5-PjX">
26 + <rect key="frame" x="0.0" y="0.0" width="393" height="734"/>
27 + <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
28 + <color key="separatorColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
29 + <color key="sectionIndexBackgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
30 + <connections>
31 + <outlet property="dataSource" destination="-1" id="yKP-hs-r89"/>
32 + <outlet property="delegate" destination="-1" id="hPq-MZ-iBl"/>
33 + </connections>
34 + </tableView>
35 + </subviews>
36 + <color key="backgroundColor" red="0.94901960780000005" green="0.94901960780000005" blue="0.94901960780000005" alpha="1" colorSpace="calibratedRGB"/>
37 + <constraints>
38 + <constraint firstItem="5Lc-C5-PjX" firstAttribute="leading" secondItem="3MR-Lq-Ca1" secondAttribute="leading" id="E1N-Fh-MGi"/>
39 + <constraint firstItem="5Lc-C5-PjX" firstAttribute="top" secondItem="3MR-Lq-Ca1" secondAttribute="top" id="oMH-QW-fBP"/>
40 + <constraint firstAttribute="trailing" secondItem="5Lc-C5-PjX" secondAttribute="trailing" id="qGu-bT-w0t"/>
41 + <constraint firstAttribute="bottom" secondItem="5Lc-C5-PjX" secondAttribute="bottom" id="yQw-1D-xi9"/>
42 + </constraints>
43 + </view>
44 + </subviews>
45 + <viewLayoutGuide key="safeArea" id="fnl-2z-Ty3"/>
46 + <color key="backgroundColor" systemColor="systemBackgroundColor"/>
47 + <constraints>
48 + <constraint firstItem="3MR-Lq-Ca1" firstAttribute="leading" secondItem="i5M-Pr-FkT" secondAttribute="leading" id="3RG-QL-Pay"/>
49 + <constraint firstAttribute="bottom" secondItem="3MR-Lq-Ca1" secondAttribute="bottom" id="H7T-5I-z6N"/>
50 + <constraint firstAttribute="trailing" secondItem="3MR-Lq-Ca1" secondAttribute="trailing" id="c03-MD-sDl"/>
51 + <constraint firstItem="3MR-Lq-Ca1" firstAttribute="top" secondItem="fnl-2z-Ty3" secondAttribute="top" id="hPa-2m-0vn"/>
52 + </constraints>
53 + <point key="canvasLocation" x="140" y="154"/>
54 + </view>
55 + </objects>
56 + <resources>
57 + <systemColor name="systemBackgroundColor">
58 + <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
59 + </systemColor>
60 + </resources>
61 +</document>