Created
August 20, 2018 13:00
-
-
Save frosty/854b0bd95ede6d362edb3f9cddf7f360 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/WordPress/Classes/Stores/NoticeStore.swift b/WordPress/Classes/Stores/NoticeStore.swift | |
index 42dcb72422..58ec7a000b 100644 | |
--- a/WordPress/Classes/Stores/NoticeStore.swift | |
+++ b/WordPress/Classes/Stores/NoticeStore.swift | |
@@ -22,7 +22,7 @@ struct Notice { | |
/// Style used to configure visual style when displayed | |
/// | |
- let style: Style | |
+ let style: NoticeStyle | |
/// A title for an optional action button that can be displayed as part of | |
/// a notice | |
@@ -32,7 +32,7 @@ struct Notice { | |
/// is tapped, if you've provided an action title | |
let actionHandler: (() -> Void)? | |
- init(title: String, message: String? = nil, feedbackType: UINotificationFeedbackType? = nil, notificationInfo: NoticeNotificationInfo? = nil, style: Style = .normal) { | |
+ init(title: String, message: String? = nil, feedbackType: UINotificationFeedbackType? = nil, notificationInfo: NoticeNotificationInfo? = nil, style: NoticeStyle = NormalNoticeStyle()) { | |
self.title = title | |
self.message = message | |
self.feedbackType = feedbackType | |
@@ -42,7 +42,7 @@ struct Notice { | |
self.style = style | |
} | |
- init(title: String, message: String? = nil, feedbackType: UINotificationFeedbackType? = nil, notificationInfo: NoticeNotificationInfo? = nil, style: Style = .normal, actionTitle: String, actionHandler: @escaping (() -> Void)) { | |
+ init(title: String, message: String? = nil, feedbackType: UINotificationFeedbackType? = nil, notificationInfo: NoticeNotificationInfo? = nil, style: NoticeStyle = NormalNoticeStyle(), actionTitle: String, actionHandler: @escaping (() -> Void)) { | |
self.title = title | |
self.message = message | |
self.feedbackType = feedbackType | |
@@ -51,11 +51,6 @@ struct Notice { | |
self.actionHandler = actionHandler | |
self.style = style | |
} | |
- | |
- public enum Style { | |
- case normal | |
- case quickStart(NSAttributedString?) | |
- } | |
} | |
struct NoticeNotificationInfo { | |
@@ -87,6 +82,53 @@ struct NoticeNotificationInfo { | |
} | |
} | |
+public protocol NoticeStyle { | |
+ // Text | |
+ var attributedMessage: NSAttributedString? { get } | |
+ | |
+ // Fonts | |
+ var titleLabelFont: UIFont { get } | |
+ var messageLabelFont: UIFont { get } | |
+ var actionButtonFont: UIFont? { get } | |
+ | |
+ // Colors | |
+ var titleColor: UIColor { get } | |
+ var messageColor: UIColor { get } | |
+ var backgroundColor: UIColor { get } | |
+ | |
+ // Misc | |
+ var isDismissable: Bool { get } | |
+} | |
+ | |
+ | |
+public struct NormalNoticeStyle: NoticeStyle { | |
+ public let attributedMessage: NSAttributedString? = nil | |
+ | |
+ public let titleLabelFont = UIFont.boldSystemFont(ofSize: 14.0) | |
+ public let messageLabelFont = UIFont.systemFont(ofSize: 14.0) | |
+ public let actionButtonFont: UIFont? = UIFont.systemFont(ofSize: 14.0) | |
+ | |
+ public let titleColor: UIColor = WPStyleGuide.darkGrey() | |
+ public let messageColor: UIColor = WPStyleGuide.darkGrey() | |
+ public let backgroundColor: UIColor = .clear | |
+ | |
+ public let isDismissable = true | |
+} | |
+ | |
+public struct QuickStartNoticeStyle: NoticeStyle { | |
+ public let attributedMessage: NSAttributedString? | |
+ | |
+ public let titleLabelFont = WPStyleGuide.fontForTextStyle(.subheadline, fontWeight: .semibold) | |
+ public let messageLabelFont = WPStyleGuide.fontForTextStyle(.subheadline) | |
+ public let actionButtonFont: UIFont? = nil | |
+ | |
+ public let titleColor: UIColor = .white | |
+ public let messageColor: UIColor = WPStyleGuide.greyLighten20() | |
+ public let backgroundColor: UIColor = WPStyleGuide.darkGrey().withAlphaComponent(0.88) | |
+ | |
+ public let isDismissable = false | |
+} | |
+ | |
/// NoticeActions can be posted to control or report the display of notices. | |
/// | |
enum NoticeAction: Action { | |
diff --git a/WordPress/Classes/ViewRelated/Blog/QuickStartTourGuide.swift b/WordPress/Classes/ViewRelated/Blog/QuickStartTourGuide.swift | |
index 9c40af1468..41d79c9564 100644 | |
--- a/WordPress/Classes/ViewRelated/Blog/QuickStartTourGuide.swift | |
+++ b/WordPress/Classes/ViewRelated/Blog/QuickStartTourGuide.swift | |
@@ -16,8 +16,9 @@ open class QuickStartTourGuide: NSObject, UINavigationControllerDelegate { | |
// MARK: Quick Start methods | |
@objc | |
func showTestQuickStartNotice() { | |
- let exampleLabelStr = QuickStartNoticeView.makeHighlightMessage(base: "Tap %@ to see your checklist", highlight: "Quick Start", icon: Gridicon.iconOfType(.listCheckmark)) | |
- let notice = Notice(title: "Test Quick Start Notice", style: .quickStart(exampleLabelStr)) | |
+ let exampleMessage = "Tap %@ to see your checklist".highlightingPhrase("Quick Start", | |
+ withIcon: Gridicon.iconOfType(.listCheckmark)) | |
+ let notice = Notice(title: "Test Quick Start Notice", style: QuickStartNoticeStyle(attributedMessage: exampleMessage)) | |
ActionDispatcher.dispatch(NoticeAction.post(notice)) | |
} | |
@@ -43,3 +44,51 @@ open class QuickStartTourGuide: NSObject, UINavigationControllerDelegate { | |
QuickStartFollowTour() | |
] | |
} | |
+ | |
+private extension String { | |
+ func highlightingPhrase(_ phrase: String, withIcon icon: UIImage) -> NSAttributedString { | |
+ let normalParts = components(separatedBy: "%@") | |
+ guard normalParts.count > 0 else { | |
+ // if the provided base doesn't contain %@ then we don't know where to place the highlight | |
+ return NSAttributedString(string: self) | |
+ } | |
+ let resultString = NSMutableAttributedString(string: normalParts[0]) | |
+ | |
+ let font = WPStyleGuide.mediumWeightFont(forStyle: .subheadline) | |
+ | |
+ let iconAttachment = NSTextAttachment() | |
+ iconAttachment.image = icon.imageWithTintColor(HighlightConstants.highlightColor) | |
+ iconAttachment.bounds = CGRect(x: 0.0, y: font.descender + HighlightConstants.iconOffset, width: HighlightConstants.iconSize, height: HighlightConstants.iconSize) | |
+ let iconStr = NSAttributedString(attachment: iconAttachment) | |
+ | |
+ let highlightStr = NSAttributedString(string: phrase, attributes: [.foregroundColor: HighlightConstants.highlightColor, .font: HighlightConstants.highlightFont]) | |
+ | |
+ switch UIView.userInterfaceLayoutDirection(for: .unspecified) { | |
+ case .rightToLeft: | |
+ resultString.append(highlightStr) | |
+ resultString.append(NSAttributedString(string: " ")) | |
+ resultString.append(iconStr) | |
+ default: | |
+ resultString.append(iconStr) | |
+ resultString.append(NSAttributedString(string: " ")) | |
+ resultString.append(highlightStr) | |
+ } | |
+ | |
+ if normalParts.count > 1 { | |
+ resultString.append(NSAttributedString(string: normalParts[1])) | |
+ } | |
+ | |
+ return resultString | |
+ } | |
+ | |
+ private enum HighlightConstants { | |
+ static let iconOffset: CGFloat = 1.0 | |
+ static let iconSize: CGFloat = 16.0 | |
+ static let highlightColor = WPStyleGuide.lightBlue() | |
+ static var highlightFont: UIFont { | |
+ get { | |
+ return WPStyleGuide.fontForTextStyle(.subheadline, fontWeight: .semibold) | |
+ } | |
+ } | |
+ } | |
+} | |
diff --git a/WordPress/Classes/ViewRelated/System/Notices/NoticePresenter.swift b/WordPress/Classes/ViewRelated/System/Notices/NoticePresenter.swift | |
index 5346361330..927064bcdc 100644 | |
--- a/WordPress/Classes/ViewRelated/System/Notices/NoticePresenter.swift | |
+++ b/WordPress/Classes/ViewRelated/System/Notices/NoticePresenter.swift | |
@@ -65,7 +65,7 @@ class NoticePresenter: NSObject { | |
generator.prepare() | |
- let noticeView = makeNoticeView(for: notice) | |
+ let noticeView = NoticeView(notice: notice) | |
noticeView.translatesAutoresizingMaskIntoConstraints = false | |
let noticeContainerView = NoticeContainerView(noticeView: noticeView) | |
@@ -95,7 +95,7 @@ class NoticePresenter: NSObject { | |
animatePresentation(fromState: fromState, toState: toState, completion: { | |
// Quick Start notices don't get automatically dismissed | |
- if case .quickStart(_) = notice.style { | |
+ guard notice.style.isDismissable else { | |
return | |
} | |
@@ -103,15 +103,6 @@ class NoticePresenter: NSObject { | |
}) | |
} | |
- private func makeNoticeView(for notice: Notice) -> NoticeView { | |
- switch notice.style { | |
- case .quickStart(let formattedMessage): | |
- return QuickStartNoticeView(notice: notice) | |
- default: | |
- return NoticeView(notice: notice) | |
- } | |
- } | |
- | |
private func offscreenState(for noticeContainer: NoticeContainerView) -> (() -> ()) { | |
return { [weak self] in | |
guard let strongSelf = self, | |
diff --git a/WordPress/Classes/ViewRelated/System/Notices/NoticeView.swift b/WordPress/Classes/ViewRelated/System/Notices/NoticeView.swift | |
index d7210b2f24..aecdeef85c 100644 | |
--- a/WordPress/Classes/ViewRelated/System/Notices/NoticeView.swift | |
+++ b/WordPress/Classes/ViewRelated/System/Notices/NoticeView.swift | |
@@ -1,22 +1,22 @@ | |
import UIKit | |
class NoticeView: UIView { | |
- internal let contentStackView = UIStackView() | |
- internal let backgroundContainerView = UIView() | |
- internal let backgroundView = UIVisualEffectView(effect: UIBlurEffect(style: .extraLight)) | |
- internal let actionBackgroundView = UIView() | |
+ private let contentStackView = UIStackView() | |
+ private let backgroundContainerView = UIView() | |
+ private let backgroundView = UIVisualEffectView(effect: UIBlurEffect(style: .extraLight)) | |
+ private let actionBackgroundView = UIView() | |
private let shadowLayer = CAShapeLayer() | |
private let shadowMaskLayer = CAShapeLayer() | |
- internal let titleLabel = UILabel() | |
- internal let messageLabel = UILabel() | |
+ private let titleLabel = UILabel() | |
+ private let messageLabel = UILabel() | |
private let actionButton = UIButton(type: .system) | |
- internal let notice: Notice | |
+ private let notice: Notice | |
var dismissHandler: (() -> Void)? | |
- required init(notice: Notice) { | |
+ init(notice: Notice) { | |
self.notice = notice | |
super.init(frame: .zero) | |
@@ -29,17 +29,33 @@ class NoticeView: UIView { | |
} | |
/// configure the NoticeView for display | |
- internal func configure() { | |
+ private func configure() { | |
configureBackgroundViews() | |
configureShadow() | |
configureContentStackView() | |
configureLabels() | |
- configureActionButton() | |
- configureDismissRecognizer() | |
+ | |
+ if notice.actionTitle != nil { | |
+ configureActionButton() | |
+ } | |
+ | |
+ if notice.style.isDismissable { | |
+ configureDismissRecognizer() | |
+ } | |
+ | |
configureForNotice() | |
} | |
private func configureBackgroundViews() { | |
+ if notice.style.backgroundColor != .clear { | |
+ let backgroundColorView = UIView() | |
+ backgroundColorView.backgroundColor = notice.style.backgroundColor | |
+ backgroundView.contentView.addSubview(backgroundColorView) | |
+ backgroundColorView.layer.cornerRadius = Metrics.cornerRadius | |
+ backgroundColorView.translatesAutoresizingMaskIntoConstraints = false | |
+ backgroundView.contentView.pinSubviewToAllEdges(backgroundColorView) | |
+ } | |
+ | |
addSubview(backgroundContainerView) | |
backgroundContainerView.translatesAutoresizingMaskIntoConstraints = false | |
pinSubviewToAllEdges(backgroundContainerView) | |
@@ -52,7 +68,7 @@ class NoticeView: UIView { | |
backgroundContainerView.layer.masksToBounds = true | |
} | |
- internal func configureShadow() { | |
+ private func configureShadow() { | |
shadowLayer.shadowPath = UIBezierPath(roundedRect: layer.bounds, cornerRadius: Metrics.cornerRadius).cgPath | |
shadowLayer.shadowColor = Appearance.shadowColor.cgColor | |
shadowLayer.shadowOpacity = Appearance.shadowOpacity | |
@@ -82,14 +98,14 @@ class NoticeView: UIView { | |
shadowMaskLayer.path = maskPath | |
} | |
- internal func configureContentStackView() { | |
+ private func configureContentStackView() { | |
contentStackView.axis = .horizontal | |
contentStackView.translatesAutoresizingMaskIntoConstraints = false | |
backgroundView.contentView.addSubview(contentStackView) | |
backgroundView.contentView.pinSubviewToAllEdges(contentStackView) | |
} | |
- private func configureLabels() { //** | |
+ private func configureLabels() { | |
let labelStackView = UIStackView() | |
labelStackView.translatesAutoresizingMaskIntoConstraints = false | |
labelStackView.alignment = .leading | |
@@ -109,11 +125,11 @@ class NoticeView: UIView { | |
labelStackView.bottomAnchor.constraint(equalTo: backgroundView.contentView.bottomAnchor) | |
]) | |
- titleLabel.font = Fonts.titleLabelFont | |
- messageLabel.font = Fonts.messageLabelFont | |
+ titleLabel.font = notice.style.titleLabelFont | |
+ messageLabel.font = notice.style.messageLabelFont | |
- titleLabel.textColor = WPStyleGuide.darkGrey() | |
- messageLabel.textColor = WPStyleGuide.darkGrey() | |
+ titleLabel.textColor = notice.style.titleColor | |
+ messageLabel.textColor = notice.style.messageColor | |
} | |
private func configureActionButton() { | |
@@ -133,7 +149,7 @@ class NoticeView: UIView { | |
actionBackgroundView.pinSubviewToAllEdgeMargins(actionButton) | |
- actionButton.titleLabel?.font = Fonts.actionButtonFont | |
+ actionButton.titleLabel?.font = notice.style.actionButtonFont | |
actionButton.setTitleColor(WPStyleGuide.mediumBlue(), for: .normal) | |
actionButton.addTarget(self, action: #selector(actionButtonTapped), for: .touchUpInside) | |
actionButton.setContentCompressionResistancePriority(.required, for: .horizontal) | |
@@ -147,7 +163,10 @@ class NoticeView: UIView { | |
private func configureForNotice() { | |
titleLabel.text = notice.title | |
- if let message = notice.message { | |
+ if let attributedMessage = notice.style.attributedMessage { | |
+ messageLabel.attributedText = attributedMessage | |
+ titleLabel.isHidden = true | |
+ } else if let message = notice.message { | |
messageLabel.text = message | |
} else { | |
titleLabel.numberOfLines = 2 | |
@@ -183,12 +202,6 @@ class NoticeView: UIView { | |
static let labelLineSpacing: CGFloat = 18.0 | |
} | |
- private enum Fonts { | |
- static let actionButtonFont = UIFont.systemFont(ofSize: 14.0) | |
- static let titleLabelFont = UIFont.boldSystemFont(ofSize: 14.0) | |
- static let messageLabelFont = UIFont.systemFont(ofSize: 14.0) | |
- } | |
- | |
private enum Appearance { | |
static let actionBackgroundColor = UIColor.white.withAlphaComponent(0.5) | |
static let shadowColor: UIColor = .black | |
diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj | |
index 1403caef22..7878c7fa40 100644 | |
--- a/WordPress/WordPress.xcodeproj/project.pbxproj | |
+++ b/WordPress/WordPress.xcodeproj/project.pbxproj | |
@@ -237,7 +237,6 @@ | |
433432521E9ED18900915988 /* LoginEpilogueViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 433432511E9ED18900915988 /* LoginEpilogueViewController.swift */; }; | |
433432541E9EE0B100915988 /* EpilogueSegue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 433432531E9EE0B100915988 /* EpilogueSegue.swift */; }; | |
433A550220F693A100757928 /* ManyDelegateNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 433A550120F693A100757928 /* ManyDelegateNavigationController.swift */; }; | |
- 433A550420F6AC5600757928 /* QuickStartNoticeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 433A550320F6AC5600757928 /* QuickStartNoticeView.swift */; }; | |
4348C88321002FBD00735DC0 /* QuickStartTourGuide.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4348C88221002FBD00735DC0 /* QuickStartTourGuide.swift */; }; | |
435035971EDCAB99004ECF47 /* jetpack.json in Resources */ = {isa = PBXBuildFile; fileRef = 435035921EDCAB99004ECF47 /* jetpack.json */; }; | |
435035981EDCAB99004ECF47 /* notifications.json in Resources */ = {isa = PBXBuildFile; fileRef = 435035931EDCAB99004ECF47 /* notifications.json */; }; | |
@@ -1735,7 +1734,6 @@ | |
433432511E9ED18900915988 /* LoginEpilogueViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginEpilogueViewController.swift; sourceTree = "<group>"; }; | |
433432531E9EE0B100915988 /* EpilogueSegue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EpilogueSegue.swift; sourceTree = "<group>"; }; | |
433A550120F693A100757928 /* ManyDelegateNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManyDelegateNavigationController.swift; sourceTree = "<group>"; }; | |
- 433A550320F6AC5600757928 /* QuickStartNoticeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickStartNoticeView.swift; sourceTree = "<group>"; }; | |
4348C88221002FBD00735DC0 /* QuickStartTourGuide.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickStartTourGuide.swift; sourceTree = "<group>"; }; | |
435035921EDCAB99004ECF47 /* jetpack.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = jetpack.json; sourceTree = "<group>"; }; | |
435035931EDCAB99004ECF47 /* notifications.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = notifications.json; sourceTree = "<group>"; }; | |
@@ -3915,7 +3913,6 @@ | |
isa = PBXGroup; | |
children = ( | |
4348C88221002FBD00735DC0 /* QuickStartTourGuide.swift */, | |
- 433A550320F6AC5600757928 /* QuickStartNoticeView.swift */, | |
4395A1582106389800844E8E /* QuickStartTours.swift */, | |
4395A15A21066DCD00844E8E /* QuickStartChecklistCell.xib */, | |
4395A15C2106718900844E8E /* QuickStartChecklistCell.swift */, | |
@@ -8079,7 +8076,6 @@ | |
17BEE0041FC867C20074C124 /* WordPressAppDelegate+Swift.swift in Sources */, | |
08472A201C727E020040769D /* PostServiceOptions.m in Sources */, | |
7E4123BA20F4097B00DF8486 /* FormattableContentGroup.swift in Sources */, | |
- 433A550420F6AC5600757928 /* QuickStartNoticeView.swift in Sources */, | |
08216FD21CDBF96000304BA7 /* MenuItemSourceViewController.m in Sources */, | |
74558369201A1FD3007809BB /* WPReusableTableViewCells.swift in Sources */, | |
E6DAABDD1CF632EC0069D933 /* ReaderSearchSuggestionsViewController.swift in Sources */, |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment