-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Reader: Show empty state for individual rows (#23144)
- Loading branch information
Showing
6 changed files
with
257 additions
and
25 deletions.
There are no files selected for viewing
18 changes: 18 additions & 0 deletions
18
WordPress/Classes/Utility/CollectionView/AdaptiveCollectionViewFlowLayout.swift
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
/// A flow layout that properly invalidates the layout when the collection view's bounds changed, | ||
/// (e.g., orientation changes). | ||
/// | ||
/// This method ensures that we work with the latest/correct bounds after the size change, and potentially | ||
/// avoids race conditions where we might get incorrect bounds while the view is still in transition. | ||
/// | ||
/// See: https://developer.apple.com/documentation/uikit/uicollectionviewlayout/1617781-shouldinvalidatelayout | ||
class AdaptiveCollectionViewFlowLayout: UICollectionViewFlowLayout { | ||
|
||
override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool { | ||
// NOTE: Apparently we need to *manually* invalidate the layout because `invalidateLayout()` | ||
// is NOT called after this method returns true. | ||
if let collectionView, collectionView.bounds.size != newBounds.size { | ||
invalidateLayout() | ||
} | ||
return super.shouldInvalidateLayout(forBoundsChange: newBounds) | ||
} | ||
} |
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
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
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
120 changes: 120 additions & 0 deletions
120
WordPress/Classes/ViewRelated/Reader/ReaderTagCardEmptyCell.swift
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
import SwiftUI | ||
import DesignSystem | ||
|
||
class ReaderTagCardEmptyCell: UICollectionViewCell, Reusable { | ||
|
||
var tagTitle: String { | ||
get { | ||
swiftUIView.tagTitle | ||
} | ||
set { | ||
swiftUIView.tagTitle = newValue | ||
} | ||
} | ||
|
||
var retryHandler: (() -> Void)? = nil | ||
|
||
private lazy var swiftUIView: ReaderTagCardEmptyCellView = { | ||
ReaderTagCardEmptyCellView(buttonTapped: { [weak self] in | ||
self?.retryHandler?() | ||
}) | ||
}() | ||
|
||
required init?(coder: NSCoder) { | ||
fatalError("init(coder:) has not been implemented") | ||
} | ||
|
||
override init(frame: CGRect) { | ||
super.init(frame: .zero) | ||
|
||
let viewToEmbed = UIView.embedSwiftUIView(swiftUIView) | ||
contentView.addSubview(viewToEmbed) | ||
contentView.pinSubviewToAllEdges(viewToEmbed) | ||
} | ||
|
||
override func prepareForReuse() { | ||
tagTitle = String() | ||
retryHandler = nil | ||
super.prepareForReuse() | ||
} | ||
|
||
func configure(tagTitle: String, retryHandler: (() -> Void)?) { | ||
self.tagTitle = tagTitle | ||
self.retryHandler = retryHandler | ||
} | ||
} | ||
|
||
// MARK: - SwiftUI | ||
|
||
private struct ReaderTagCardEmptyCellView: View { | ||
|
||
var tagTitle = String() | ||
var buttonTapped: (() -> Void)? = nil | ||
|
||
@ScaledMetric(relativeTo: Font.TextStyle.callout) | ||
private var iconLength = 32.0 | ||
|
||
var body: some View { | ||
VStack(spacing: .DS.Padding.double) { | ||
Image(systemName: "wifi.slash") | ||
.resizable() | ||
.frame(width: iconLength, height: iconLength) | ||
.foregroundStyle(Color.DS.Foreground.secondary) | ||
|
||
// added to double the padding between the Image and the VStack. | ||
Spacer().frame(height: .hairlineBorderWidth) | ||
|
||
VStack(spacing: .DS.Padding.single) { | ||
Text(Strings.title) | ||
.font(.callout) | ||
.fontWeight(.semibold) | ||
|
||
Text(Strings.body) | ||
.font(.callout) | ||
.foregroundStyle(.secondary) | ||
.multilineTextAlignment(.center) | ||
} | ||
|
||
Button { | ||
buttonTapped?() | ||
} label: { | ||
Text(Strings.buttonTitle) | ||
.font(.callout) | ||
.padding(.vertical, .DS.Padding.half) | ||
.padding(.horizontal, .DS.Padding.single) | ||
} | ||
} | ||
.padding(.DS.Padding.single) | ||
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center) | ||
} | ||
|
||
private struct Strings { | ||
static let title = NSLocalizedString( | ||
"reader.tagStream.cards.emptyView.error.title", | ||
value: "Posts failed to load", | ||
comment: """ | ||
The title of an empty state component for one of the tags in the tag stream. | ||
This empty state component is displayed only when the app fails to load posts under this tag. | ||
""" | ||
) | ||
|
||
static let body = NSLocalizedString( | ||
"reader.tagStream.cards.emptyView.error.body", | ||
value: "We couldn't load posts from this tag right now", | ||
comment: """ | ||
The body text of an empty state component for one of the tags in the tag stream. | ||
This empty state component is displayed only when the app fails to load posts under this tag. | ||
""" | ||
) | ||
|
||
static let buttonTitle = NSLocalizedString( | ||
"reader.tagStream.cards.emptyView.button", | ||
value: "Retry", | ||
comment: """ | ||
Verb. The button title of an empty state component for one of the tags in the tag stream. | ||
This empty state component is displayed only when the app fails to load posts under this tag. | ||
When tapped, the app will try to reload posts under this tag. | ||
""" | ||
) | ||
} | ||
} |
Oops, something went wrong.