Skip to content

Commit

Permalink
Reader: Add a footer view for the Reader tags feed (#23109)
Browse files Browse the repository at this point in the history
  • Loading branch information
wargcm committed Apr 30, 2024
2 parents 2ce235f + 0a19acf commit 7343e2b
Show file tree
Hide file tree
Showing 8 changed files with 209 additions and 7 deletions.
25 changes: 21 additions & 4 deletions WordPress/Classes/ViewRelated/Reader/ReaderTagCardCell.swift
Expand Up @@ -47,7 +47,7 @@ class ReaderTagCardCell: UITableViewCell {

override func awakeFromNib() {
super.awakeFromNib()
registerTagCell()
registerCells()
setupButtonStyles()
accessibilityElements = [tagButton, collectionView].compactMap { $0 }
collectionViewHeightConstraint.constant = cellSize.height
Expand All @@ -64,6 +64,10 @@ class ReaderTagCardCell: UITableViewCell {
}

func configure(parent: UIViewController, tag: ReaderTagTopic, isLoggedIn: Bool, shouldSyncRemotely: Bool = false) {
if viewModel?.slug == tag.slug {
return
}
resetScrollPosition()
weak var weakSelf = self
viewModel = ReaderTagCardCellViewModel(parent: parent,
tag: tag,
Expand Down Expand Up @@ -116,9 +120,13 @@ private extension ReaderTagCardCell {
tagButton.configuration = buttonConfig
}

func registerTagCell() {
let nib = UINib(nibName: ReaderTagCell.classNameWithoutNamespaces(), bundle: nil)
collectionView.register(nib, forCellWithReuseIdentifier: ReaderTagCell.classNameWithoutNamespaces())
func registerCells() {
let tagCell = UINib(nibName: ReaderTagCell.classNameWithoutNamespaces(), bundle: nil)
let footerView = UINib(nibName: ReaderTagFooterView.classNameWithoutNamespaces(), bundle: nil)
collectionView.register(tagCell, forCellWithReuseIdentifier: ReaderTagCell.classNameWithoutNamespaces())
collectionView.register(footerView,
forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter,
withReuseIdentifier: ReaderTagFooterView.classNameWithoutNamespaces())
}

/// Injects a "fake" UICollectionView for the loading state animation.
Expand Down Expand Up @@ -166,4 +174,13 @@ private extension ReaderTagCardCell {
ghostableCollectionView.removeFromSuperview()
}

func resetScrollPosition() {
let isRTL = UIView.userInterfaceLayoutDirection(for: .unspecified) == .rightToLeft
if isRTL {
collectionView.scrollToEnd(animated: false)
} else {
collectionView.scrollToStart(animated: false)
}
}

}
2 changes: 1 addition & 1 deletion WordPress/Classes/ViewRelated/Reader/ReaderTagCardCell.xib
Expand Up @@ -33,7 +33,7 @@
<collectionViewFlowLayout key="collectionViewLayout" scrollDirection="horizontal" minimumLineSpacing="10" minimumInteritemSpacing="16" id="0Qb-19-SWX">
<size key="itemSize" width="240" height="297"/>
<size key="headerReferenceSize" width="0.0" height="0.0"/>
<size key="footerReferenceSize" width="0.0" height="0.0"/>
<size key="footerReferenceSize" width="50" height="50"/>
<inset key="sectionInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
</collectionViewFlowLayout>
</collectionView>
Expand Down
Expand Up @@ -9,11 +9,11 @@ class ReaderTagCardCellViewModel: NSObject {
private typealias DataSource = UICollectionViewDiffableDataSource<Int, NSManagedObjectID>
private typealias Snapshot = NSDiffableDataSourceSnapshot<Int, NSManagedObjectID>

let slug: String
weak var viewDelegate: ReaderTagCardCellViewModelDelegate? = nil

private let coreDataStack: CoreDataStackSwift
private weak var parentViewController: UIViewController?
private let slug: String
private weak var collectionView: UICollectionView?
private let isLoggedIn: Bool
private let cellSize: () -> CGSize?
Expand All @@ -26,7 +26,7 @@ class ReaderTagCardCellViewModel: NSObject {
guard let collectionView else {
return nil
}
return DataSource(collectionView: collectionView) { [weak self] collectionView, indexPath, objectID in
let dataSource = DataSource(collectionView: collectionView) { [weak self] collectionView, indexPath, objectID in
guard let post = try? ContextManager.shared.mainContext.existingObject(with: objectID) as? ReaderPost,
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ReaderTagCell.classNameWithoutNamespaces(), for: indexPath) as? ReaderTagCell else {
return UICollectionViewCell()
Expand All @@ -36,6 +36,20 @@ class ReaderTagCardCellViewModel: NSObject {
isLoggedIn: self?.isLoggedIn ?? AccountHelper.isLoggedIn)
return cell
}
dataSource.supplementaryViewProvider = { [weak self] collectionView, kind, indexPath in
guard let slug = self?.slug,
kind == UICollectionView.elementKindSectionFooter,
let view = collectionView.dequeueReusableSupplementaryView(ofKind: kind,
withReuseIdentifier: ReaderTagFooterView.classNameWithoutNamespaces(),
for: indexPath) as? ReaderTagFooterView else {
return nil
}
view.configure(with: slug) { [weak self] in
self?.onTagButtonTapped()
}
return view
}
return dataSource
}()

private lazy var resultsController: NSFetchedResultsController<ReaderPost> = {
Expand Down Expand Up @@ -103,6 +117,7 @@ class ReaderTagCardCellViewModel: NSObject {

struct Constants {
static let displayPostLimit = 10
static let footerWidth: CGFloat = 200
}

}
Expand Down Expand Up @@ -144,4 +159,10 @@ extension ReaderTagCardCellViewModel: UICollectionViewDelegateFlowLayout {
return cellSize() ?? .zero
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize {
var viewSize = cellSize() ?? .zero
viewSize.width = Constants.footerWidth
return viewSize
}

}
42 changes: 42 additions & 0 deletions WordPress/Classes/ViewRelated/Reader/ReaderTagFooterView.swift
@@ -0,0 +1,42 @@

class ReaderTagFooterView: UICollectionReusableView {

@IBOutlet private weak var contentStackView: UIStackView!
@IBOutlet private weak var arrowButton: UIButton!
@IBOutlet private weak var moreLabel: UILabel!

private var onTapped: (() -> Void)?

override func awakeFromNib() {
super.awakeFromNib()
setupStyles()
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(onViewTapped))
addGestureRecognizer(tapGesture)
}

func configure(with slug: String, onTapped: @escaping () -> Void) {
moreLabel.setText(String(format: Constants.moreText, slug))
self.onTapped = onTapped
}

@objc func onViewTapped() {
onTapped?()
}

@IBAction func onArrowButtonTapped(_ sender: Any) {
onTapped?()
}

private func setupStyles() {
moreLabel.font = WPStyleGuide.fontForTextStyle(.subheadline, fontWeight: .semibold)
arrowButton.configuration?.background.backgroundColor = UIColor(light: .secondarySystemBackground,
dark: .tertiarySystemBackground)
}

private struct Constants {
static let moreText = NSLocalizedString("reader.tags.footer.more",
value: "More from %1$@",
comment: "Label for an action to open more content from a specified Reader tag. %1$@ is the Reader tag.")
}

}
93 changes: 93 additions & 0 deletions WordPress/Classes/ViewRelated/Reader/ReaderTagFooterView.xib
@@ -0,0 +1,93 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_12" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22684"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB" customClass="ReaderTagFooterView" customModule="WordPress" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="200" height="165"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="16" translatesAutoresizingMaskIntoConstraints="NO" id="O1u-cq-UlG">
<rect key="frame" x="8" y="56.999999999999993" width="184" height="76.333333333333314"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="45x-6s-kqU">
<rect key="frame" x="0.0" y="0.0" width="184" height="40"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="h5d-m7-I8W">
<rect key="frame" x="72" y="0.0" width="40" height="40"/>
<constraints>
<constraint firstAttribute="height" constant="40" id="Cu4-R1-by6"/>
<constraint firstAttribute="width" constant="40" id="v0f-90-5G3"/>
</constraints>
<state key="normal" title="Button"/>
<buttonConfiguration key="configuration" style="filled" image="reader-tag-arrow">
<backgroundConfiguration key="background" cornerRadius="20">
<color key="backgroundColor" systemColor="secondarySystemBackgroundColor"/>
</backgroundConfiguration>
<color key="baseForegroundColor" systemColor="labelColor"/>
</buttonConfiguration>
<connections>
<action selector="onArrowButtonTapped:" destination="iN0-l3-epB" eventType="touchUpInside" id="J2Y-ac-1HS"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstItem="h5d-m7-I8W" firstAttribute="centerX" secondItem="45x-6s-kqU" secondAttribute="centerX" id="6uK-ky-xos"/>
<constraint firstItem="h5d-m7-I8W" firstAttribute="height" secondItem="45x-6s-kqU" secondAttribute="height" id="S6l-mb-E7I"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="h5d-m7-I8W" secondAttribute="trailing" id="avw-Dh-vkh"/>
<constraint firstItem="h5d-m7-I8W" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="45x-6s-kqU" secondAttribute="leading" id="drT-U6-Ued"/>
<constraint firstItem="h5d-m7-I8W" firstAttribute="centerY" secondItem="45x-6s-kqU" secondAttribute="centerY" id="uH8-WT-pA6"/>
</constraints>
</view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="kzW-8a-6nX">
<rect key="frame" x="0.0" y="56.000000000000007" width="184" height="20.333333333333336"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<constraints>
<constraint firstItem="kzW-8a-6nX" firstAttribute="leading" secondItem="O1u-cq-UlG" secondAttribute="leading" id="m76-AL-cdH"/>
<constraint firstAttribute="trailing" secondItem="kzW-8a-6nX" secondAttribute="trailing" id="p8f-at-S3k"/>
</constraints>
</stackView>
</subviews>
<viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="kzW-8a-6nX" secondAttribute="trailing" constant="8" id="Cy8-WM-y3E"/>
<constraint firstItem="kzW-8a-6nX" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="vUN-kp-3ea" secondAttribute="leading" constant="8" id="Hrp-pU-Ppl"/>
<constraint firstItem="O1u-cq-UlG" firstAttribute="centerY" secondItem="vUN-kp-3ea" secondAttribute="centerY" id="JfK-lD-z9k"/>
<constraint firstItem="O1u-cq-UlG" firstAttribute="centerX" secondItem="vUN-kp-3ea" secondAttribute="centerX" id="TUT-lC-4bf"/>
</constraints>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<connections>
<outlet property="arrowButton" destination="h5d-m7-I8W" id="b1a-vJ-mf2"/>
<outlet property="contentStackView" destination="O1u-cq-UlG" id="vKB-y9-Jf3"/>
<outlet property="moreLabel" destination="kzW-8a-6nX" id="gt2-bW-iyC"/>
</connections>
<point key="canvasLocation" x="-16.793893129770993" y="-253.87323943661974"/>
</view>
</objects>
<resources>
<image name="reader-tag-arrow" width="24" height="24"/>
<systemColor name="labelColor">
<color white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
<systemColor name="secondarySystemBackgroundColor">
<color red="0.94901960780000005" green="0.94901960780000005" blue="0.96862745100000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</systemColor>
<systemColor name="systemBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
</resources>
</document>
@@ -0,0 +1,16 @@
{
"images" : [
{
"filename" : "reader-tag-arrow-right.svg",
"idiom" : "universal",
"language-direction" : "left-to-right"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"template-rendering-intent" : "template"
}
}
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 7343e2b

Please sign in to comment.