Showing
9 changed files
with
203 additions
and
55 deletions
| ... | @@ -7,7 +7,7 @@ | ... | @@ -7,7 +7,7 @@ |
| 7 | <key>Pods-SwiftWarplyFramework.xcscheme_^#shared#^_</key> | 7 | <key>Pods-SwiftWarplyFramework.xcscheme_^#shared#^_</key> |
| 8 | <dict> | 8 | <dict> |
| 9 | <key>orderHint</key> | 9 | <key>orderHint</key> |
| 10 | - <integer>1</integer> | 10 | + <integer>0</integer> |
| 11 | </dict> | 11 | </dict> |
| 12 | </dict> | 12 | </dict> |
| 13 | </dict> | 13 | </dict> | ... | ... |
| ... | @@ -7,7 +7,7 @@ | ... | @@ -7,7 +7,7 @@ |
| 7 | <key>SwiftWarplyFramework.xcscheme_^#shared#^_</key> | 7 | <key>SwiftWarplyFramework.xcscheme_^#shared#^_</key> |
| 8 | <dict> | 8 | <dict> |
| 9 | <key>orderHint</key> | 9 | <key>orderHint</key> |
| 10 | - <integer>0</integer> | 10 | + <integer>1</integer> |
| 11 | </dict> | 11 | </dict> |
| 12 | </dict> | 12 | </dict> |
| 13 | </dict> | 13 | </dict> | ... | ... |
No preview for this file type
| ... | @@ -1675,6 +1675,77 @@ public final class WarplySDK { | ... | @@ -1675,6 +1675,77 @@ public final class WarplySDK { |
| 1675 | } | 1675 | } |
| 1676 | } | 1676 | } |
| 1677 | 1677 | ||
| 1678 | + /// Retrieve a coupon from a coupon set (offer) | ||
| 1679 | + /// - Parameters: | ||
| 1680 | + /// - couponSetUuid: The UUID of the coupon set (offer) to retrieve a coupon from | ||
| 1681 | + /// - completion: Completion handler with response dictionary containing coupon code and expiration | ||
| 1682 | + /// - failureCallback: Failure callback with error code | ||
| 1683 | + /// | ||
| 1684 | + /// Response structure on success: | ||
| 1685 | + /// ```json | ||
| 1686 | + /// { | ||
| 1687 | + /// "msg": "Retrieved", | ||
| 1688 | + /// "result": { | ||
| 1689 | + /// "coupon": "FNMRE2E5FXHH", | ||
| 1690 | + /// "expiration": "2026-10-31 23:59:00" | ||
| 1691 | + /// }, | ||
| 1692 | + /// "status": 1 | ||
| 1693 | + /// } | ||
| 1694 | + /// ``` | ||
| 1695 | + public func retrieveCoupon(couponSetUuid: String, completion: @escaping ([String: Any]?) -> Void, failureCallback: @escaping (Int) -> Void) { | ||
| 1696 | + Task { | ||
| 1697 | + do { | ||
| 1698 | + let response = try await networkService.retrieveCoupon(couponSetUuid: couponSetUuid) | ||
| 1699 | + | ||
| 1700 | + await MainActor.run { | ||
| 1701 | + if response["status"] as? Int == 1 { | ||
| 1702 | + let dynatraceEvent = LoyaltySDKDynatraceEventModel() | ||
| 1703 | + dynatraceEvent._eventName = "custom_success_retrieve_coupon_loyalty" | ||
| 1704 | + dynatraceEvent._parameters = nil | ||
| 1705 | + self.postFrameworkEvent("dynatrace", sender: dynatraceEvent) | ||
| 1706 | + | ||
| 1707 | + print("✅ [WarplySDK] Coupon retrieved successfully") | ||
| 1708 | + if let result = response["result"] as? [String: Any] { | ||
| 1709 | + print(" Coupon: \(result["coupon"] as? String ?? "unknown")") | ||
| 1710 | + print(" Expiration: \(result["expiration"] as? String ?? "unknown")") | ||
| 1711 | + } | ||
| 1712 | + | ||
| 1713 | + completion(response) | ||
| 1714 | + } else { | ||
| 1715 | + let dynatraceEvent = LoyaltySDKDynatraceEventModel() | ||
| 1716 | + dynatraceEvent._eventName = "custom_error_retrieve_coupon_loyalty" | ||
| 1717 | + dynatraceEvent._parameters = nil | ||
| 1718 | + self.postFrameworkEvent("dynatrace", sender: dynatraceEvent) | ||
| 1719 | + | ||
| 1720 | + failureCallback(-1) | ||
| 1721 | + } | ||
| 1722 | + } | ||
| 1723 | + } catch { | ||
| 1724 | + await MainActor.run { | ||
| 1725 | + self.handleError(error, context: "retrieveCoupon", endpoint: "retrieveCoupon", failureCallback: failureCallback) | ||
| 1726 | + } | ||
| 1727 | + } | ||
| 1728 | + } | ||
| 1729 | + } | ||
| 1730 | + | ||
| 1731 | + /// Retrieve a coupon from a coupon set (async/await variant) | ||
| 1732 | + /// - Parameter couponSetUuid: The UUID of the coupon set (offer) to retrieve a coupon from | ||
| 1733 | + /// - Returns: Response dictionary containing coupon code and expiration | ||
| 1734 | + /// - Throws: WarplyError if the request fails | ||
| 1735 | + public func retrieveCoupon(couponSetUuid: String) async throws -> [String: Any] { | ||
| 1736 | + return try await withCheckedThrowingContinuation { continuation in | ||
| 1737 | + retrieveCoupon(couponSetUuid: couponSetUuid, completion: { response in | ||
| 1738 | + if let response = response { | ||
| 1739 | + continuation.resume(returning: response) | ||
| 1740 | + } else { | ||
| 1741 | + continuation.resume(throwing: WarplyError.networkError) | ||
| 1742 | + } | ||
| 1743 | + }, failureCallback: { errorCode in | ||
| 1744 | + continuation.resume(throwing: WarplyError.unknownError(errorCode)) | ||
| 1745 | + }) | ||
| 1746 | + } | ||
| 1747 | + } | ||
| 1748 | + | ||
| 1678 | /// Verify ticket for user authentication | 1749 | /// Verify ticket for user authentication |
| 1679 | public func verifyTicket(guid: String, ticket: String, completion: @escaping (VerifyTicketResponseModel?) -> Void) { | 1750 | public func verifyTicket(guid: String, ticket: String, completion: @escaping (VerifyTicketResponseModel?) -> Void) { |
| 1680 | // Clear previous state | 1751 | // Clear previous state | ... | ... |
| ... | @@ -89,6 +89,7 @@ public enum Endpoint { | ... | @@ -89,6 +89,7 @@ public enum Endpoint { |
| 89 | // Coupon Operations | 89 | // Coupon Operations |
| 90 | case validateCoupon(coupon: [String: Any]) | 90 | case validateCoupon(coupon: [String: Any]) |
| 91 | case redeemCoupon(productId: String, productUuid: String, merchantId: String) | 91 | case redeemCoupon(productId: String, productUuid: String, merchantId: String) |
| 92 | + case retrieveCoupon(couponSetUuid: String) | ||
| 92 | 93 | ||
| 93 | // Profile | 94 | // Profile |
| 94 | case getProfile | 95 | case getProfile |
| ... | @@ -137,7 +138,7 @@ public enum Endpoint { | ... | @@ -137,7 +138,7 @@ public enum Endpoint { |
| 137 | return "/api/mobile/v2/{appUUID}/context/" | 138 | return "/api/mobile/v2/{appUUID}/context/" |
| 138 | 139 | ||
| 139 | // Authenticated Context endpoints - /oauth/{appUUID}/context | 140 | // Authenticated Context endpoints - /oauth/{appUUID}/context |
| 140 | - case .getCampaignsPersonalized, .getCoupons, .getMarketPassDetails, .getProfile, .addCard, .getCards, .deleteCard, .getTransactionHistory, .getPointsHistory, .validateCoupon, .redeemCoupon: | 141 | + case .getCampaignsPersonalized, .getCoupons, .getMarketPassDetails, .getProfile, .addCard, .getCards, .deleteCard, .getTransactionHistory, .getPointsHistory, .validateCoupon, .redeemCoupon, .retrieveCoupon: |
| 141 | return "/oauth/{appUUID}/context" | 142 | return "/oauth/{appUUID}/context" |
| 142 | 143 | ||
| 143 | // Session endpoints - /api/session/{sessionUuid} | 144 | // Session endpoints - /api/session/{sessionUuid} |
| ... | @@ -166,7 +167,7 @@ public enum Endpoint { | ... | @@ -166,7 +167,7 @@ public enum Endpoint { |
| 166 | switch self { | 167 | switch self { |
| 167 | case .register, .changePassword, .resetPassword, .requestOtp, .verifyTicket, .refreshToken, .logout, .getCampaigns, .getCampaignsPersonalized, | 168 | case .register, .changePassword, .resetPassword, .requestOtp, .verifyTicket, .refreshToken, .logout, .getCampaigns, .getCampaignsPersonalized, |
| 168 | .getCoupons, .getCouponSets, .getAvailableCoupons, | 169 | .getCoupons, .getCouponSets, .getAvailableCoupons, |
| 169 | - .getMarketPassDetails, .getProfile, .addCard, .getCards, .deleteCard, .getTransactionHistory, .getPointsHistory, .validateCoupon, .redeemCoupon, .getMerchants, .getMerchantCategories, .getArticles, .sendEvent, .sendDeviceInfo, .getCosmoteUser, .deiLogin: | 170 | + .getMarketPassDetails, .getProfile, .addCard, .getCards, .deleteCard, .getTransactionHistory, .getPointsHistory, .validateCoupon, .redeemCoupon, .retrieveCoupon, .getMerchants, .getMerchantCategories, .getArticles, .sendEvent, .sendDeviceInfo, .getCosmoteUser, .deiLogin: |
| 170 | return .POST | 171 | return .POST |
| 171 | case .getSingleCampaign, .getNetworkStatus: | 172 | case .getSingleCampaign, .getNetworkStatus: |
| 172 | return .GET | 173 | return .GET |
| ... | @@ -383,6 +384,14 @@ public enum Endpoint { | ... | @@ -383,6 +384,14 @@ public enum Endpoint { |
| 383 | ] | 384 | ] |
| 384 | ] | 385 | ] |
| 385 | 386 | ||
| 387 | + case .retrieveCoupon(let couponSetUuid): | ||
| 388 | + return [ | ||
| 389 | + "coupon": [ | ||
| 390 | + "action": "retrieve_coupon", | ||
| 391 | + "coupon_set": couponSetUuid | ||
| 392 | + ] | ||
| 393 | + ] | ||
| 394 | + | ||
| 386 | // Merchants - using correct shops structure for DEI API | 395 | // Merchants - using correct shops structure for DEI API |
| 387 | case .getMerchants(let language, let categories, let defaultShown, let center, let tags, let uuid, let distance, let parentUuids): | 396 | case .getMerchants(let language, let categories, let defaultShown, let center, let tags, let uuid, let distance, let parentUuids): |
| 388 | return [ | 397 | return [ |
| ... | @@ -473,7 +482,7 @@ public enum Endpoint { | ... | @@ -473,7 +482,7 @@ public enum Endpoint { |
| 473 | return .standardContext | 482 | return .standardContext |
| 474 | 483 | ||
| 475 | // Authenticated Context - /oauth/{appUUID}/context | 484 | // Authenticated Context - /oauth/{appUUID}/context |
| 476 | - case .getCampaignsPersonalized, .getCoupons, .getMarketPassDetails, .getProfile, .addCard, .getCards, .deleteCard, .getTransactionHistory, .getPointsHistory, .validateCoupon, .redeemCoupon: | 485 | + case .getCampaignsPersonalized, .getCoupons, .getMarketPassDetails, .getProfile, .addCard, .getCards, .deleteCard, .getTransactionHistory, .getPointsHistory, .validateCoupon, .redeemCoupon, .retrieveCoupon: |
| 477 | return .authenticatedContext | 486 | return .authenticatedContext |
| 478 | 487 | ||
| 479 | // Authentication - /oauth/{appUUID}/login, /oauth/{appUUID}/token | 488 | // Authentication - /oauth/{appUUID}/login, /oauth/{appUUID}/token |
| ... | @@ -515,7 +524,7 @@ public enum Endpoint { | ... | @@ -515,7 +524,7 @@ public enum Endpoint { |
| 515 | return .standard | 524 | return .standard |
| 516 | 525 | ||
| 517 | // Bearer Token Authentication (loyalty headers + Authorization: Bearer) | 526 | // Bearer Token Authentication (loyalty headers + Authorization: Bearer) |
| 518 | - case .changePassword, .getCampaignsPersonalized, .getCoupons, .getMarketPassDetails, .getProfile, .addCard, .getCards, .deleteCard, .getTransactionHistory, .getPointsHistory, .validateCoupon, .redeemCoupon: | 527 | + case .changePassword, .getCampaignsPersonalized, .getCoupons, .getMarketPassDetails, .getProfile, .addCard, .getCards, .deleteCard, .getTransactionHistory, .getPointsHistory, .validateCoupon, .redeemCoupon, .retrieveCoupon: |
| 519 | return .bearerToken | 528 | return .bearerToken |
| 520 | 529 | ||
| 521 | // Basic Authentication (loyalty headers + Authorization: Basic) | 530 | // Basic Authentication (loyalty headers + Authorization: Basic) | ... | ... |
| ... | @@ -1084,6 +1084,20 @@ extension NetworkService { | ... | @@ -1084,6 +1084,20 @@ extension NetworkService { |
| 1084 | return response | 1084 | return response |
| 1085 | } | 1085 | } |
| 1086 | 1086 | ||
| 1087 | + /// Retrieve a coupon from a coupon set | ||
| 1088 | + /// - Parameter couponSetUuid: The UUID of the coupon set (offer) to retrieve a coupon from | ||
| 1089 | + /// - Returns: Response dictionary containing the retrieved coupon code and expiration | ||
| 1090 | + /// - Throws: NetworkError if request fails | ||
| 1091 | + public func retrieveCoupon(couponSetUuid: String) async throws -> [String: Any] { | ||
| 1092 | + print("🔄 [NetworkService] Retrieving coupon for coupon set: \(couponSetUuid)") | ||
| 1093 | + let endpoint = Endpoint.retrieveCoupon(couponSetUuid: couponSetUuid) | ||
| 1094 | + let response = try await requestRaw(endpoint) | ||
| 1095 | + | ||
| 1096 | + print("✅ [NetworkService] Coupon retrieval request completed") | ||
| 1097 | + | ||
| 1098 | + return response | ||
| 1099 | + } | ||
| 1100 | + | ||
| 1087 | // MARK: - Card Security Utilities | 1101 | // MARK: - Card Security Utilities |
| 1088 | 1102 | ||
| 1089 | /// Mask card number for secure logging | 1103 | /// Mask card number for secure logging | ... | ... |
| 1 | <?xml version="1.0" encoding="UTF-8"?> | 1 | <?xml version="1.0" encoding="UTF-8"?> |
| 2 | -<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23094" 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 | <device id="retina6_12" orientation="portrait" appearance="light"/> |
| 4 | <dependencies> | 4 | <dependencies> |
| 5 | - <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23084"/> | 5 | + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="24504"/> |
| 6 | <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"/> | 7 | <capability name="System colors in document resources" minToolsVersion="11.0"/> |
| 8 | <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"/> |
| ... | @@ -55,10 +55,10 @@ | ... | @@ -55,10 +55,10 @@ |
| 55 | <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> | 55 | <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> |
| 56 | <subviews> | 56 | <subviews> |
| 57 | <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="XaT-fU-eNh" userLabel="Main View"> | 57 | <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="XaT-fU-eNh" userLabel="Main View"> |
| 58 | - <rect key="frame" x="0.0" y="59" width="393" height="793"/> | 58 | + <rect key="frame" x="0.0" y="118" width="393" height="734"/> |
| 59 | <subviews> | 59 | <subviews> |
| 60 | <scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" translatesAutoresizingMaskIntoConstraints="NO" id="YpC-uS-mhw"> | 60 | <scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" translatesAutoresizingMaskIntoConstraints="NO" id="YpC-uS-mhw"> |
| 61 | - <rect key="frame" x="0.0" y="0.0" width="393" height="793"/> | 61 | + <rect key="frame" x="0.0" y="0.0" width="393" height="734"/> |
| 62 | <subviews> | 62 | <subviews> |
| 63 | <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="qrm-40-JLT" userLabel="Scroll Content View"> | 63 | <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="qrm-40-JLT" userLabel="Scroll Content View"> |
| 64 | <rect key="frame" x="0.0" y="0.0" width="393" height="1177"/> | 64 | <rect key="frame" x="0.0" y="0.0" width="393" height="1177"/> |
| ... | @@ -74,14 +74,14 @@ | ... | @@ -74,14 +74,14 @@ |
| 74 | <rect key="frame" x="239" y="17" width="138" height="20.666666666666671"/> | 74 | <rect key="frame" x="239" y="17" width="138" height="20.666666666666671"/> |
| 75 | <subviews> | 75 | <subviews> |
| 76 | <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="tFA-1H-T5S" userLabel="Info Image View"> | 76 | <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="tFA-1H-T5S" userLabel="Info Image View"> |
| 77 | - <rect key="frame" x="10" y="3.6666666666666723" width="13.666666666666664" height="13.333333333333336"/> | 77 | + <rect key="frame" x="10" y="3.6666666666666581" width="13.666666666666664" height="13.333333333333336"/> |
| 78 | <constraints> | 78 | <constraints> |
| 79 | <constraint firstAttribute="height" constant="13.5" id="uQt-vY-kbk"/> | 79 | <constraint firstAttribute="height" constant="13.5" id="uQt-vY-kbk"/> |
| 80 | <constraint firstAttribute="width" constant="13.5" id="yzR-99-6Vp"/> | 80 | <constraint firstAttribute="width" constant="13.5" id="yzR-99-6Vp"/> |
| 81 | </constraints> | 81 | </constraints> |
| 82 | </imageView> | 82 | </imageView> |
| 83 | <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Περισσότερα" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="K34-LM-bC1" userLabel="Info Label"> | 83 | <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Περισσότερα" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="K34-LM-bC1" userLabel="Info Label"> |
| 84 | - <rect key="frame" x="28" y="-0.3333333333333286" width="100" height="21"/> | 84 | + <rect key="frame" x="28" y="-0.33333333333334281" width="100" height="21"/> |
| 85 | <fontDescription key="fontDescription" type="system" pointSize="17"/> | 85 | <fontDescription key="fontDescription" type="system" pointSize="17"/> |
| 86 | <nil key="textColor"/> | 86 | <nil key="textColor"/> |
| 87 | <nil key="highlightedColor"/> | 87 | <nil key="highlightedColor"/> |
| ... | @@ -144,7 +144,7 @@ | ... | @@ -144,7 +144,7 @@ |
| 144 | <rect key="frame" x="0.0" y="0.0" width="345" height="54.333333333333336"/> | 144 | <rect key="frame" x="0.0" y="0.0" width="345" height="54.333333333333336"/> |
| 145 | <subviews> | 145 | <subviews> |
| 146 | <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="lEF-bh-hOi" userLabel="CouponCodeTitleLabel"> | 146 | <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="lEF-bh-hOi" userLabel="CouponCodeTitleLabel"> |
| 147 | - <rect key="frame" x="17" y="17" width="277" height="20.333333333333329"/> | 147 | + <rect key="frame" x="17" y="17.000000000000057" width="277" height="20.333333333333329"/> |
| 148 | <fontDescription key="fontDescription" type="system" pointSize="17"/> | 148 | <fontDescription key="fontDescription" type="system" pointSize="17"/> |
| 149 | <nil key="textColor"/> | 149 | <nil key="textColor"/> |
| 150 | <nil key="highlightedColor"/> | 150 | <nil key="highlightedColor"/> |
| ... | @@ -181,16 +181,16 @@ | ... | @@ -181,16 +181,16 @@ |
| 181 | </constraints> | 181 | </constraints> |
| 182 | </view> | 182 | </view> |
| 183 | <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="wT1-HY-mg9" userLabel="CouponCodeContentView"> | 183 | <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="wT1-HY-mg9" userLabel="CouponCodeContentView"> |
| 184 | - <rect key="frame" x="0.0" y="54.333333333333371" width="345" height="80"/> | 184 | + <rect key="frame" x="0.0" y="54.333333333333314" width="345" height="80"/> |
| 185 | <subviews> | 185 | <subviews> |
| 186 | <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="2Fn-5d-j8v" userLabel="CouponCodeValueLabel"> | 186 | <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="2Fn-5d-j8v" userLabel="CouponCodeValueLabel"> |
| 187 | - <rect key="frame" x="16.999999999999996" y="25.999999999999943" width="56.666666666666657" height="28"/> | 187 | + <rect key="frame" x="16.999999999999996" y="26" width="56.666666666666657" height="28"/> |
| 188 | <fontDescription key="fontDescription" type="system" pointSize="24"/> | 188 | <fontDescription key="fontDescription" type="system" pointSize="24"/> |
| 189 | <nil key="textColor"/> | 189 | <nil key="textColor"/> |
| 190 | <nil key="highlightedColor"/> | 190 | <nil key="highlightedColor"/> |
| 191 | </label> | 191 | </label> |
| 192 | <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="AXc-Yh-5Ek" userLabel="CopyButtonImage"> | 192 | <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="AXc-Yh-5Ek" userLabel="CopyButtonImage"> |
| 193 | - <rect key="frame" x="84.666666666666671" y="23.666666666666686" width="33" height="33"/> | 193 | + <rect key="frame" x="84.666666666666671" y="23.666666666666742" width="33" height="33"/> |
| 194 | <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> | 194 | <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> |
| 195 | <constraints> | 195 | <constraints> |
| 196 | <constraint firstAttribute="height" constant="33" id="7ds-Ao-fBn"/> | 196 | <constraint firstAttribute="height" constant="33" id="7ds-Ao-fBn"/> |
| ... | @@ -318,7 +318,7 @@ | ... | @@ -318,7 +318,7 @@ |
| 318 | <nil key="highlightedColor"/> | 318 | <nil key="highlightedColor"/> |
| 319 | </label> | 319 | </label> |
| 320 | <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="C8k-TU-LiL" userLabel="TermsButtonArrowImage"> | 320 | <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="C8k-TU-LiL" userLabel="TermsButtonArrowImage"> |
| 321 | - <rect key="frame" x="109.33333333333334" y="15" width="9" height="5"/> | 321 | + <rect key="frame" x="109.33333333333334" y="15.000000000000114" width="9" height="5"/> |
| 322 | <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> | 322 | <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> |
| 323 | <constraints> | 323 | <constraints> |
| 324 | <constraint firstAttribute="height" constant="5" id="ERb-FD-j0Y"/> | 324 | <constraint firstAttribute="height" constant="5" id="ERb-FD-j0Y"/> |
| ... | @@ -349,7 +349,7 @@ | ... | @@ -349,7 +349,7 @@ |
| 349 | </constraints> | 349 | </constraints> |
| 350 | </view> | 350 | </view> |
| 351 | <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Ak8-Tc-k8X" userLabel="TermsLabel"> | 351 | <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Ak8-Tc-k8X" userLabel="TermsLabel"> |
| 352 | - <rect key="frame" x="24" y="940.66666666666663" width="345" height="20.333333333333371"/> | 352 | + <rect key="frame" x="24" y="940.66666666666674" width="345" height="20.333333333333371"/> |
| 353 | <constraints> | 353 | <constraints> |
| 354 | <constraint firstAttribute="height" constant="20.329999999999998" id="ZA1-TX-m9Y"/> | 354 | <constraint firstAttribute="height" constant="20.329999999999998" id="ZA1-TX-m9Y"/> |
| 355 | </constraints> | 355 | </constraints> | ... | ... |
| ... | @@ -42,9 +42,7 @@ import UIKit | ... | @@ -42,9 +42,7 @@ import UIKit |
| 42 | @IBOutlet weak var termsLabel: UILabel! | 42 | @IBOutlet weak var termsLabel: UILabel! |
| 43 | @IBOutlet weak var termsLabelHeight: NSLayoutConstraint! | 43 | @IBOutlet weak var termsLabelHeight: NSLayoutConstraint! |
| 44 | 44 | ||
| 45 | - @IBOutlet weak var mapButton: UIButton! | 45 | + @IBOutlet weak var redeemButton: UIButton! |
| 46 | - | ||
| 47 | - @IBOutlet weak var websiteButton: UIButton! | ||
| 48 | 46 | ||
| 49 | var couponset: CouponSetItemModel? | 47 | var couponset: CouponSetItemModel? |
| 50 | private var isDetailsExpanded = false | 48 | private var isDetailsExpanded = false |
| ... | @@ -52,6 +50,9 @@ import UIKit | ... | @@ -52,6 +50,9 @@ import UIKit |
| 52 | private var isCouponQRExpanded = false | 50 | private var isCouponQRExpanded = false |
| 53 | private var isTermsExpanded = false | 51 | private var isTermsExpanded = false |
| 54 | 52 | ||
| 53 | + // Loader overlay | ||
| 54 | + private var loaderOverlay: UIView? | ||
| 55 | + | ||
| 55 | var postImageURL: String? { | 56 | var postImageURL: String? { |
| 56 | didSet { | 57 | didSet { |
| 57 | if let url = postImageURL { | 58 | if let url = postImageURL { |
| ... | @@ -97,21 +98,13 @@ import UIKit | ... | @@ -97,21 +98,13 @@ import UIKit |
| 97 | termsButton.addTarget(self, action: #selector(toggleTerms), for: .touchUpInside) | 98 | termsButton.addTarget(self, action: #selector(toggleTerms), for: .touchUpInside) |
| 98 | termsLabelHeight.constant = 0 | 99 | termsLabelHeight.constant = 0 |
| 99 | 100 | ||
| 100 | - mapButton.titleLabel?.font = UIFont(name: "PingLCG-Bold", size: 16) | 101 | + redeemButton.titleLabel?.font = UIFont(name: "PingLCG-Bold", size: 16) |
| 101 | - mapButton.setTitle("Καταστήματα κοντά μου", for: .normal) | 102 | + redeemButton.setTitle("Απόκτησε το κουπόνι", for: .normal) |
| 102 | - mapButton.setTitleColor(UIColor(rgb: 0xFFFFFF), for: .normal) | 103 | + redeemButton.setTitleColor(UIColor(rgb: 0xFFFFFF), for: .normal) |
| 103 | - mapButton.setTitleColor(UIColor(rgb: 0xFFFFFF), for: .highlighted) | 104 | + redeemButton.setTitleColor(UIColor(rgb: 0xFFFFFF), for: .highlighted) |
| 104 | - mapButton.layer.cornerRadius = 4.0 | 105 | + redeemButton.layer.cornerRadius = 4.0 |
| 105 | - mapButton.backgroundColor = UIColor(rgb: 0x000F1E) | 106 | + redeemButton.backgroundColor = UIColor(rgb: 0x000F1E) |
| 106 | - | 107 | + redeemButton.addTarget(self, action: #selector(redeemButtonTapped), for: .touchUpInside) |
| 107 | - websiteButton.titleLabel?.font = UIFont(name: "PingLCG-Bold", size: 16) | ||
| 108 | - websiteButton.setTitle("Δες το website", for: .normal) | ||
| 109 | - websiteButton.setTitleColor(UIColor(rgb: 0x000F1E), for: .normal) | ||
| 110 | - websiteButton.setTitleColor(UIColor(rgb: 0x000F1E), for: .highlighted) | ||
| 111 | - websiteButton.backgroundColor = .clear | ||
| 112 | - websiteButton.layer.borderWidth = 1 | ||
| 113 | - websiteButton.layer.borderColor = UIColor(rgb: 0x000F1E).cgColor | ||
| 114 | - websiteButton.layer.cornerRadius = 4.0 | ||
| 115 | 108 | ||
| 116 | // Configure the view with offer data | 109 | // Configure the view with offer data |
| 117 | if let offer = couponset { | 110 | if let offer = couponset { |
| ... | @@ -119,6 +112,79 @@ import UIKit | ... | @@ -119,6 +112,79 @@ import UIKit |
| 119 | } | 112 | } |
| 120 | } | 113 | } |
| 121 | 114 | ||
| 115 | + @objc private func redeemButtonTapped() { | ||
| 116 | + guard let couponSetUuid = couponset?._uuid, !couponSetUuid.isEmpty else { | ||
| 117 | + showErrorAlert(message: "Δεν βρέθηκε το αναγνωριστικό της προσφοράς.") | ||
| 118 | + return | ||
| 119 | + } | ||
| 120 | + | ||
| 121 | + // Disable button to prevent double taps | ||
| 122 | + redeemButton.isEnabled = false | ||
| 123 | + showLoader() | ||
| 124 | + | ||
| 125 | + WarplySDK.shared.retrieveCoupon(couponSetUuid: couponSetUuid, completion: { [weak self] response in | ||
| 126 | + guard let self = self else { return } | ||
| 127 | + self.hideLoader() | ||
| 128 | + self.redeemButton.isEnabled = true | ||
| 129 | + | ||
| 130 | + if let response = response, | ||
| 131 | + let result = response["result"] as? [String: Any], | ||
| 132 | + let couponCode = result["coupon"] as? String { | ||
| 133 | + let expiration = result["expiration"] as? String ?? "" | ||
| 134 | + self.showSuccessAlert(couponCode: couponCode, expiration: expiration) | ||
| 135 | + } else { | ||
| 136 | + self.showErrorAlert(message: "Η ενεργοποίηση του κουπονιού απέτυχε. Παρακαλώ δοκίμασε ξανά.") | ||
| 137 | + } | ||
| 138 | + }, failureCallback: { [weak self] errorCode in | ||
| 139 | + guard let self = self else { return } | ||
| 140 | + self.hideLoader() | ||
| 141 | + self.redeemButton.isEnabled = true | ||
| 142 | + self.showErrorAlert(message: "Η ενεργοποίηση του κουπονιού απέτυχε. Παρακαλώ δοκίμασε ξανά.") | ||
| 143 | + }) | ||
| 144 | + } | ||
| 145 | + | ||
| 146 | + // MARK: - Loader | ||
| 147 | + | ||
| 148 | + private func showLoader() { | ||
| 149 | + let overlay = UIView(frame: self.view.bounds) | ||
| 150 | + overlay.backgroundColor = UIColor.black.withAlphaComponent(0.3) | ||
| 151 | + overlay.autoresizingMask = [.flexibleWidth, .flexibleHeight] | ||
| 152 | + | ||
| 153 | + let spinner = UIActivityIndicatorView(style: .large) | ||
| 154 | + spinner.color = .white | ||
| 155 | + spinner.center = overlay.center | ||
| 156 | + spinner.autoresizingMask = [.flexibleTopMargin, .flexibleBottomMargin, .flexibleLeftMargin, .flexibleRightMargin] | ||
| 157 | + spinner.startAnimating() | ||
| 158 | + | ||
| 159 | + overlay.addSubview(spinner) | ||
| 160 | + self.view.addSubview(overlay) | ||
| 161 | + self.loaderOverlay = overlay | ||
| 162 | + } | ||
| 163 | + | ||
| 164 | + private func hideLoader() { | ||
| 165 | + loaderOverlay?.removeFromSuperview() | ||
| 166 | + loaderOverlay = nil | ||
| 167 | + } | ||
| 168 | + | ||
| 169 | + // MARK: - Alerts | ||
| 170 | + | ||
| 171 | + private func showSuccessAlert(couponCode: String, expiration: String) { | ||
| 172 | + var message = "Ο κωδικός κουπονιού σου:\n\(couponCode)" | ||
| 173 | + if !expiration.isEmpty { | ||
| 174 | + message += "\n\nΛήξη: \(expiration)" | ||
| 175 | + } | ||
| 176 | + | ||
| 177 | + let alert = UIAlertController(title: "Επιτυχία", message: message, preferredStyle: .alert) | ||
| 178 | + alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil)) | ||
| 179 | + present(alert, animated: true, completion: nil) | ||
| 180 | + } | ||
| 181 | + | ||
| 182 | + private func showErrorAlert(message: String) { | ||
| 183 | + let alert = UIAlertController(title: "Σφάλμα", message: message, preferredStyle: .alert) | ||
| 184 | + alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil)) | ||
| 185 | + present(alert, animated: true, completion: nil) | ||
| 186 | + } | ||
| 187 | + | ||
| 122 | private func setupUI(with couponset: CouponSetItemModel) { | 188 | private func setupUI(with couponset: CouponSetItemModel) { |
| 123 | // couponImage.image = UIImage(named: couponset._img_preview, in: Bundle.frameworkResourceBundle, compatibleWith: nil) | 189 | // couponImage.image = UIImage(named: couponset._img_preview, in: Bundle.frameworkResourceBundle, compatibleWith: nil) |
| 124 | self.postImageURL = couponset._img_preview | 190 | self.postImageURL = couponset._img_preview | ... | ... |
| ... | @@ -17,7 +17,7 @@ | ... | @@ -17,7 +17,7 @@ |
| 17 | <outlet property="infoImage" destination="RK8-R9-SZK" id="ZjM-PX-DgT"/> | 17 | <outlet property="infoImage" destination="RK8-R9-SZK" id="ZjM-PX-DgT"/> |
| 18 | <outlet property="infoLabel" destination="oln-Zl-Mu1" id="OZb-dV-dlF"/> | 18 | <outlet property="infoLabel" destination="oln-Zl-Mu1" id="OZb-dV-dlF"/> |
| 19 | <outlet property="infoView" destination="raJ-sJ-NGX" id="fol-KV-D65"/> | 19 | <outlet property="infoView" destination="raJ-sJ-NGX" id="fol-KV-D65"/> |
| 20 | - <outlet property="mapButton" destination="bTa-jT-Ufb" id="gH0-yo-in7"/> | 20 | + <outlet property="redeemButton" destination="bTa-jT-Ufb" id="zz9-GB-5CD"/> |
| 21 | <outlet property="shareImage" destination="a1t-wH-dMg" id="Viw-KD-1JB"/> | 21 | <outlet property="shareImage" destination="a1t-wH-dMg" id="Viw-KD-1JB"/> |
| 22 | <outlet property="subtitleLabel" destination="iWC-mi-WKw" id="peM-oa-eSS"/> | 22 | <outlet property="subtitleLabel" destination="iWC-mi-WKw" id="peM-oa-eSS"/> |
| 23 | <outlet property="termsButton" destination="eGV-3B-aQo" id="Y0X-hP-SDU"/> | 23 | <outlet property="termsButton" destination="eGV-3B-aQo" id="Y0X-hP-SDU"/> |
| ... | @@ -28,7 +28,6 @@ | ... | @@ -28,7 +28,6 @@ |
| 28 | <outlet property="termsLabelHeight" destination="9VB-9j-Q79" id="G0C-tp-L7M"/> | 28 | <outlet property="termsLabelHeight" destination="9VB-9j-Q79" id="G0C-tp-L7M"/> |
| 29 | <outlet property="titleLabel" destination="aSO-pm-a0W" id="uyw-AX-ElA"/> | 29 | <outlet property="titleLabel" destination="aSO-pm-a0W" id="uyw-AX-ElA"/> |
| 30 | <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/> | 30 | <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/> |
| 31 | - <outlet property="websiteButton" destination="lU8-hR-MF0" id="cj6-X8-D8Z"/> | ||
| 32 | </connections> | 31 | </connections> |
| 33 | </placeholder> | 32 | </placeholder> |
| 34 | <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/> | 33 | <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/> |
| ... | @@ -102,7 +101,7 @@ | ... | @@ -102,7 +101,7 @@ |
| 102 | </constraints> | 101 | </constraints> |
| 103 | </imageView> | 102 | </imageView> |
| 104 | <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="iWC-mi-WKw" userLabel="Subtitle Label"> | 103 | <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="iWC-mi-WKw" userLabel="Subtitle Label"> |
| 105 | - <rect key="frame" x="24" y="254.33333333333337" width="345" height="20.333333333333258"/> | 104 | + <rect key="frame" x="24" y="254.33333333333334" width="345" height="20.333333333333286"/> |
| 106 | <fontDescription key="fontDescription" type="system" pointSize="17"/> | 105 | <fontDescription key="fontDescription" type="system" pointSize="17"/> |
| 107 | <nil key="textColor"/> | 106 | <nil key="textColor"/> |
| 108 | <nil key="highlightedColor"/> | 107 | <nil key="highlightedColor"/> |
| ... | @@ -120,7 +119,7 @@ | ... | @@ -120,7 +119,7 @@ |
| 120 | <nil key="highlightedColor"/> | 119 | <nil key="highlightedColor"/> |
| 121 | </label> | 120 | </label> |
| 122 | <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="12M-YC-Cox" userLabel="TermsButtonView"> | 121 | <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="12M-YC-Cox" userLabel="TermsButtonView"> |
| 123 | - <rect key="frame" x="23.999999999999993" y="452.66666666666663" width="123.33333333333331" height="35"/> | 122 | + <rect key="frame" x="23.999999999999993" y="527.66666666666663" width="123.33333333333331" height="35"/> |
| 124 | <subviews> | 123 | <subviews> |
| 125 | <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Όροι Χρήσης" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="uSf-AS-iFa" userLabel="TermsButtonTitleLabel"> | 124 | <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Όροι Χρήσης" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="uSf-AS-iFa" userLabel="TermsButtonTitleLabel"> |
| 126 | <rect key="frame" x="0.0" y="5" width="101.33333333333333" height="25"/> | 125 | <rect key="frame" x="0.0" y="5" width="101.33333333333333" height="25"/> |
| ... | @@ -160,7 +159,7 @@ | ... | @@ -160,7 +159,7 @@ |
| 160 | </constraints> | 159 | </constraints> |
| 161 | </view> | 160 | </view> |
| 162 | <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="jug-xV-lmv" userLabel="TermsLabel"> | 161 | <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="jug-xV-lmv" userLabel="TermsLabel"> |
| 163 | - <rect key="frame" x="24" y="497.66666666666663" width="345" height="20.333333333333371"/> | 162 | + <rect key="frame" x="24" y="572.66666666666663" width="345" height="20.333333333333371"/> |
| 164 | <constraints> | 163 | <constraints> |
| 165 | <constraint firstAttribute="height" constant="20.329999999999998" id="9VB-9j-Q79"/> | 164 | <constraint firstAttribute="height" constant="20.329999999999998" id="9VB-9j-Q79"/> |
| 166 | </constraints> | 165 | </constraints> |
| ... | @@ -168,18 +167,10 @@ | ... | @@ -168,18 +167,10 @@ |
| 168 | <nil key="textColor"/> | 167 | <nil key="textColor"/> |
| 169 | <nil key="highlightedColor"/> | 168 | <nil key="highlightedColor"/> |
| 170 | </label> | 169 | </label> |
| 171 | - <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="bTa-jT-Ufb" userLabel="MapButton"> | 170 | + <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="bTa-jT-Ufb" userLabel="RedeemButton"> |
| 172 | - <rect key="frame" x="24" y="558" width="345" height="55"/> | ||
| 173 | - <constraints> | ||
| 174 | - <constraint firstAttribute="height" constant="55" id="5AV-zY-O6v"/> | ||
| 175 | - </constraints> | ||
| 176 | - <state key="normal" title="Button"/> | ||
| 177 | - <buttonConfiguration key="configuration" style="plain" title="Button"/> | ||
| 178 | - </button> | ||
| 179 | - <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="lU8-hR-MF0" userLabel="WebsiteButton"> | ||
| 180 | <rect key="frame" x="24" y="633" width="345" height="55"/> | 171 | <rect key="frame" x="24" y="633" width="345" height="55"/> |
| 181 | <constraints> | 172 | <constraints> |
| 182 | - <constraint firstAttribute="height" constant="55" id="aeV-F1-tWk"/> | 173 | + <constraint firstAttribute="height" constant="55" id="5AV-zY-O6v"/> |
| 183 | </constraints> | 174 | </constraints> |
| 184 | <state key="normal" title="Button"/> | 175 | <state key="normal" title="Button"/> |
| 185 | <buttonConfiguration key="configuration" style="plain" title="Button"/> | 176 | <buttonConfiguration key="configuration" style="plain" title="Button"/> |
| ... | @@ -192,7 +183,6 @@ | ... | @@ -192,7 +183,6 @@ |
| 192 | <constraint firstAttribute="trailing" secondItem="50f-Uw-WmD" secondAttribute="trailing" id="5vF-D2-mBO"/> | 183 | <constraint firstAttribute="trailing" secondItem="50f-Uw-WmD" secondAttribute="trailing" id="5vF-D2-mBO"/> |
| 193 | <constraint firstItem="12M-YC-Cox" firstAttribute="top" secondItem="tOt-gP-Et5" secondAttribute="bottom" constant="50" id="6cC-FH-1Xw"/> | 184 | <constraint firstItem="12M-YC-Cox" firstAttribute="top" secondItem="tOt-gP-Et5" secondAttribute="bottom" constant="50" id="6cC-FH-1Xw"/> |
| 194 | <constraint firstItem="50f-Uw-WmD" firstAttribute="leading" secondItem="mci-HQ-9iu" secondAttribute="leading" id="7Rd-U6-d9j"/> | 185 | <constraint firstItem="50f-Uw-WmD" firstAttribute="leading" secondItem="mci-HQ-9iu" secondAttribute="leading" id="7Rd-U6-d9j"/> |
| 195 | - <constraint firstItem="lU8-hR-MF0" firstAttribute="leading" secondItem="mci-HQ-9iu" secondAttribute="leading" constant="24" id="9R6-Lj-xSo"/> | ||
| 196 | <constraint firstItem="aSO-pm-a0W" firstAttribute="leading" secondItem="mci-HQ-9iu" secondAttribute="leading" constant="24" id="BIn-gA-oSw"/> | 186 | <constraint firstItem="aSO-pm-a0W" firstAttribute="leading" secondItem="mci-HQ-9iu" secondAttribute="leading" constant="24" id="BIn-gA-oSw"/> |
| 197 | <constraint firstItem="a1t-wH-dMg" firstAttribute="leading" secondItem="kQb-LM-Zaa" secondAttribute="trailing" constant="11" id="DlZ-NN-vE2"/> | 187 | <constraint firstItem="a1t-wH-dMg" firstAttribute="leading" secondItem="kQb-LM-Zaa" secondAttribute="trailing" constant="11" id="DlZ-NN-vE2"/> |
| 198 | <constraint firstItem="12M-YC-Cox" firstAttribute="leading" secondItem="mci-HQ-9iu" secondAttribute="leading" constant="24" id="Eal-pm-W9t"/> | 188 | <constraint firstItem="12M-YC-Cox" firstAttribute="leading" secondItem="mci-HQ-9iu" secondAttribute="leading" constant="24" id="Eal-pm-W9t"/> |
| ... | @@ -211,12 +201,10 @@ | ... | @@ -211,12 +201,10 @@ |
| 211 | <constraint firstItem="a1t-wH-dMg" firstAttribute="top" secondItem="50f-Uw-WmD" secondAttribute="bottom" constant="17" id="bSw-JI-jDV"/> | 201 | <constraint firstItem="a1t-wH-dMg" firstAttribute="top" secondItem="50f-Uw-WmD" secondAttribute="bottom" constant="17" id="bSw-JI-jDV"/> |
| 212 | <constraint firstItem="iWC-mi-WKw" firstAttribute="leading" secondItem="mci-HQ-9iu" secondAttribute="leading" constant="24" id="dMq-cH-vOX"/> | 202 | <constraint firstItem="iWC-mi-WKw" firstAttribute="leading" secondItem="mci-HQ-9iu" secondAttribute="leading" constant="24" id="dMq-cH-vOX"/> |
| 213 | <constraint firstItem="raJ-sJ-NGX" firstAttribute="top" secondItem="mci-HQ-9iu" secondAttribute="top" constant="17" id="g7b-Ql-ifv"/> | 203 | <constraint firstItem="raJ-sJ-NGX" firstAttribute="top" secondItem="mci-HQ-9iu" secondAttribute="top" constant="17" id="g7b-Ql-ifv"/> |
| 214 | - <constraint firstItem="lU8-hR-MF0" firstAttribute="top" secondItem="bTa-jT-Ufb" secondAttribute="bottom" constant="20" id="hGL-sc-uEw"/> | ||
| 215 | <constraint firstItem="aSO-pm-a0W" firstAttribute="top" secondItem="50f-Uw-WmD" secondAttribute="bottom" constant="23" id="jvc-rb-E6b"/> | 204 | <constraint firstItem="aSO-pm-a0W" firstAttribute="top" secondItem="50f-Uw-WmD" secondAttribute="bottom" constant="23" id="jvc-rb-E6b"/> |
| 216 | <constraint firstItem="tOt-gP-Et5" firstAttribute="top" secondItem="PZ8-Go-A85" secondAttribute="bottom" constant="20" id="kQ3-4v-3Jp"/> | 205 | <constraint firstItem="tOt-gP-Et5" firstAttribute="top" secondItem="PZ8-Go-A85" secondAttribute="bottom" constant="20" id="kQ3-4v-3Jp"/> |
| 217 | <constraint firstItem="jug-xV-lmv" firstAttribute="top" secondItem="12M-YC-Cox" secondAttribute="bottom" constant="9.9999999999998863" id="kSx-qT-pPa"/> | 206 | <constraint firstItem="jug-xV-lmv" firstAttribute="top" secondItem="12M-YC-Cox" secondAttribute="bottom" constant="9.9999999999998863" id="kSx-qT-pPa"/> |
| 218 | - <constraint firstAttribute="bottom" secondItem="lU8-hR-MF0" secondAttribute="bottom" constant="46" id="l1j-ca-Uq9"/> | 207 | + <constraint firstAttribute="bottom" secondItem="bTa-jT-Ufb" secondAttribute="bottom" constant="46" id="l42-O3-RQt"/> |
| 219 | - <constraint firstAttribute="trailing" secondItem="lU8-hR-MF0" secondAttribute="trailing" constant="24" id="lEm-My-Oi9"/> | ||
| 220 | <constraint firstItem="bTa-jT-Ufb" firstAttribute="leading" secondItem="mci-HQ-9iu" secondAttribute="leading" constant="24" id="nR2-Py-LTi"/> | 208 | <constraint firstItem="bTa-jT-Ufb" firstAttribute="leading" secondItem="mci-HQ-9iu" secondAttribute="leading" constant="24" id="nR2-Py-LTi"/> |
| 221 | <constraint firstItem="jug-xV-lmv" firstAttribute="leading" secondItem="mci-HQ-9iu" secondAttribute="leading" constant="24" id="oUa-cz-J7N"/> | 209 | <constraint firstItem="jug-xV-lmv" firstAttribute="leading" secondItem="mci-HQ-9iu" secondAttribute="leading" constant="24" id="oUa-cz-J7N"/> |
| 222 | <constraint firstItem="tOt-gP-Et5" firstAttribute="leading" secondItem="mci-HQ-9iu" secondAttribute="leading" constant="24" id="xz5-C4-0GD"/> | 210 | <constraint firstItem="tOt-gP-Et5" firstAttribute="leading" secondItem="mci-HQ-9iu" secondAttribute="leading" constant="24" id="xz5-C4-0GD"/> | ... | ... |
-
Please register or login to post a comment