@@ -3,6 +3,7 @@ import UIKit
33import Gridicons
44import WordPressUI
55import Yosemite
6+ import SwiftUI
67
78// MARK: - DashboardViewController
89//
@@ -73,6 +74,13 @@ final class DashboardViewController: UIViewController {
7374 } )
7475 } ( )
7576
77+ private var hasAnnouncementFeatureFlag : Bool { ServiceLocator . featureFlagService. isFeatureFlagEnabled ( . justInTimeMessagesOnDashboard)
78+ }
79+
80+ private var announcementViewHostingController : ConstraintsUpdatingHostingController < AnnouncementCardWrapper > ?
81+
82+ private var announcementView : UIView ?
83+
7684 /// Bottom Jetpack benefits banner, shown when the site is connected to Jetpack without Jetpack-the-plugin.
7785 private lazy var bottomJetpackBenefitsBannerController = JetpackBenefitsBannerHostingController ( )
7886 private var contentBottomToJetpackBenefitsBannerConstraint : NSLayoutConstraint ?
@@ -117,6 +125,10 @@ final class DashboardViewController: UIViewController {
117125 observeNavigationBarHeightForStoreNameLabelVisibility ( )
118126 observeStatsVersionForDashboardUIUpdates ( )
119127 trackProductsOnboardingEligibility ( )
128+ observeAnnouncements ( )
129+ if hasAnnouncementFeatureFlag {
130+ viewModel. syncAnnouncements ( for: siteID)
131+ }
120132 Task { @MainActor in
121133 await reloadDashboardUIStatsVersion ( forced: true )
122134 }
@@ -136,6 +148,18 @@ final class DashboardViewController: UIViewController {
136148 override var shouldShowOfflineBanner : Bool {
137149 return true
138150 }
151+
152+ internal override func willTransition( to newCollection: UITraitCollection , with coordinator: UIViewControllerTransitionCoordinator ) {
153+ super. willTransition ( to: newCollection, with: coordinator)
154+ updateAnnouncementCardVisibility ( with: newCollection)
155+ }
156+
157+ /// Hide the announcement card in compact (landscape phone)
158+ ///
159+ func updateAnnouncementCardVisibility( with newCollection: UITraitCollection ) {
160+ let shouldHideCard = newCollection. verticalSizeClass == . compact
161+ announcementView? . isHidden = shouldHideCard
162+ }
139163}
140164
141165// MARK: - Configuration
@@ -281,6 +305,60 @@ private extension DashboardViewController {
281305 } . store ( in: & subscriptions)
282306 }
283307
308+ // This is used so we have a specific type for the view while applying modifiers.
309+ struct AnnouncementCardWrapper : View {
310+ let cardView : FeatureAnnouncementCardView
311+
312+ var body : some View {
313+ cardView. background ( Color ( . listForeground) )
314+ }
315+ }
316+
317+ func observeAnnouncements( ) {
318+ viewModel. $announcementViewModel. sink { [ weak self] viewModel in
319+ guard let self = self else { return }
320+ self . removeAnnouncement ( )
321+ guard let viewModel = viewModel else {
322+ return
323+ }
324+
325+ let cardView = FeatureAnnouncementCardView ( viewModel: viewModel,
326+ dismiss: { } ,
327+ callToAction: { } )
328+
329+ self . showAnnouncement ( AnnouncementCardWrapper ( cardView: cardView) )
330+ }
331+ . store ( in: & subscriptions)
332+ }
333+
334+ private func removeAnnouncement( ) {
335+ guard let announcementView = announcementView else {
336+ return
337+ }
338+ announcementView. removeFromSuperview ( )
339+ announcementViewHostingController? . removeFromParent ( )
340+ announcementViewHostingController = nil
341+ self . announcementView = nil
342+ }
343+
344+ private func showAnnouncement( _ cardView: AnnouncementCardWrapper ) {
345+ let hostingController = ConstraintsUpdatingHostingController ( rootView: cardView)
346+ guard let uiView = hostingController. view else {
347+ return
348+ }
349+ announcementViewHostingController = hostingController
350+ announcementView = uiView
351+
352+ addChild ( hostingController)
353+ let indexAfterHeader = ( headerStackView. arrangedSubviews. firstIndex ( of: innerStackView) ?? - 1 ) + 1
354+ headerStackView. insertArrangedSubview ( uiView, at: indexAfterHeader)
355+
356+ updateAnnouncementCardVisibility ( with: traitCollection)
357+
358+ hostingController. didMove ( toParent: self )
359+ hostingController. view. layoutIfNeeded ( )
360+ }
361+
284362 /// Display the error banner at the top of the dashboard content (below the site title)
285363 ///
286364 func showTopBannerView( ) {
0 commit comments