From 956f6047f95c31209162dbf6a28ff70646aaadb5 Mon Sep 17 00:00:00 2001 From: Aishwarya Nanna Date: Wed, 12 Apr 2023 03:06:17 +0530 Subject: [PATCH 1/3] - Added optional progress view in Timer template --- .../CTTimerTemplateController.swift | 56 +++++++++++++++---- .../Timer/Model/TimerTemplateProperties.swift | 18 +++++- .../Templates/Utility/GlobalConstants.swift | 1 + 3 files changed, 64 insertions(+), 11 deletions(-) diff --git a/CTNotificationContent/Templates/Timer/Controller/CTTimerTemplateController.swift b/CTNotificationContent/Templates/Timer/Controller/CTTimerTemplateController.swift index 516083d..3d86baa 100644 --- a/CTNotificationContent/Templates/Timer/Controller/CTTimerTemplateController.swift +++ b/CTNotificationContent/Templates/Timer/Controller/CTTimerTemplateController.swift @@ -14,6 +14,7 @@ import UserNotificationsUI var jsonContent: TimerTemplateProperties? = nil var timer: Timer = Timer() var thresholdSeconds = 0 + var progressViewHeight: CGFloat = 0.0 private var imageView: UIImageView = { let imageView = UIImageView() imageView.contentMode = .scaleAspectFit @@ -49,6 +50,12 @@ import UserNotificationsUI timerLabel.translatesAutoresizingMaskIntoConstraints = false return timerLabel }() + private var timerProgressView: UIProgressView = { + let timerProgressView = UIProgressView() + timerProgressView.setProgress(0.0, animated: true) + timerProgressView.translatesAutoresizingMaskIntoConstraints = false + return timerProgressView + }() @objc public override func viewDidLoad() { super.viewDidLoad() @@ -73,6 +80,7 @@ import UserNotificationsUI contentView.addSubview(captionLabel) contentView.addSubview(subcaptionLabel) contentView.addSubview(timerLabel) + contentView.addSubview(timerProgressView) captionLabel.text = templateCaption subcaptionLabel.text = templateSubcaption @@ -128,7 +136,19 @@ import UserNotificationsUI } } } + if let timerProgressView = jsonContent.pt_timer_progress_view, timerProgressView{ + if thresholdSeconds > 0 { + // Load progress view only if timer is not ended. + progressViewHeight = Constraints.kProgressViewHeight + self.activateProgressViewContraints() + self.createFrameWithoutImage() + } + } + if let timerProgressClr = jsonContent.pt_timer_progress_clr, !timerProgressClr.isEmpty { + timerProgressView.progressTintColor = UIColor(hex: timerProgressClr) + } + view.backgroundColor = UIColor(hex: bgColor) imageView.backgroundColor = UIColor(hex: bgColor) captionLabel.textColor = UIColor(hex: captionColor) @@ -138,21 +158,21 @@ import UserNotificationsUI func setupConstraints() { NSLayoutConstraint.activate([ - captionLabel.topAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -(CTUtiltiy.getCaptionHeight() - Constraints.kCaptionTopPadding)), + captionLabel.topAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -(CTUtiltiy.getCaptionHeight() - Constraints.kCaptionTopPadding + progressViewHeight)), captionLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: Constraints.kCaptionLeftPadding), captionLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -Constraints.kTimerLabelWidth), captionLabel.heightAnchor.constraint(equalToConstant: Constraints.kCaptionHeight), - subcaptionLabel.topAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -(Constraints.kSubCaptionHeight + Constraints.kSubCaptionTopPadding)), + subcaptionLabel.topAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -(Constraints.kSubCaptionHeight + Constraints.kSubCaptionTopPadding + progressViewHeight)), subcaptionLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: Constraints.kCaptionLeftPadding), subcaptionLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -Constraints.kTimerLabelWidth), - subcaptionLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -Constraints.kSubCaptionTopPadding), + subcaptionLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -(Constraints.kSubCaptionTopPadding + progressViewHeight)), subcaptionLabel.heightAnchor.constraint(equalToConstant: Constraints.kSubCaptionHeight), - timerLabel.topAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -CTUtiltiy.getCaptionHeight()), + timerLabel.topAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -(CTUtiltiy.getCaptionHeight() + progressViewHeight)), timerLabel.leadingAnchor.constraint(equalTo: captionLabel.trailingAnchor, constant: Constraints.kCaptionLeftPadding), timerLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -Constraints.kCaptionLeftPadding), - timerLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -Constraints.kSubCaptionTopPadding), + timerLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -(Constraints.kSubCaptionTopPadding + progressViewHeight)), timerLabel.heightAnchor.constraint(equalToConstant: CTUtiltiy.getCaptionHeight()) ]) } @@ -168,6 +188,9 @@ import UserNotificationsUI else { self.timerLabel.text = String(format: "%02i:%02i:%02i", hr, min, sec) } + if let progressView = jsonContent?.pt_timer_progress_view, progressView{ + timerProgressView.setProgress(Float(thresholdSeconds), animated: true) + } thresholdSeconds -= 1 } else { timer.invalidate() @@ -178,6 +201,10 @@ import UserNotificationsUI func updateViewForExpiredTime() { if let jsonContent = jsonContent { + if let progressView = jsonContent.pt_timer_progress_view, progressView{ + timerProgressView.removeFromSuperview() + } + if let title = jsonContent.pt_title_alt, !title.isEmpty { captionLabel.text = title } @@ -201,7 +228,7 @@ import UserNotificationsUI func createFrameWithoutImage() { let viewWidth = view.frame.size.width - let viewHeight = CTUtiltiy.getCaptionHeight() + let viewHeight = CTUtiltiy.getCaptionHeight() + progressViewHeight let frame: CGRect = CGRect(x: 0, y: 0, width: viewWidth, height: viewHeight) view.frame = frame contentView.frame = frame @@ -210,22 +237,31 @@ import UserNotificationsUI func createFrameWithImage() { let viewWidth = view.frame.size.width - var viewHeight = viewWidth + CTUtiltiy.getCaptionHeight() + var viewHeight = viewWidth + CTUtiltiy.getCaptionHeight() + progressViewHeight // For view in Landscape - viewHeight = (viewWidth * (Constraints.kLandscapeMultiplier)) + CTUtiltiy.getCaptionHeight() + viewHeight = (viewWidth * (Constraints.kLandscapeMultiplier)) + CTUtiltiy.getCaptionHeight() + progressViewHeight let frame: CGRect = CGRect(x: 0, y: 0, width: viewWidth, height: viewHeight) view.frame = frame contentView.frame = frame preferredContentSize = CGSize(width: viewWidth, height: viewHeight) } - + func activateImageViewContraints() { NSLayoutConstraint.activate([ imageView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: -Constraints.kImageBorderWidth), imageView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: -Constraints.kImageBorderWidth), imageView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: Constraints.kImageBorderWidth), - imageView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -CTUtiltiy.getCaptionHeight()) + imageView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -(CTUtiltiy.getCaptionHeight() + progressViewHeight)) + ]) + } + + func activateProgressViewContraints() { + NSLayoutConstraint.activate([ + timerProgressView.topAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -Constraints.kProgressViewHeight), + timerProgressView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: Constraints.kCaptionLeftPadding), + timerProgressView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -Constraints.kCaptionLeftPadding), + timerProgressView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -Constraints.kCaptionTopPadding) ]) } diff --git a/CTNotificationContent/Templates/Timer/Model/TimerTemplateProperties.swift b/CTNotificationContent/Templates/Timer/Model/TimerTemplateProperties.swift index 974c58a..9cc57d5 100644 --- a/CTNotificationContent/Templates/Timer/Model/TimerTemplateProperties.swift +++ b/CTNotificationContent/Templates/Timer/Model/TimerTemplateProperties.swift @@ -22,9 +22,11 @@ struct TimerTemplateProperties: Decodable { let pt_timer_end: Int? let pt_title_clr: String? let pt_msg_clr: String? + let pt_timer_progress_view: Bool? + let pt_timer_progress_clr: String? enum CodingKeys: String, CodingKey { - case pt_title, pt_title_alt, pt_msg, pt_msg_alt, pt_msg_summary, pt_dl1, pt_big_img, pt_big_img_alt, pt_bg, pt_chrono_title_clr, pt_timer_threshold, pt_timer_end, pt_title_clr, pt_msg_clr + case pt_title, pt_title_alt, pt_msg, pt_msg_alt, pt_msg_summary, pt_dl1, pt_big_img, pt_big_img_alt, pt_bg, pt_chrono_title_clr, pt_timer_threshold, pt_timer_end, pt_title_clr, pt_msg_clr, pt_timer_progress_view, pt_timer_progress_clr } init(from decoder: Decoder) throws { @@ -42,6 +44,7 @@ struct TimerTemplateProperties: Decodable { pt_chrono_title_clr = try container.decodeIfPresent(String.self, forKey: .pt_chrono_title_clr) pt_title_clr = try container.decodeIfPresent(String.self, forKey: .pt_title_clr) pt_msg_clr = try container.decodeIfPresent(String.self, forKey: .pt_msg_clr) + pt_timer_progress_clr = try container.decodeIfPresent(String.self, forKey: .pt_timer_progress_clr) // Value for pt_timer_threshold and pt_timer_end key can be Int or String if received from JSON data or individual keys respectively, so checked for both case if present or else nil. var thresholdValue: Int? = nil @@ -67,5 +70,18 @@ struct TimerTemplateProperties: Decodable { } } pt_timer_end = timerEndValue + + // Value for pt_timer_progress_view key can be Bool or String if received from JSON data or individual keys respectively, so checked for both case if present or else nil. + var progressViewValue: Bool? = nil + do { + if let boolValue = try container.decodeIfPresent(Bool.self, forKey: .pt_timer_progress_view) { + progressViewValue = boolValue + } + } catch { + if let stringValue = try container.decodeIfPresent(String.self, forKey: .pt_timer_progress_view) { + progressViewValue = Bool(stringValue) + } + } + pt_timer_progress_view = progressViewValue } } diff --git a/CTNotificationContent/Templates/Utility/GlobalConstants.swift b/CTNotificationContent/Templates/Utility/GlobalConstants.swift index 8d86cbc..fd26104 100644 --- a/CTNotificationContent/Templates/Utility/GlobalConstants.swift +++ b/CTNotificationContent/Templates/Utility/GlobalConstants.swift @@ -17,6 +17,7 @@ enum Constraints { static let kTimerLabelWidth: CGFloat = 100.0 static let kLandscapeMultiplier: CGFloat = 0.5625 // 16:9 in landscape static let kPortraitMultiplier: CGFloat = 1.777 // 16:9 in portrait + static let kProgressViewHeight: CGFloat = 12.0 } enum ConstantKeys { From c3049a3de1fe1a07ca898f1e07440ae9e186d735 Mon Sep 17 00:00:00 2001 From: Aishwarya Nanna Date: Mon, 17 Apr 2023 14:36:12 +0530 Subject: [PATCH 2/3] - Updated constraints to fix height of content view when timer expired --- .../CTTimerTemplateController.swift | 54 ++++++++++++++++--- 1 file changed, 47 insertions(+), 7 deletions(-) diff --git a/CTNotificationContent/Templates/Timer/Controller/CTTimerTemplateController.swift b/CTNotificationContent/Templates/Timer/Controller/CTTimerTemplateController.swift index 3d86baa..dfe9079 100644 --- a/CTNotificationContent/Templates/Timer/Controller/CTTimerTemplateController.swift +++ b/CTNotificationContent/Templates/Timer/Controller/CTTimerTemplateController.swift @@ -15,6 +15,14 @@ import UserNotificationsUI var timer: Timer = Timer() var thresholdSeconds = 0 var progressViewHeight: CGFloat = 0.0 + var captionLabelTopConstraint: NSLayoutConstraint? + var subCaptionBottomConstraint: NSLayoutConstraint? + var subCaptionTopConstraint: NSLayoutConstraint? + var timerLabelTopConstraint: NSLayoutConstraint? + var timerLabelBottomConstraint: NSLayoutConstraint? + var imageViewBottomConstraint: NSLayoutConstraint? + var isImageAdded = false + private var imageView: UIImageView = { let imageView = UIImageView() imageView.contentMode = .scaleAspectFit @@ -128,6 +136,7 @@ import UserNotificationsUI CTUtiltiy.checkImageUrlValid(imageUrl: bigImg) { [weak self] (imageData) in DispatchQueue.main.async { if imageData != nil { + self?.isImageAdded = true self?.imageView.image = imageData self?.activateImageViewContraints() self?.createFrameWithImage() @@ -157,22 +166,27 @@ import UserNotificationsUI } func setupConstraints() { + captionLabelTopConstraint = captionLabel.topAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -(CTUtiltiy.getCaptionHeight() - Constraints.kCaptionTopPadding + progressViewHeight)) + captionLabelTopConstraint?.isActive = true + subCaptionTopConstraint = subcaptionLabel.topAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -(Constraints.kSubCaptionHeight + Constraints.kSubCaptionTopPadding + progressViewHeight)) + subCaptionTopConstraint?.isActive = true + subCaptionBottomConstraint = subcaptionLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -(Constraints.kSubCaptionTopPadding + progressViewHeight)) + subCaptionBottomConstraint?.isActive = true + timerLabelTopConstraint = timerLabel.topAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -(CTUtiltiy.getCaptionHeight() + progressViewHeight)) + timerLabelTopConstraint?.isActive = true + timerLabelBottomConstraint = timerLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -(Constraints.kSubCaptionTopPadding + progressViewHeight)) + timerLabelBottomConstraint?.isActive = true NSLayoutConstraint.activate([ - captionLabel.topAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -(CTUtiltiy.getCaptionHeight() - Constraints.kCaptionTopPadding + progressViewHeight)), captionLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: Constraints.kCaptionLeftPadding), captionLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -Constraints.kTimerLabelWidth), captionLabel.heightAnchor.constraint(equalToConstant: Constraints.kCaptionHeight), - subcaptionLabel.topAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -(Constraints.kSubCaptionHeight + Constraints.kSubCaptionTopPadding + progressViewHeight)), subcaptionLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: Constraints.kCaptionLeftPadding), subcaptionLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -Constraints.kTimerLabelWidth), - subcaptionLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -(Constraints.kSubCaptionTopPadding + progressViewHeight)), subcaptionLabel.heightAnchor.constraint(equalToConstant: Constraints.kSubCaptionHeight), - timerLabel.topAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -(CTUtiltiy.getCaptionHeight() + progressViewHeight)), timerLabel.leadingAnchor.constraint(equalTo: captionLabel.trailingAnchor, constant: Constraints.kCaptionLeftPadding), timerLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -Constraints.kCaptionLeftPadding), - timerLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -(Constraints.kSubCaptionTopPadding + progressViewHeight)), timerLabel.heightAnchor.constraint(equalToConstant: CTUtiltiy.getCaptionHeight()) ]) } @@ -203,6 +217,13 @@ import UserNotificationsUI if let jsonContent = jsonContent { if let progressView = jsonContent.pt_timer_progress_view, progressView{ timerProgressView.removeFromSuperview() + progressViewHeight = 0.0 + updateConstraints() + if isImageAdded{ + createFrameWithImage() + }else{ + createFrameWithoutImage() + } } if let title = jsonContent.pt_title_alt, !title.isEmpty { @@ -220,12 +241,30 @@ import UserNotificationsUI self?.createFrameWithImage() self?.activateImageViewContraints() } + else{ + if let imageAdded = self?.isImageAdded, imageAdded{ + self?.createFrameWithImage() + }else{ + self?.createFrameWithoutImage() + } + } } } } } } + func updateConstraints(){ + captionLabelTopConstraint?.constant = -(CTUtiltiy.getCaptionHeight() - Constraints.kCaptionTopPadding + progressViewHeight) + subCaptionTopConstraint?.constant = -(Constraints.kSubCaptionHeight + Constraints.kSubCaptionTopPadding + progressViewHeight) + subCaptionBottomConstraint?.constant = -(Constraints.kSubCaptionTopPadding + progressViewHeight) + timerLabelTopConstraint?.constant = -(CTUtiltiy.getCaptionHeight() + progressViewHeight) + timerLabelBottomConstraint?.constant = -(Constraints.kSubCaptionTopPadding + progressViewHeight) + if isImageAdded{ + imageViewBottomConstraint?.constant = -(CTUtiltiy.getCaptionHeight() + progressViewHeight) + } + } + func createFrameWithoutImage() { let viewWidth = view.frame.size.width let viewHeight = CTUtiltiy.getCaptionHeight() + progressViewHeight @@ -248,11 +287,12 @@ import UserNotificationsUI } func activateImageViewContraints() { + imageViewBottomConstraint = imageView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -(CTUtiltiy.getCaptionHeight() + progressViewHeight)) + imageViewBottomConstraint?.isActive = true NSLayoutConstraint.activate([ imageView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: -Constraints.kImageBorderWidth), imageView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: -Constraints.kImageBorderWidth), - imageView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: Constraints.kImageBorderWidth), - imageView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -(CTUtiltiy.getCaptionHeight() + progressViewHeight)) + imageView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: Constraints.kImageBorderWidth) ]) } From 3de1f81ee2f7db945cb6327c5efb16379cc1f099 Mon Sep 17 00:00:00 2001 From: Aishwarya Nanna Date: Mon, 17 Apr 2023 14:42:02 +0530 Subject: [PATCH 3/3] - Removed custom progress view colour --- .../Timer/Controller/CTTimerTemplateController.swift | 4 ---- .../Templates/Timer/Model/TimerTemplateProperties.swift | 4 +--- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/CTNotificationContent/Templates/Timer/Controller/CTTimerTemplateController.swift b/CTNotificationContent/Templates/Timer/Controller/CTTimerTemplateController.swift index dfe9079..1028801 100644 --- a/CTNotificationContent/Templates/Timer/Controller/CTTimerTemplateController.swift +++ b/CTNotificationContent/Templates/Timer/Controller/CTTimerTemplateController.swift @@ -153,10 +153,6 @@ import UserNotificationsUI self.createFrameWithoutImage() } } - - if let timerProgressClr = jsonContent.pt_timer_progress_clr, !timerProgressClr.isEmpty { - timerProgressView.progressTintColor = UIColor(hex: timerProgressClr) - } view.backgroundColor = UIColor(hex: bgColor) imageView.backgroundColor = UIColor(hex: bgColor) diff --git a/CTNotificationContent/Templates/Timer/Model/TimerTemplateProperties.swift b/CTNotificationContent/Templates/Timer/Model/TimerTemplateProperties.swift index 9cc57d5..c300864 100644 --- a/CTNotificationContent/Templates/Timer/Model/TimerTemplateProperties.swift +++ b/CTNotificationContent/Templates/Timer/Model/TimerTemplateProperties.swift @@ -23,10 +23,9 @@ struct TimerTemplateProperties: Decodable { let pt_title_clr: String? let pt_msg_clr: String? let pt_timer_progress_view: Bool? - let pt_timer_progress_clr: String? enum CodingKeys: String, CodingKey { - case pt_title, pt_title_alt, pt_msg, pt_msg_alt, pt_msg_summary, pt_dl1, pt_big_img, pt_big_img_alt, pt_bg, pt_chrono_title_clr, pt_timer_threshold, pt_timer_end, pt_title_clr, pt_msg_clr, pt_timer_progress_view, pt_timer_progress_clr + case pt_title, pt_title_alt, pt_msg, pt_msg_alt, pt_msg_summary, pt_dl1, pt_big_img, pt_big_img_alt, pt_bg, pt_chrono_title_clr, pt_timer_threshold, pt_timer_end, pt_title_clr, pt_msg_clr, pt_timer_progress_view } init(from decoder: Decoder) throws { @@ -44,7 +43,6 @@ struct TimerTemplateProperties: Decodable { pt_chrono_title_clr = try container.decodeIfPresent(String.self, forKey: .pt_chrono_title_clr) pt_title_clr = try container.decodeIfPresent(String.self, forKey: .pt_title_clr) pt_msg_clr = try container.decodeIfPresent(String.self, forKey: .pt_msg_clr) - pt_timer_progress_clr = try container.decodeIfPresent(String.self, forKey: .pt_timer_progress_clr) // Value for pt_timer_threshold and pt_timer_end key can be Int or String if received from JSON data or individual keys respectively, so checked for both case if present or else nil. var thresholdValue: Int? = nil