Skip to content

Commit ca2fa88

Browse files
authored
Add [Stories Feed] FXIOS-13084 / FXIOS-13095 Stories feed (#29845)
1 parent 2b2d68b commit ca2fa88

File tree

9 files changed

+523
-4
lines changed

9 files changed

+523
-4
lines changed

firefox-ios/Client.xcodeproj/project.pbxproj

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1552,12 +1552,17 @@
15521552
C714D7752E46649600FC02E6 /* ShortcutsLibraryDiffableDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = C714D7742E46649600FC02E6 /* ShortcutsLibraryDiffableDataSource.swift */; };
15531553
C714D7B62E4673A300FC02E6 /* ShortcutsLibraryDiffableDataSourceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C714D7B52E4673A300FC02E6 /* ShortcutsLibraryDiffableDataSourceTests.swift */; };
15541554
C714D8362E468D8200FC02E6 /* homepageRedesignOff.json in Resources */ = {isa = PBXBuildFile; fileRef = C714D8352E468D6900FC02E6 /* homepageRedesignOff.json */; };
1555+
C720FB3F2E955A2B00AB0DAC /* StoriesFeedViewControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C720FB3E2E955A2B00AB0DAC /* StoriesFeedViewControllerTests.swift */; };
1556+
C720FB412E955A4E00AB0DAC /* StoriesFeedDiffableDataSourceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C720FB402E955A4E00AB0DAC /* StoriesFeedDiffableDataSourceTests.swift */; };
15551557
C743CB1D2DF201D50069CB23 /* StoryCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C743CB1C2DF201D50069CB23 /* StoryCell.swift */; };
15561558
C787D8C32C1CB77900940123 /* FirefoxAccountSignInViewControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C787D8C22C1CB77900940123 /* FirefoxAccountSignInViewControllerTests.swift */; };
15571559
C78FC19E2E62448400B077DA /* ShortcutsLibraryViewControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C78FC19D2E62448400B077DA /* ShortcutsLibraryViewControllerTests.swift */; };
15581560
C796E22A2E3D48D3005D6A1D /* ShortcutsLibraryViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C796E2292E3D48D3005D6A1D /* ShortcutsLibraryViewController.swift */; };
1561+
C7B376E32E870173006B2D32 /* StoriesFeedCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7B376E22E870173006B2D32 /* StoriesFeedCell.swift */; };
1562+
C7B376E52E870E80006B2D32 /* StoriesFeedDiffableDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7B376E42E870E80006B2D32 /* StoriesFeedDiffableDataSource.swift */; };
15591563
C7B376E82E871095006B2D32 /* StoriesFeedState.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7B376E72E871095006B2D32 /* StoriesFeedState.swift */; };
15601564
C7B376EA2E8715A1006B2D32 /* StoriesFeedAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7B376E92E8715A1006B2D32 /* StoriesFeedAction.swift */; };
1565+
C7B37A342E8AFCF7006B2D32 /* StoriesFeedSectionLayoutProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7B37A332E8AFCF7006B2D32 /* StoriesFeedSectionLayoutProvider.swift */; };
15611566
C7CDBEFD2CE6926900826A92 /* BookmarksFolderEmptyStateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7CDBEFC2CE6926900826A92 /* BookmarksFolderEmptyStateView.swift */; };
15621567
C7D736312E85DCA0000ECE41 /* StoriesFeedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7D736302E85DCA0000ECE41 /* StoriesFeedViewController.swift */; };
15631568
C7F051522D95EACF00EC52C0 /* HistoryDeletionUtilityTelemetry.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7F051512D95EACF00EC52C0 /* HistoryDeletionUtilityTelemetry.swift */; };
@@ -9774,15 +9779,20 @@
97749779
C714D7742E46649600FC02E6 /* ShortcutsLibraryDiffableDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShortcutsLibraryDiffableDataSource.swift; sourceTree = "<group>"; };
97759780
C714D7B52E4673A300FC02E6 /* ShortcutsLibraryDiffableDataSourceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShortcutsLibraryDiffableDataSourceTests.swift; sourceTree = "<group>"; };
97769781
C714D8352E468D6900FC02E6 /* homepageRedesignOff.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = homepageRedesignOff.json; sourceTree = "<group>"; };
9782+
C720FB3E2E955A2B00AB0DAC /* StoriesFeedViewControllerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoriesFeedViewControllerTests.swift; sourceTree = "<group>"; };
9783+
C720FB402E955A4E00AB0DAC /* StoriesFeedDiffableDataSourceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoriesFeedDiffableDataSourceTests.swift; sourceTree = "<group>"; };
97779784
C7354071A05454E7FF3C70D8 /* lt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = lt; path = lt.lproj/ErrorPages.strings; sourceTree = "<group>"; };
97789785
C743CB1C2DF201D50069CB23 /* StoryCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoryCell.swift; sourceTree = "<group>"; };
97799786
C7664A29B78A808DC314353C /* he */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = he; path = he.lproj/Search.strings; sourceTree = "<group>"; };
97809787
C787D8C22C1CB77900940123 /* FirefoxAccountSignInViewControllerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirefoxAccountSignInViewControllerTests.swift; sourceTree = "<group>"; };
97819788
C78FC19D2E62448400B077DA /* ShortcutsLibraryViewControllerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShortcutsLibraryViewControllerTests.swift; sourceTree = "<group>"; };
97829789
C796E2292E3D48D3005D6A1D /* ShortcutsLibraryViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShortcutsLibraryViewController.swift; sourceTree = "<group>"; };
97839790
C7A6413B89FE82B94F735FFD /* gl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = gl; path = gl.lproj/ClearHistoryConfirm.strings; sourceTree = "<group>"; };
9791+
C7B376E22E870173006B2D32 /* StoriesFeedCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoriesFeedCell.swift; sourceTree = "<group>"; };
9792+
C7B376E42E870E80006B2D32 /* StoriesFeedDiffableDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoriesFeedDiffableDataSource.swift; sourceTree = "<group>"; };
97849793
C7B376E72E871095006B2D32 /* StoriesFeedState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoriesFeedState.swift; sourceTree = "<group>"; };
97859794
C7B376E92E8715A1006B2D32 /* StoriesFeedAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoriesFeedAction.swift; sourceTree = "<group>"; };
9795+
C7B37A332E8AFCF7006B2D32 /* StoriesFeedSectionLayoutProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoriesFeedSectionLayoutProvider.swift; sourceTree = "<group>"; };
97869796
C7C54345A164D550CF2BC575 /* kn */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = kn; path = kn.lproj/3DTouchActions.strings; sourceTree = "<group>"; };
97879797
C7CDBEFC2CE6926900826A92 /* BookmarksFolderEmptyStateView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarksFolderEmptyStateView.swift; sourceTree = "<group>"; };
97889798
C7D341F8BA6A9E44518C11C8 /* oc */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = oc; path = oc.lproj/3DTouchActions.strings; sourceTree = "<group>"; };
@@ -14299,6 +14309,15 @@
1429914309
path = ShortcutsLibrary;
1430014310
sourceTree = "<group>";
1430114311
};
14312+
C720FB3D2E9559B300AB0DAC /* StoriesFeed */ = {
14313+
isa = PBXGroup;
14314+
children = (
14315+
C720FB3E2E955A2B00AB0DAC /* StoriesFeedViewControllerTests.swift */,
14316+
C720FB402E955A4E00AB0DAC /* StoriesFeedDiffableDataSourceTests.swift */,
14317+
);
14318+
path = StoriesFeed;
14319+
sourceTree = "<group>";
14320+
};
1430214321
C78FC19C2E62446B00B077DA /* Redux */ = {
1430314322
isa = PBXGroup;
1430414323
children = (
@@ -14333,6 +14352,9 @@
1433314352
children = (
1433414353
C7B376E62E871053006B2D32 /* Redux */,
1433514354
C7D736302E85DCA0000ECE41 /* StoriesFeedViewController.swift */,
14355+
C7B376E22E870173006B2D32 /* StoriesFeedCell.swift */,
14356+
C7B376E42E870E80006B2D32 /* StoriesFeedDiffableDataSource.swift */,
14357+
C7B37A332E8AFCF7006B2D32 /* StoriesFeedSectionLayoutProvider.swift */,
1433614358
);
1433714359
path = StoriesFeed;
1433814360
sourceTree = "<group>";
@@ -15345,6 +15367,7 @@
1534515367
8A00BD852CAB3FC200680AF9 /* Homepage Rebuild */,
1534615368
E1AEC16E286E0CF500062E29 /* Home */,
1534715369
C714D6382E46575D00FC02E6 /* ShortcutsLibrary */,
15370+
C720FB3D2E9559B300AB0DAC /* StoriesFeed */,
1534815371
4331D3EE2A059C1C00542BDD /* SyncContentSettingsViewControllerTests.swift */,
1534915372
8AD54D3128FD9E2C0070D4B3 /* Theme */,
1535015373
21292E6A2E7896910001AC06 /* RecordVisitObservationManagerTests.swift */,
@@ -18189,6 +18212,7 @@
1818918212
4346FF08295BA6A300F4D220 /* CreditCardSettingsViewController.swift in Sources */,
1819018213
1DCEC3F22D5D1FEC00129966 /* ASSearchEngineSelector.swift in Sources */,
1819118214
E19B38B528A42EBC00D8C541 /* WallpaperCellViewModel.swift in Sources */,
18215+
C7B37A342E8AFCF7006B2D32 /* StoriesFeedSectionLayoutProvider.swift in Sources */,
1819218216
8AAEBA042BF51134000C02B5 /* MicrosurveyState.swift in Sources */,
1819318217
5A3A7DCE2886F7880065F81A /* BookmarksDataAdaptor.swift in Sources */,
1819418218
C80E1A102A0943640025B9E1 /* UIFont+Extension.swift in Sources */,
@@ -18691,6 +18715,7 @@
1869118715
23ED80FF25C89C9800D0E9D5 /* DefaultBrowserOnboardingViewController.swift in Sources */,
1869218716
8A3EF80D2A2FD04D00796E3A /* ResetWallpaperOnboardingPage.swift in Sources */,
1869318717
E1FE132F29C0B3CB002A65FF /* NotificationSurfaceManager.swift in Sources */,
18718+
C7B376E32E870173006B2D32 /* StoriesFeedCell.swift in Sources */,
1869418719
D88FDA9F1F4E2B9200FD9709 /* PhotonActionSheetProtocol.swift in Sources */,
1869518720
5AD3B67C2CF65DE600AFA1FE /* LocaleInterface.swift in Sources */,
1869618721
21618A932A4499FC00A5189E /* AppState.swift in Sources */,
@@ -18871,6 +18896,7 @@
1887118896
BCBE058C2E3A8720004B6039 /* SummarizeSetting.swift in Sources */,
1887218897
E1442FD5294782D9003680B0 /* UIView+SnapKit.swift in Sources */,
1887318898
2816F0001B33E05400522243 /* UIConstants.swift in Sources */,
18899+
C7B376E52E870E80006B2D32 /* StoriesFeedDiffableDataSource.swift in Sources */,
1887418900
21E78A7228F9A93100F8D687 /* UIDeviceInterface.swift in Sources */,
1887518901
EBB89508219398E500EB91A0 /* ContentBlocker+Safelist.swift in Sources */,
1887618902
C838FD5E289981240068F60B /* WallpaperURLProvider.swift in Sources */,
@@ -19480,6 +19506,7 @@
1948019506
5AD3B67A2CF653A600AFA1FE /* MockLocale.swift in Sources */,
1948119507
8A7A93EE2810ADF2005E7E1B /* ContileProviderTests.swift in Sources */,
1948219508
1DA3E4B22DB1C86F0065F7E7 /* ASSearchEngineUtilitiesTests.swift in Sources */,
19509+
C720FB412E955A4E00AB0DAC /* StoriesFeedDiffableDataSourceTests.swift in Sources */,
1948319510
5A3A7DDA2889EC4D0065F81A /* ReadingListMock.swift in Sources */,
1948419511
8A33221F27DFE318008F809E /* TopSitesDataAdaptorTests.swift in Sources */,
1948519512
2165B2C02860BB41004C0786 /* AdjustTelemetryHelperTests.swift in Sources */,
@@ -19568,6 +19595,7 @@
1956819595
F80D53CF2A09A3350047ED14 /* RustSyncManagerTests.swift in Sources */,
1956919596
1D3C90882ACE1AF400304C87 /* RemoteTabPanelTests.swift in Sources */,
1957019597
43446CF02412DDBE00F5C643 /* UpdateViewModelTests.swift in Sources */,
19598+
C720FB3F2E955A2B00AB0DAC /* StoriesFeedViewControllerTests.swift in Sources */,
1957119599
8A93F86829D373B0004159D9 /* MockNavigationController.swift in Sources */,
1957219600
0B8A39F12D351C2500853E47 /* EditBookmarkDataSourceTests.swift in Sources */,
1957319601
8AE1E1D927B1BD380024C45E /* UIStackViewExtensionsTests.swift in Sources */,

firefox-ios/Client/Application/AccessibilityIdentifiers.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,10 @@ struct AccessibilityIdentifiers {
236236
static let favIconImage = "SyncedTabFavIconImage"
237237
static let descriptionLabel = "SyncedTabDescriptionLabel"
238238
}
239+
240+
struct StoriesFeed {
241+
static let storiesFeedCell = "StoriesFeedCell"
242+
}
239243
}
240244

241245
struct GeneralizedIdentifiers {

firefox-ios/Client/Frontend/Home/Homepage Rebuild/Merino/MerinoStoryConfiguration.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ final class MerinoStoryConfiguration: Sendable, Equatable, Hashable {
1515
var title: String { story.title }
1616
var url: URL? { story.url }
1717
var imageURL: URL? { story.imageURL }
18+
var iconURL: URL? { story.iconURL }
1819
var description: String {
1920
return "\(story.publisher)"
2021
}
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
// This Source Code Form is subject to the terms of the Mozilla Public
2+
// License, v. 2.0. If a copy of the MPL was not distributed with this
3+
// file, You can obtain one at http://mozilla.org/MPL/2.0/
4+
5+
import Common
6+
import Foundation
7+
import SiteImageView
8+
9+
class StoriesFeedCell: UICollectionViewCell,
10+
ReusableCell,
11+
Notifiable,
12+
ThemeApplicable {
13+
struct UX {
14+
static let cellCornerRadius: CGFloat = 16
15+
static let thumbnailSize = CGSize(width: 345, height: 180)
16+
static let thumbnailCornerRadius: CGFloat = 8
17+
static let attributionStackViewSpacing: CGFloat = 8
18+
static let attributionFaviconSize = CGSize(width: 16, height: 16)
19+
static let faviconCornerRadius: CGFloat = 0
20+
static let verticalSpacing: CGFloat = 8
21+
static let horizontalInsets: CGFloat = 16
22+
static let shadowOffset = CGSize(width: 0, height: 1)
23+
static let shadowBlurRadius: CGFloat = 2
24+
static let shadowOpacity: Float = 1
25+
}
26+
27+
// MARK: - Notifiable Properties
28+
var notificationCenter: NotificationProtocol
29+
30+
// MARK: - UI Elements
31+
private var thumbnailImageView: HeroImageView = .build { _ in }
32+
33+
private lazy var titleLabel: UILabel = .build { label in
34+
label.adjustsFontForContentSizeCategory = true
35+
label.font = FXFontStyles.Bold.callout.scaledFont()
36+
}
37+
38+
private lazy var attributionStackView: UIStackView = .build { stackView in
39+
stackView.spacing = UX.attributionStackViewSpacing
40+
stackView.alignment = .center
41+
}
42+
43+
private lazy var attributionFaviconImageView: FaviconImageView = .build()
44+
45+
private lazy var attributionTitleLabel: UILabel = .build { label in
46+
label.font = FXFontStyles.Regular.subheadline.scaledFont()
47+
label.adjustsFontForContentSizeCategory = true
48+
label.numberOfLines = 0
49+
}
50+
51+
// MARK: Initializers
52+
override init(frame: CGRect) {
53+
self.notificationCenter = NotificationCenter.default
54+
super.init(frame: frame)
55+
56+
isAccessibilityElement = true
57+
accessibilityIdentifier = AccessibilityIdentifiers.FirefoxHomepage.StoriesFeed.storiesFeedCell
58+
startObservingNotifications(
59+
withNotificationCenter: notificationCenter,
60+
forObserver: self,
61+
observing: [UIContentSizeCategory.didChangeNotification]
62+
)
63+
setupLayout()
64+
}
65+
66+
required init?(coder: NSCoder) {
67+
fatalError("init(coder:) has not been implemented")
68+
}
69+
70+
override func layoutSubviews() {
71+
super.layoutSubviews()
72+
contentView.layer.shadowPath = UIBezierPath(roundedRect: contentView.bounds,
73+
cornerRadius: UX.cellCornerRadius).cgPath
74+
}
75+
76+
// MARK: Public functions
77+
func configure(story: MerinoStoryConfiguration, theme: Theme, position: Int? = nil, totalCount: Int? = nil) {
78+
let heroImageViewModel = HomepageHeroImageViewModel(urlStringRequest: story.imageURL?.absoluteString ?? "",
79+
generalCornerRadius: UX.thumbnailCornerRadius,
80+
faviconCornerRadius: UX.thumbnailCornerRadius,
81+
heroImageSize: UX.thumbnailSize)
82+
thumbnailImageView.setHeroImage(heroImageViewModel)
83+
84+
titleLabel.text = story.title
85+
titleLabel.numberOfLines = getNumberOfLinesForTitle()
86+
accessibilityLabel = story.accessibilityLabel
87+
if let position = position, let totalCount = totalCount {
88+
accessibilityHint = String(
89+
format: .FirefoxHomepage.Pocket.PositionAccessibilityHint,
90+
String(position),
91+
String(totalCount)
92+
)
93+
}
94+
95+
// Use provided favicon if given, otherwise fetch favicon from story url
96+
// Site resource only necessary when fetching a resource directly instead of scraping
97+
if let url = story.iconURL ?? story.url {
98+
let siteResource = story.iconURL.map { SiteResource.remoteURL(url: $0) }
99+
let viewModel = FaviconImageViewModel(
100+
siteURLString: url.absoluteString,
101+
siteResource: siteResource,
102+
faviconCornerRadius: UX.faviconCornerRadius
103+
)
104+
attributionFaviconImageView.setFavicon(viewModel)
105+
}
106+
107+
attributionTitleLabel.text = story.description
108+
109+
applyTheme(theme: theme)
110+
}
111+
112+
// MARK: - Helpers
113+
private func setupLayout() {
114+
contentView.layer.cornerRadius = UX.cellCornerRadius
115+
116+
attributionStackView.addArrangedSubview(attributionFaviconImageView)
117+
attributionStackView.addArrangedSubview(attributionTitleLabel)
118+
119+
contentView.addSubviews(thumbnailImageView, titleLabel, attributionStackView)
120+
121+
NSLayoutConstraint.activate([
122+
thumbnailImageView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: UX.verticalSpacing),
123+
thumbnailImageView.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),
124+
thumbnailImageView.widthAnchor.constraint(equalToConstant: UX.thumbnailSize.width),
125+
thumbnailImageView.heightAnchor.constraint(equalToConstant: UX.thumbnailSize.height),
126+
127+
titleLabel.topAnchor.constraint(equalTo: thumbnailImageView.bottomAnchor, constant: UX.verticalSpacing),
128+
titleLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: UX.horizontalInsets),
129+
titleLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -UX.horizontalInsets),
130+
131+
attributionStackView.topAnchor.constraint(greaterThanOrEqualTo: titleLabel.bottomAnchor,
132+
constant: UX.verticalSpacing),
133+
attributionStackView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor,
134+
constant: UX.horizontalInsets),
135+
attributionStackView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor,
136+
constant: -UX.horizontalInsets),
137+
attributionStackView.bottomAnchor.constraint(lessThanOrEqualTo: contentView.bottomAnchor,
138+
constant: -UX.horizontalInsets),
139+
140+
attributionFaviconImageView.heightAnchor.constraint(equalToConstant: UX.attributionFaviconSize.height),
141+
attributionFaviconImageView.widthAnchor.constraint(equalToConstant: UX.attributionFaviconSize.width),
142+
])
143+
}
144+
145+
private func setupShadow(theme: Theme) {
146+
contentView.layer.shadowRadius = UX.shadowBlurRadius
147+
contentView.layer.shadowOffset = UX.shadowOffset
148+
contentView.layer.shadowColor = theme.colors.shadowDefault.cgColor
149+
contentView.layer.shadowOpacity = UX.shadowOpacity // opacity is handled in color
150+
}
151+
152+
// Allow full title wrapping when dynamic type > .large, since truncation at larger sizes omits too many words and
153+
// hurts readability. Otherwise, show 3 lines of the title
154+
private func getNumberOfLinesForTitle() -> Int {
155+
return UIApplication.shared.preferredContentSizeCategory > UIContentSizeCategory.large ? 0 : 3
156+
}
157+
158+
// MARK: - ThemeApplicable
159+
func applyTheme(theme: Theme) {
160+
contentView.backgroundColor = theme.colors.layer2
161+
titleLabel.textColor = theme.colors.textPrimary
162+
attributionTitleLabel.textColor = theme.colors.textSecondary
163+
setupShadow(theme: theme)
164+
}
165+
166+
// MARK: - Notifiable
167+
func handleNotifications(_ notification: Notification) {
168+
switch notification.name {
169+
case UIContentSizeCategory.didChangeNotification:
170+
titleLabel.numberOfLines = getNumberOfLinesForTitle()
171+
default: break
172+
}
173+
}
174+
}

0 commit comments

Comments
 (0)