Manos Chorianopoulos

CategoryOffers part2

...@@ -9,10 +9,118 @@ import UIKit ...@@ -9,10 +9,118 @@ import UIKit
9 9
10 @objc(CategoryOfferCollectionViewCell) 10 @objc(CategoryOfferCollectionViewCell)
11 public class CategoryOfferCollectionViewCell: UICollectionViewCell { 11 public class CategoryOfferCollectionViewCell: UICollectionViewCell {
12 + @IBOutlet weak var parentView: UIView!
13 + @IBOutlet weak var bannerImage: UIImageView!
14 + @IBOutlet weak var logoImage: UIImageView!
15 + @IBOutlet weak var discountView: UIView!
16 + @IBOutlet weak var discountLabel: UILabel!
17 + @IBOutlet weak var merchantNameLabel: UILabel!
18 + @IBOutlet weak var titleLabel: UILabel!
19 + @IBOutlet weak var subtitleLabel: UILabel!
20 + @IBOutlet weak var expirationLabel: UILabel!
21 +
22 + var postImageURL: String? {
23 + didSet {
24 + if let url = postImageURL {
25 + self.bannerImage.image = UIImage()
26 + UIImage.loadImageUsingCacheWithUrlString(url) { image in
27 + if url == self.postImageURL {
28 + self.bannerImage.image = image
29 + }
30 + }
31 + } else {
32 + self.bannerImage.image = nil
33 + }
34 + }
35 + }
36 +
37 + var logoImageURL: String? {
38 + didSet {
39 + if let url = logoImageURL {
40 + self.logoImage.image = UIImage()
41 + UIImage.loadImageUsingCacheWithUrlString(url) { image in
42 + if url == self.logoImageURL {
43 + self.logoImage.image = image
44 + }
45 + }
46 + } else {
47 + self.logoImage.image = nil
48 + }
49 + }
50 + }
12 51
13 public override func awakeFromNib() { 52 public override func awakeFromNib() {
14 super.awakeFromNib() 53 super.awakeFromNib()
15 - // Initialization code 54 +
55 + parentView.layer.borderWidth = 1.0
56 + parentView.layer.borderColor = UIColor(rgb: 0xD2D6D9).cgColor
57 + parentView.layer.cornerRadius = 12.0
58 + parentView.clipsToBounds = true
59 +
60 + logoImage.layer.cornerRadius = 8.0
61 + logoImage.clipsToBounds = true
62 + logoImage.backgroundColor = UIColor(rgb: 0xEEEEEE)
63 +
64 + discountView.layer.cornerRadius = 17.0
65 + discountView.clipsToBounds = true
16 } 66 }
17 67
68 + func configureCell(data: OfferModel) {
69 + bannerImage.image = UIImage(named: data.bannerImage, in: Bundle.frameworkResourceBundle, compatibleWith: nil)
70 +
71 + discountLabel.text = data.discount
72 + discountLabel.font = UIFont(name: "PingLCG-Bold", size: 14)
73 + discountLabel.textColor = UIColor(rgb: 0xFFFFFF)
74 + discountView.backgroundColor = UIColor(rgb: 0xCBCBCB)
75 +
76 + merchantNameLabel.text = data.title
77 + merchantNameLabel.font = UIFont(name: "PingLCG-Regular", size: 12)
78 + merchantNameLabel.textColor = UIColor(rgb: 0x000F1E)
79 +
80 + titleLabel.text = data.title
81 + titleLabel.font = UIFont(name: "PingLCG-Bold", size: 15)
82 + titleLabel.textColor = UIColor(rgb: 0x000F1E)
83 +
84 + subtitleLabel.text = data.description
85 + subtitleLabel.font = UIFont(name: "PingLCG-Regular", size: 13)
86 + subtitleLabel.textColor = UIColor(rgb: 0x00111B)
87 +
88 + expirationLabel.text = data.expirationDate
89 + expirationLabel.font = UIFont(name: "PingLCG-Regular", size: 12)
90 + expirationLabel.textColor = UIColor(rgb: 0x9BA1A6)
91 +
92 + logoImage.image = UIImage(named: data.merchantLogo, in: Bundle.frameworkResourceBundle, compatibleWith: nil)
93 + }
94 +
95 + func configureCell(data: CouponSetItemModel) {
96 + self.postImageURL = data._app_img_preview
97 +
98 + discountLabel.text = data._discount
99 + discountLabel.font = UIFont(name: "PingLCG-Bold", size: 14)
100 + discountLabel.textColor = UIColor(rgb: 0xFFFFFF)
101 + discountView.backgroundColor = UIColor(rgb: 0xCBCBCB)
102 +
103 + if let merchant = data._merchant {
104 + merchantNameLabel.text = merchant._admin_name
105 + self.logoImageURL = merchant._img_preview
106 + } else {
107 + merchantNameLabel.text = ""
108 + self.logoImageURL = nil
109 + }
110 +
111 + merchantNameLabel.font = UIFont(name: "PingLCG-Regular", size: 12)
112 + merchantNameLabel.textColor = UIColor(rgb: 0x000F1E)
113 +
114 + titleLabel.text = data._name
115 + titleLabel.font = UIFont(name: "PingLCG-Bold", size: 15)
116 + titleLabel.textColor = UIColor(rgb: 0x000F1E)
117 +
118 + subtitleLabel.text = data._short_description
119 + subtitleLabel.font = UIFont(name: "PingLCG-Regular", size: 13)
120 + subtitleLabel.textColor = UIColor(rgb: 0x00111B)
121 +
122 + expirationLabel.text = "until " + data.formattedEndDate(format: "dd-MM")
123 + expirationLabel.font = UIFont(name: "PingLCG-Regular", size: 12)
124 + expirationLabel.textColor = UIColor(rgb: 0x9BA1A6)
125 + }
18 } 126 }
......
1 -<?xml version="1.0" encoding="UTF-8" standalone="no"?> 1 +<?xml version="1.0" encoding="UTF-8"?>
2 -<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="13142" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES"> 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"/>
3 <dependencies> 4 <dependencies>
4 - <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12042"/> 5 + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="24504"/>
5 <capability name="Safe area layout guides" minToolsVersion="9.0"/> 6 <capability name="Safe area layout guides" minToolsVersion="9.0"/>
7 + <capability name="System colors in document resources" minToolsVersion="11.0"/>
6 <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> 8 <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
7 </dependencies> 9 </dependencies>
8 <objects> 10 <objects>
9 <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/> 11 <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
10 <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/> 12 <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
11 - <collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" id="gTV-IL-0wX" customClass="CategoryOfferCollectionViewCell" customModuleProvider="target"> 13 + <collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" id="gTV-IL-0wX" customClass="CategoryOfferCollectionViewCell" customModule="SwiftWarplyFramework" customModuleProvider="target">
12 - <rect key="frame" x="0.0" y="0.0" width="50" height="50"/> 14 + <rect key="frame" x="0.0" y="0.0" width="170" height="280"/>
13 <autoresizingMask key="autoresizingMask"/> 15 <autoresizingMask key="autoresizingMask"/>
14 <view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center"> 16 <view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
15 - <rect key="frame" x="0.0" y="0.0" width="50" height="50"/> 17 + <rect key="frame" x="0.0" y="0.0" width="170" height="280"/>
16 - <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/> 18 + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
19 + <subviews>
20 + <!-- parentView: card container with border + rounded corners -->
21 + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="A1B-CD-EFG" userLabel="parentView">
22 + <rect key="frame" x="0.0" y="0.0" width="170" height="280"/>
23 + <subviews>
24 + <!-- Top View: gray background, banner image, logo, discount -->
25 + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="TOP-vw-001" userLabel="TopView">
26 + <rect key="frame" x="0.0" y="0.0" width="170" height="140"/>
27 + <subviews>
28 + <!-- Banner image fills the top view -->
29 + <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="BNR-img-001">
30 + <rect key="frame" x="0.0" y="0.0" width="170" height="140"/>
31 + </imageView>
32 + <!-- Logo image: centered in top view -->
33 + <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="LGO-img-001">
34 + <rect key="frame" x="51" y="42" width="48" height="48"/>
35 + <constraints>
36 + <constraint firstAttribute="width" constant="48" id="LGO-w-001"/>
37 + <constraint firstAttribute="height" constant="48" id="LGO-h-001"/>
38 + </constraints>
39 + </imageView>
40 + <!-- Discount circle: top-right -->
41 + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="DSC-vw-001" userLabel="discountView">
42 + <rect key="frame" x="130" y="8" width="34" height="34"/>
43 + <subviews>
44 + <label opaque="NO" userInteractionEnabled="NO" contentMode="center" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="%" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="YES" minimumFontScaleFactor="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="DSC-lbl-001">
45 + <rect key="frame" x="2" y="2" width="30" height="30"/>
46 + <fontDescription key="fontDescription" type="system" pointSize="14"/>
47 + <nil key="textColor"/>
48 + <nil key="highlightedColor"/>
49 + </label>
50 + </subviews>
51 + <color key="backgroundColor" red="0.796" green="0.796" blue="0.796" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
52 + <constraints>
53 + <constraint firstAttribute="width" constant="34" id="DSC-w-001"/>
54 + <constraint firstAttribute="height" constant="34" id="DSC-h-001"/>
55 + <constraint firstItem="DSC-lbl-001" firstAttribute="top" secondItem="DSC-vw-001" secondAttribute="top" constant="2" id="DSC-t-001"/>
56 + <constraint firstItem="DSC-lbl-001" firstAttribute="leading" secondItem="DSC-vw-001" secondAttribute="leading" constant="2" id="DSC-l-001"/>
57 + <constraint firstAttribute="trailing" secondItem="DSC-lbl-001" secondAttribute="trailing" constant="2" id="DSC-tr-001"/>
58 + <constraint firstAttribute="bottom" secondItem="DSC-lbl-001" secondAttribute="bottom" constant="2" id="DSC-b-001"/>
59 + </constraints>
60 + </view>
61 + </subviews>
62 + <color key="backgroundColor" red="0.937" green="0.941" blue="0.945" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
63 + <constraints>
64 + <!-- Banner fills top view -->
65 + <constraint firstItem="BNR-img-001" firstAttribute="top" secondItem="TOP-vw-001" secondAttribute="top" id="BNR-t-001"/>
66 + <constraint firstItem="BNR-img-001" firstAttribute="leading" secondItem="TOP-vw-001" secondAttribute="leading" id="BNR-l-001"/>
67 + <constraint firstAttribute="trailing" secondItem="BNR-img-001" secondAttribute="trailing" id="BNR-tr-001"/>
68 + <constraint firstAttribute="bottom" secondItem="BNR-img-001" secondAttribute="bottom" id="BNR-b-001"/>
69 + <!-- Logo centered -->
70 + <constraint firstItem="LGO-img-001" firstAttribute="centerX" secondItem="TOP-vw-001" secondAttribute="centerX" id="LGO-cx-001"/>
71 + <constraint firstItem="LGO-img-001" firstAttribute="centerY" secondItem="TOP-vw-001" secondAttribute="centerY" id="LGO-cy-001"/>
72 + <!-- Discount top-right, 8pt from edges -->
73 + <constraint firstAttribute="trailing" secondItem="DSC-vw-001" secondAttribute="trailing" constant="8" id="DSC-tr2-001"/>
74 + <constraint firstItem="DSC-vw-001" firstAttribute="top" secondItem="TOP-vw-001" secondAttribute="top" constant="8" id="DSC-top-001"/>
75 + <!-- Top view height -->
76 + <constraint firstAttribute="height" constant="140" id="TOP-h-001"/>
77 + </constraints>
78 + </view>
79 + <!-- Bottom View: white, text labels -->
80 + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="BTM-vw-001" userLabel="BottomView">
81 + <rect key="frame" x="0.0" y="140" width="170" height="140"/>
82 + <subviews>
83 + <!-- Merchant name label -->
84 + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Merchant" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="MRC-lbl-001">
85 + <rect key="frame" x="10" y="10" width="150" height="16"/>
86 + <fontDescription key="fontDescription" type="system" pointSize="12"/>
87 + <nil key="textColor"/>
88 + <nil key="highlightedColor"/>
89 + </label>
90 + <!-- Title label (bold) -->
91 + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="TTL-lbl-001">
92 + <rect key="frame" x="10" y="30" width="150" height="40"/>
93 + <fontDescription key="fontDescription" type="system" pointSize="15"/>
94 + <nil key="textColor"/>
95 + <nil key="highlightedColor"/>
96 + </label>
97 + <!-- Subtitle label -->
98 + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Subtitle" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="SUB-lbl-001">
99 + <rect key="frame" x="10" y="74" width="150" height="34"/>
100 + <fontDescription key="fontDescription" type="system" pointSize="13"/>
101 + <nil key="textColor"/>
102 + <nil key="highlightedColor"/>
103 + </label>
104 + <!-- Expiration label -->
105 + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="until 30-09" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="EXP-lbl-001">
106 + <rect key="frame" x="10" y="112" width="150" height="16"/>
107 + <fontDescription key="fontDescription" type="system" pointSize="12"/>
108 + <nil key="textColor"/>
109 + <nil key="highlightedColor"/>
110 + </label>
111 + </subviews>
112 + <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
113 + <constraints>
114 + <!-- Merchant label -->
115 + <constraint firstItem="MRC-lbl-001" firstAttribute="top" secondItem="BTM-vw-001" secondAttribute="top" constant="10" id="MRC-t-001"/>
116 + <constraint firstItem="MRC-lbl-001" firstAttribute="leading" secondItem="BTM-vw-001" secondAttribute="leading" constant="10" id="MRC-l-001"/>
117 + <constraint firstAttribute="trailing" secondItem="MRC-lbl-001" secondAttribute="trailing" constant="10" id="MRC-tr-001"/>
118 + <!-- Title below merchant, 4pt gap -->
119 + <constraint firstItem="TTL-lbl-001" firstAttribute="top" secondItem="MRC-lbl-001" secondAttribute="bottom" constant="4" id="TTL-t-001"/>
120 + <constraint firstItem="TTL-lbl-001" firstAttribute="leading" secondItem="BTM-vw-001" secondAttribute="leading" constant="10" id="TTL-l-001"/>
121 + <constraint firstAttribute="trailing" secondItem="TTL-lbl-001" secondAttribute="trailing" constant="10" id="TTL-tr-001"/>
122 + <!-- Subtitle below title, 4pt gap -->
123 + <constraint firstItem="SUB-lbl-001" firstAttribute="top" secondItem="TTL-lbl-001" secondAttribute="bottom" constant="4" id="SUB-t-001"/>
124 + <constraint firstItem="SUB-lbl-001" firstAttribute="leading" secondItem="BTM-vw-001" secondAttribute="leading" constant="10" id="SUB-l-001"/>
125 + <constraint firstAttribute="trailing" secondItem="SUB-lbl-001" secondAttribute="trailing" constant="10" id="SUB-tr-001"/>
126 + <!-- Expiration pinned to bottom -->
127 + <constraint firstAttribute="bottom" secondItem="EXP-lbl-001" secondAttribute="bottom" constant="10" id="EXP-b-001"/>
128 + <constraint firstItem="EXP-lbl-001" firstAttribute="leading" secondItem="BTM-vw-001" secondAttribute="leading" constant="10" id="EXP-l-001"/>
129 + <constraint firstAttribute="trailing" secondItem="EXP-lbl-001" secondAttribute="trailing" constant="10" id="EXP-tr-001"/>
130 + </constraints>
131 + </view>
132 + </subviews>
133 + <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
134 + <constraints>
135 + <!-- Top view pinned to top -->
136 + <constraint firstItem="TOP-vw-001" firstAttribute="top" secondItem="A1B-CD-EFG" secondAttribute="top" id="TOP-t-p-001"/>
137 + <constraint firstItem="TOP-vw-001" firstAttribute="leading" secondItem="A1B-CD-EFG" secondAttribute="leading" id="TOP-l-p-001"/>
138 + <constraint firstAttribute="trailing" secondItem="TOP-vw-001" secondAttribute="trailing" id="TOP-tr-p-001"/>
139 + <!-- Bottom view below top view -->
140 + <constraint firstItem="BTM-vw-001" firstAttribute="top" secondItem="TOP-vw-001" secondAttribute="bottom" id="BTM-t-p-001"/>
141 + <constraint firstItem="BTM-vw-001" firstAttribute="leading" secondItem="A1B-CD-EFG" secondAttribute="leading" id="BTM-l-p-001"/>
142 + <constraint firstAttribute="trailing" secondItem="BTM-vw-001" secondAttribute="trailing" id="BTM-tr-p-001"/>
143 + <constraint firstAttribute="bottom" secondItem="BTM-vw-001" secondAttribute="bottom" id="BTM-b-p-001"/>
144 + </constraints>
145 + </view>
146 + </subviews>
147 + <constraints>
148 + <constraint firstItem="A1B-CD-EFG" firstAttribute="top" secondItem="gTV-IL-0wX" secondAttribute="top" id="PV-t-001"/>
149 + <constraint firstItem="A1B-CD-EFG" firstAttribute="leading" secondItem="gTV-IL-0wX" secondAttribute="leading" id="PV-l-001"/>
150 + <constraint firstAttribute="trailing" secondItem="A1B-CD-EFG" secondAttribute="trailing" id="PV-tr-001"/>
151 + <constraint firstAttribute="bottom" secondItem="A1B-CD-EFG" secondAttribute="bottom" id="PV-b-001"/>
152 + </constraints>
17 </view> 153 </view>
18 <viewLayoutGuide key="safeArea" id="ZTg-uK-7eu"/> 154 <viewLayoutGuide key="safeArea" id="ZTg-uK-7eu"/>
155 + <connections>
156 + <outlet property="bannerImage" destination="BNR-img-001" id="BNR-out-001"/>
157 + <outlet property="discountLabel" destination="DSC-lbl-001" id="DSC-out-001"/>
158 + <outlet property="discountView" destination="DSC-vw-001" id="DSC-out-002"/>
159 + <outlet property="expirationLabel" destination="EXP-lbl-001" id="EXP-out-001"/>
160 + <outlet property="logoImage" destination="LGO-img-001" id="LGO-out-001"/>
161 + <outlet property="merchantNameLabel" destination="MRC-lbl-001" id="MRC-out-001"/>
162 + <outlet property="parentView" destination="A1B-CD-EFG" id="PV-out-001"/>
163 + <outlet property="subtitleLabel" destination="SUB-lbl-001" id="SUB-out-001"/>
164 + <outlet property="titleLabel" destination="TTL-lbl-001" id="TTL-out-001"/>
165 + </connections>
166 + <size key="customSize" width="170" height="280"/>
167 + <point key="canvasLocation" x="50" y="50"/>
19 </collectionViewCell> 168 </collectionViewCell>
20 </objects> 169 </objects>
170 + <resources>
171 + <systemColor name="systemBackgroundColor">
172 + <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
173 + </systemColor>
174 + </resources>
21 </document> 175 </document>
......
...@@ -18,21 +18,11 @@ public class CategoryOffersGridTableViewCell: UITableViewCell { ...@@ -18,21 +18,11 @@ public class CategoryOffersGridTableViewCell: UITableViewCell {
18 18
19 public override func awakeFromNib() { 19 public override func awakeFromNib() {
20 super.awakeFromNib() 20 super.awakeFromNib()
21 - // Initialization code
22 21
23 - setupCollectionView()
24 - }
25 -
26 - public override func setSelected(_ selected: Bool, animated: Bool) {
27 - super.setSelected(selected, animated: animated)
28 - // Configure the view for the selected state
29 - }
30 -
31 - private func setupCollectionView() {
32 collectionView.delegate = self 22 collectionView.delegate = self
33 collectionView.dataSource = self 23 collectionView.dataSource = self
34 collectionView.backgroundColor = .clear 24 collectionView.backgroundColor = .clear
35 - collectionView.isScrollEnabled = false // Scroll is handled by the outer TableView 25 + collectionView.isScrollEnabled = false
36 26
37 XIBLoader.registerCollectionViewCell( 27 XIBLoader.registerCollectionViewCell(
38 collectionView, 28 collectionView,
...@@ -42,22 +32,44 @@ public class CategoryOffersGridTableViewCell: UITableViewCell { ...@@ -42,22 +32,44 @@ public class CategoryOffersGridTableViewCell: UITableViewCell {
42 ) 32 )
43 33
44 if let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout { 34 if let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
45 - layout.minimumInteritemSpacing = 16 35 + layout.minimumInteritemSpacing = 12
46 layout.minimumLineSpacing = 16 36 layout.minimumLineSpacing = 16
47 layout.sectionInset = UIEdgeInsets(top: 16, left: 16, bottom: 16, right: 16) 37 layout.sectionInset = UIEdgeInsets(top: 16, left: 16, bottom: 16, right: 16)
48 } 38 }
49 } 39 }
50 40
41 + public override func setSelected(_ selected: Bool, animated: Bool) {
42 + super.setSelected(selected, animated: animated)
43 + }
44 +
51 func configureCell(with sectionData: SectionModel?, parentViewController: UIViewController?) { 45 func configureCell(with sectionData: SectionModel?, parentViewController: UIViewController?) {
52 self.data = sectionData 46 self.data = sectionData
53 self.parentViewController = parentViewController 47 self.parentViewController = parentViewController
54 48
55 collectionView.reloadData() 49 collectionView.reloadData()
56 50
57 - // Use layoutIfNeeded to calculate content size and set the height constraint 51 + // Calculate and set the collection view height so the table view cell expands correctly
58 - collectionView.layoutIfNeeded() 52 + DispatchQueue.main.async {
59 - let height = collectionView.collectionViewLayout.collectionViewContentSize.height 53 + self.collectionView.layoutIfNeeded()
60 - collectionViewHeightConstraint.constant = height 54 + let height = self.collectionView.collectionViewLayout.collectionViewContentSize.height
55 + self.collectionViewHeightConstraint.constant = max(height, 1)
56 + // Notify the parent table view to recalculate its layout
57 + if let tableView = self.parentViewController?.view.subviews.first(where: { $0 is UITableView }) as? UITableView {
58 + tableView.beginUpdates()
59 + tableView.endUpdates()
60 + }
61 + }
62 + }
63 +
64 + // Compute item size for 2-column grid
65 + private func itemSize() -> CGSize {
66 + let totalWidth = collectionView.bounds.width > 0 ? collectionView.bounds.width : UIScreen.main.bounds.width
67 + let inset: CGFloat = 16
68 + let spacing: CGFloat = 12
69 + let availableWidth = totalWidth - (inset * 2) - spacing
70 + let itemWidth = floor(availableWidth / 2)
71 + let itemHeight = itemWidth * 1.65 // ratio matching the design card proportions
72 + return CGSize(width: itemWidth, height: itemHeight)
61 } 73 }
62 } 74 }
63 75
...@@ -101,38 +113,35 @@ extension CategoryOffersGridTableViewCell: UICollectionViewDataSource, UICollect ...@@ -101,38 +113,35 @@ extension CategoryOffersGridTableViewCell: UICollectionViewDataSource, UICollect
101 return 113 return
102 } 114 }
103 115
104 - // Handle navigation based on item type
105 switch data.itemType { 116 switch data.itemType {
106 case .couponSets: 117 case .couponSets:
107 if let couponSet = items[indexPath.row] as? CouponSetItemModel { 118 if let couponSet = items[indexPath.row] as? CouponSetItemModel {
108 - let storyboard = UIStoryboard(name: "Main", bundle: Bundle.frameworkResourceBundle) 119 + let vc = CouponsetViewController(nibName: "CouponsetViewController", bundle: Bundle.frameworkResourceBundle)
109 - if let vc = storyboard.instantiateViewController(withIdentifier: "CouponsetViewController") as? CouponsetViewController {
110 vc.couponset = couponSet 120 vc.couponset = couponSet
111 - self.parentViewController?.navigationController?.pushViewController(vc, animated: true) 121 + parentViewController?.navigationController?.pushViewController(vc, animated: true)
112 - }
113 } 122 }
114 default: 123 default:
115 if let offer = items[indexPath.row] as? OfferModel { 124 if let offer = items[indexPath.row] as? OfferModel {
116 - // Determine if it's a campaign or other offer and navigate appropriately 125 + let vc = CouponViewController(nibName: "CouponViewController", bundle: Bundle.frameworkResourceBundle)
117 - // (Using existing patterns from MyRewardsViewController) 126 + vc.offer = offer
118 - let storyboard = UIStoryboard(name: "Main", bundle: Bundle.frameworkResourceBundle) 127 + parentViewController?.navigationController?.pushViewController(vc, animated: true)
119 - if let vc = storyboard.instantiateViewController(withIdentifier: "CampaignViewController") as? CampaignViewController {
120 - vc.campaignUrl = offer.campaignUrl // Assuming OfferModel has this
121 - self.parentViewController?.navigationController?.pushViewController(vc, animated: true)
122 - }
123 } 128 }
124 } 129 }
125 } 130 }
126 131
127 public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { 132 public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
128 - // Calculate width for 2 columns with spacing 133 + return itemSize()
129 - let padding: CGFloat = 16 * 3 // left + middle + right padding 134 + }
130 - let availableWidth = collectionView.frame.width - padding
131 - let itemWidth = availableWidth / 2
132 135
133 - // Adjust height as needed based on design (aspect ratio or fixed) 136 + public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
134 - let itemHeight = itemWidth * 1.3 // Approximation from screenshot 137 + return 16
138 + }
135 139
136 - return CGSize(width: itemWidth, height: itemHeight) 140 + public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
141 + return 12
142 + }
143 +
144 + public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
145 + return UIEdgeInsets(top: 16, left: 16, bottom: 16, right: 16)
137 } 146 }
138 } 147 }
......
...@@ -10,6 +10,7 @@ import UIKit ...@@ -10,6 +10,7 @@ import UIKit
10 protocol MyRewardsOffersScrollTableViewCellDelegate: AnyObject { 10 protocol MyRewardsOffersScrollTableViewCellDelegate: AnyObject {
11 func didSelectOffer(_ offer: OfferModel) 11 func didSelectOffer(_ offer: OfferModel)
12 func didSelectCouponSet(_ couponSet: CouponSetItemModel) 12 func didSelectCouponSet(_ couponSet: CouponSetItemModel)
13 + func didSelectAllOffers(_ section: SectionModel)
13 } 14 }
14 15
15 @objc(MyRewardsOffersScrollTableViewCell) 16 @objc(MyRewardsOffersScrollTableViewCell)
...@@ -29,19 +30,19 @@ public class MyRewardsOffersScrollTableViewCell: UITableViewCell { ...@@ -29,19 +30,19 @@ public class MyRewardsOffersScrollTableViewCell: UITableViewCell {
29 super.awakeFromNib() 30 super.awakeFromNib()
30 // Initialization code 31 // Initialization code
31 32
32 - // allButtonView.layer.borderWidth = 1.0
33 - // allButtonView.layer.borderColor = UIColor(rgb: 0x000F1E).cgColor
34 - // allButtonView.layer.cornerRadius = 4.0
35 -
36 allButtonArrowImage.image = UIImage(named: "arrow_right_blue", in: Bundle.frameworkResourceBundle, compatibleWith: nil) 33 allButtonArrowImage.image = UIImage(named: "arrow_right_blue", in: Bundle.frameworkResourceBundle, compatibleWith: nil)
37 34
38 - // allButtonLabel.text = "Όλα"
39 allButtonLabel.text = "All" 35 allButtonLabel.text = "All"
40 allButtonLabel.font = UIFont(name: "PingLCG-Regular", size: 15) 36 allButtonLabel.font = UIFont(name: "PingLCG-Regular", size: 15)
41 allButtonLabel.textColor = UIColor(rgb: 0x004E6E) 37 allButtonLabel.textColor = UIColor(rgb: 0x004E6E)
42 allButtonLabel.frame.size.width = allButtonLabel.intrinsicContentSize.width 38 allButtonLabel.frame.size.width = allButtonLabel.intrinsicContentSize.width
43 allButtonLabel.frame.size.height = allButtonLabel.intrinsicContentSize.height 39 allButtonLabel.frame.size.height = allButtonLabel.intrinsicContentSize.height
44 40
41 + // Add tap gesture to allButtonView
42 + let tapGesture = UITapGestureRecognizer(target: self, action: #selector(allButtonTapped))
43 + allButtonView.isUserInteractionEnabled = true
44 + allButtonView.addGestureRecognizer(tapGesture)
45 +
45 // UPDATED: Safe XIB registration for collection view cells 46 // UPDATED: Safe XIB registration for collection view cells
46 registerCollectionViewCells() 47 registerCollectionViewCells()
47 48
...@@ -56,6 +57,11 @@ public class MyRewardsOffersScrollTableViewCell: UITableViewCell { ...@@ -56,6 +57,11 @@ public class MyRewardsOffersScrollTableViewCell: UITableViewCell {
56 collectionView.dataSource = self 57 collectionView.dataSource = self
57 } 58 }
58 59
60 + @objc private func allButtonTapped() {
61 + guard let data = data else { return }
62 + delegate?.didSelectAllOffers(data)
63 + }
64 +
59 // NEW: Safe collection view cell registration 65 // NEW: Safe collection view cell registration
60 private func registerCollectionViewCells() { 66 private func registerCollectionViewCells() {
61 XIBLoader.registerCollectionViewCell( 67 XIBLoader.registerCollectionViewCell(
...@@ -109,20 +115,11 @@ public class MyRewardsOffersScrollTableViewCell: UITableViewCell { ...@@ -109,20 +115,11 @@ public class MyRewardsOffersScrollTableViewCell: UITableViewCell {
109 collectionViewBottom.constant = 0 115 collectionViewBottom.constant = 0
110 } 116 }
111 117
112 - // Update collection view height based on section
113 - // if data?.title == "Αγαπημένα" {
114 - // collectionViewHeightConstraint.constant = 350 // Match cell height
115 - // } else {
116 collectionViewHeightConstraint.constant = 232 // Default height 118 collectionViewHeightConstraint.constant = 232 // Default height
117 - // }
118 119
119 // Configure layout based on section type 120 // Configure layout based on section type
120 if let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout { 121 if let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
121 - // if data?.title == "Αγαπημένα" {
122 - // layout.minimumLineSpacing = 24
123 - // } else {
124 layout.minimumLineSpacing = 7 122 layout.minimumLineSpacing = 7
125 - // }
126 } 123 }
127 124
128 let catBoldText = (data?.title ?? "") + " " 125 let catBoldText = (data?.title ?? "") + " "
...@@ -138,13 +135,11 @@ public class MyRewardsOffersScrollTableViewCell: UITableViewCell { ...@@ -138,13 +135,11 @@ public class MyRewardsOffersScrollTableViewCell: UITableViewCell {
138 categoryLabel.attributedText = catAttributedString 135 categoryLabel.attributedText = catAttributedString
139 136
140 self.collectionView.reloadData(); 137 self.collectionView.reloadData();
141 -
142 } 138 }
143 } 139 }
144 140
145 extension MyRewardsOffersScrollTableViewCell: UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout { 141 extension MyRewardsOffersScrollTableViewCell: UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
146 142
147 -
148 public func numberOfSections(in collectionView: UICollectionView) -> Int { 143 public func numberOfSections(in collectionView: UICollectionView) -> Int {
149 return 1 144 return 1
150 } 145 }
...@@ -189,11 +184,9 @@ extension MyRewardsOffersScrollTableViewCell: UICollectionViewDataSource, UIColl ...@@ -189,11 +184,9 @@ extension MyRewardsOffersScrollTableViewCell: UICollectionViewDataSource, UIColl
189 switch data.itemType { 184 switch data.itemType {
190 case .couponSets: 185 case .couponSets:
191 if let couponSet = items[indexPath.row] as? CouponSetItemModel { 186 if let couponSet = items[indexPath.row] as? CouponSetItemModel {
192 - // Pass CouponSetItemModel directly to new delegate method
193 delegate?.didSelectCouponSet(couponSet) 187 delegate?.didSelectCouponSet(couponSet)
194 } 188 }
195 default: 189 default:
196 - // Handle OfferModel directly for ProfileViewController compatibility
197 if let offer = items[indexPath.row] as? OfferModel { 190 if let offer = items[indexPath.row] as? OfferModel {
198 delegate?.didSelectOffer(offer) 191 delegate?.didSelectOffer(offer)
199 } 192 }
...@@ -202,20 +195,12 @@ extension MyRewardsOffersScrollTableViewCell: UICollectionViewDataSource, UIColl ...@@ -202,20 +195,12 @@ extension MyRewardsOffersScrollTableViewCell: UICollectionViewDataSource, UIColl
202 195
203 // MARK: - UICollectionViewDelegateFlowLayout 196 // MARK: - UICollectionViewDelegateFlowLayout
204 public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { 197 public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
205 - // if self.data?.title == "Αγαπημένα" {
206 - // return CGSize(width: 275, height: 350)
207 - // } else {
208 return CGSize(width: 257, height: 232) 198 return CGSize(width: 257, height: 232)
209 - // }
210 } 199 }
211 200
212 // Distance Between Item Cells 201 // Distance Between Item Cells
213 public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat { 202 public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
214 - // if self.data?.title == "Αγαπημένα" {
215 - // return 24
216 - // } else {
217 return 7 203 return 7
218 - // }
219 } 204 }
220 205
221 public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat { 206 public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
......
...@@ -25,43 +25,54 @@ import UIKit ...@@ -25,43 +25,54 @@ import UIKit
25 private func setupTableView() { 25 private func setupTableView() {
26 tableView.delegate = self 26 tableView.delegate = self
27 tableView.dataSource = self 27 tableView.dataSource = self
28 -
29 tableView.separatorStyle = .none 28 tableView.separatorStyle = .none
30 tableView.backgroundColor = .white 29 tableView.backgroundColor = .white
30 + tableView.estimatedRowHeight = 100
31 + tableView.rowHeight = UITableView.automaticDimension
31 32
32 - tableView.register(UINib(nibName: "CategoryOffersHeaderTableViewCell", bundle: Bundle.frameworkResourceBundle), forCellReuseIdentifier: "CategoryOffersHeaderTableViewCell") 33 + tableView.register(
33 - tableView.register(UINib(nibName: "CategoryOffersGridTableViewCell", bundle: Bundle.frameworkResourceBundle), forCellReuseIdentifier: "CategoryOffersGridTableViewCell") 34 + UINib(nibName: "CategoryOffersHeaderTableViewCell", bundle: Bundle.frameworkResourceBundle),
35 + forCellReuseIdentifier: "CategoryOffersHeaderTableViewCell"
36 + )
37 + tableView.register(
38 + UINib(nibName: "CategoryOffersGridTableViewCell", bundle: Bundle.frameworkResourceBundle),
39 + forCellReuseIdentifier: "CategoryOffersGridTableViewCell"
40 + )
34 } 41 }
35 } 42 }
36 43
37 extension CategoryOffersViewController: UITableViewDelegate, UITableViewDataSource { 44 extension CategoryOffersViewController: UITableViewDelegate, UITableViewDataSource {
45 +
38 public func numberOfSections(in tableView: UITableView) -> Int { 46 public func numberOfSections(in tableView: UITableView) -> Int {
39 return 1 47 return 1
40 } 48 }
41 49
42 public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 50 public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
43 - return 2 // Header + Grid 51 + return 2 // Row 0: Header, Row 1: Grid
44 } 52 }
45 53
46 public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 54 public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
47 if indexPath.row == 0 { 55 if indexPath.row == 0 {
48 let cell = tableView.dequeueReusableCell(withIdentifier: "CategoryOffersHeaderTableViewCell", for: indexPath) as! CategoryOffersHeaderTableViewCell 56 let cell = tableView.dequeueReusableCell(withIdentifier: "CategoryOffersHeaderTableViewCell", for: indexPath) as! CategoryOffersHeaderTableViewCell
49 - if let title = sectionData?.title { 57 + cell.headerLabel.text = sectionData?.title ?? ""
50 - cell.headerLabel.text = title 58 + cell.selectionStyle = .none
51 - }
52 return cell 59 return cell
53 } else { 60 } else {
54 let cell = tableView.dequeueReusableCell(withIdentifier: "CategoryOffersGridTableViewCell", for: indexPath) as! CategoryOffersGridTableViewCell 61 let cell = tableView.dequeueReusableCell(withIdentifier: "CategoryOffersGridTableViewCell", for: indexPath) as! CategoryOffersGridTableViewCell
55 cell.configureCell(with: sectionData, parentViewController: self) 62 cell.configureCell(with: sectionData, parentViewController: self)
63 + cell.selectionStyle = .none
56 return cell 64 return cell
57 } 65 }
58 } 66 }
59 67
60 public func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { 68 public func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
61 - if indexPath.row == 0 {
62 return UITableView.automaticDimension 69 return UITableView.automaticDimension
63 - } else {
64 - return UITableView.automaticDimension // Or a calculated height depending on content
65 } 70 }
71 +
72 + public func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
73 + if indexPath.row == 0 {
74 + return 100
75 + }
76 + return 600
66 } 77 }
67 } 78 }
......
...@@ -802,4 +802,15 @@ extension MyRewardsViewController: MyRewardsOffersScrollTableViewCellDelegate { ...@@ -802,4 +802,15 @@ extension MyRewardsViewController: MyRewardsOffersScrollTableViewCellDelegate {
802 func didSelectCouponSet(_ couponSet: CouponSetItemModel) { 802 func didSelectCouponSet(_ couponSet: CouponSetItemModel) {
803 openCouponsetViewController(with: couponSet) 803 openCouponsetViewController(with: couponSet)
804 } 804 }
805 +
806 + func didSelectAllOffers(_ section: SectionModel) {
807 + let vc = CategoryOffersViewController(nibName: "CategoryOffersViewController", bundle: Bundle.frameworkResourceBundle)
808 + vc.sectionData = section
809 + if let navigationController = self.navigationController {
810 + navigationController.pushViewController(vc, animated: true)
811 + } else {
812 + vc.modalPresentationStyle = .fullScreen
813 + self.present(vc, animated: true, completion: nil)
814 + }
815 + }
805 } 816 }
......
...@@ -545,6 +545,11 @@ extension ProfileViewController: MyRewardsOffersScrollTableViewCellDelegate { ...@@ -545,6 +545,11 @@ extension ProfileViewController: MyRewardsOffersScrollTableViewCellDelegate {
545 // ProfileViewController doesn't handle coupon sets, so just log 545 // ProfileViewController doesn't handle coupon sets, so just log
546 print("CouponSet selected in ProfileViewController: \(couponSet._name)") 546 print("CouponSet selected in ProfileViewController: \(couponSet._name)")
547 } 547 }
548 +
549 + func didSelectAllOffers(_ section: SectionModel) {
550 + // ProfileViewController doesn't navigate to category offers
551 + print("⚠️ [ProfileVC] didSelectAllOffers — not handled")
552 + }
548 } 553 }
549 554
550 // Add delegate conformance 555 // Add delegate conformance
......