Compare commits

...

3 Commits

Author SHA1 Message Date
Shadowfacts bb3e1b44b1 Hide live text controls when other gallery controls are hidden
Closes #189
2022-10-28 19:16:00 -04:00
Shadowfacts 868df25417 Disable pruning offscreen rows in new timelines
I don't think this is actually necessary, the system should kill us
often enough that the amount of items in the data source doesn't become
unmanageable.

Making modifications to the data source in viewDidDisappear was causing
the collection view's contentOffset to change to be scrolled to top
(roughly) when the view became visible again.

Disabling it also fixes several issues caused by updating the data
source even when there were no changes.

Closes #193
Closes #192
Closes #187
Closes #186
2022-10-28 19:05:07 -04:00
Shadowfacts 2801f65e67 Fix reblog labels in new cells not being tappable
Closes #197
2022-10-28 18:48:30 -04:00
4 changed files with 47 additions and 22 deletions

View File

@ -14,6 +14,7 @@ import VisionKit
protocol LargeImageContentView: UIView { protocol LargeImageContentView: UIView {
var animationImage: UIImage? { get } var animationImage: UIImage? { get }
var activityItemsForSharing: [Any] { get } var activityItemsForSharing: [Any] { get }
func setControlsVisible(_ controlsVisible: Bool)
func grayscaleStateChanged() func grayscaleStateChanged()
} }
@ -22,6 +23,9 @@ class LargeImageImageContentView: UIImageView, LargeImageContentView {
#if !targetEnvironment(macCatalyst) #if !targetEnvironment(macCatalyst)
@available(iOS 16.0, *) @available(iOS 16.0, *)
private static let analyzer = ImageAnalyzer() private static let analyzer = ImageAnalyzer()
private var _analysisInteraction: AnyObject?
@available(iOS 16.0, *)
private var analysisInteraction: ImageAnalysisInteraction? { _analysisInteraction as? ImageAnalysisInteraction }
#endif #endif
var animationImage: UIImage? { image! } var animationImage: UIImage? { image! }
@ -45,6 +49,7 @@ class LargeImageImageContentView: UIImageView, LargeImageContentView {
if #available(iOS 16.0, *), if #available(iOS 16.0, *),
ImageAnalyzer.isSupported { ImageAnalyzer.isSupported {
let interaction = ImageAnalysisInteraction() let interaction = ImageAnalysisInteraction()
self._analysisInteraction = interaction
interaction.delegate = self interaction.delegate = self
interaction.preferredInteractionTypes = .automatic interaction.preferredInteractionTypes = .automatic
addInteraction(interaction) addInteraction(interaction)
@ -64,6 +69,17 @@ class LargeImageImageContentView: UIImageView, LargeImageContentView {
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
} }
func setControlsVisible(_ controlsVisible: Bool) {
#if !targetEnvironment(macCatalyst)
if #available(iOS 16.0, *),
let analysisInteraction {
// note: passing animated: true here doesn't seem to do anything by itself as of iOS 16.2 (20C5032e)
// so the LargeImageViewController handles animating, but we still need to pass true here otherwise it doesn't animate
analysisInteraction.setSupplementaryInterfaceHidden(!controlsVisible, animated: true)
}
#endif
}
func grayscaleStateChanged() { func grayscaleStateChanged() {
guard let data = sourceData else { guard let data = sourceData else {
return return
@ -113,6 +129,9 @@ class LargeImageGifContentView: GIFImageView, LargeImageContentView {
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
} }
func setControlsVisible(_ controlsVisible: Bool) {
}
func grayscaleStateChanged() { func grayscaleStateChanged() {
// todo // todo
} }
@ -151,6 +170,9 @@ class LargeImageGifvContentView: GifvAttachmentView, LargeImageContentView {
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
} }
func setControlsVisible(_ controlsVisible: Bool) {
}
func grayscaleStateChanged() { func grayscaleStateChanged() {
// no-op, GifvAttachmentView observes the grayscale state itself // no-op, GifvAttachmentView observes the grayscale state itself
} }

View File

@ -174,6 +174,7 @@ class LargeImageViewController: UIViewController, UIScrollViewDelegate, LargeIma
self.controlsVisible = controlsVisible self.controlsVisible = controlsVisible
if animated { if animated {
UIView.animate(withDuration: 0.2) { UIView.animate(withDuration: 0.2) {
self.contentView.setControlsVisible(controlsVisible)
self.updateControlsView() self.updateControlsView()
} }
} else { } else {

View File

@ -160,7 +160,7 @@ class TimelineViewController: UIViewController, TimelineLikeCollectionViewContro
override func viewDidDisappear(_ animated: Bool) { override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated) super.viewDidDisappear(animated)
pruneOffscreenRows() // pruneOffscreenRows()
} }
private func removeTimelineDescriptionCell() { private func removeTimelineDescriptionCell() {
@ -170,27 +170,28 @@ class TimelineViewController: UIViewController, TimelineLikeCollectionViewContro
isShowingTimelineDescription = false isShowingTimelineDescription = false
} }
private func pruneOffscreenRows() { // private func pruneOffscreenRows() {
guard let lastVisibleIndexPath = collectionView.indexPathsForVisibleItems.last else { // guard let lastVisibleIndexPath = collectionView.indexPathsForVisibleItems.last else {
return // return
} // }
var snapshot = dataSource.snapshot() // var snapshot = dataSource.snapshot()
guard snapshot.indexOfSection(.statuses) != nil else { // guard snapshot.indexOfSection(.statuses) != nil else {
return // return
} // }
let items = snapshot.itemIdentifiers(inSection: .statuses) // let items = snapshot.itemIdentifiers(inSection: .statuses)
let pageSize = 20 // let pageSize = 20
let numberOfPagesToPrune = (items.count - lastVisibleIndexPath.row - 1) / pageSize // let numberOfPagesToPrune = (items.count - lastVisibleIndexPath.row - 1) / pageSize
if numberOfPagesToPrune > 0 { // if numberOfPagesToPrune > 0 {
let itemsToRemove = Array(items.suffix(numberOfPagesToPrune * pageSize)) // let itemsToRemove = Array(items.suffix(numberOfPagesToPrune * pageSize))
snapshot.deleteItems(itemsToRemove) // snapshot.deleteItems(itemsToRemove)
} //
dataSource.apply(snapshot, animatingDifferences: false) // dataSource.apply(snapshot, animatingDifferences: false)
//
if case .status(id: let id, state: _) = snapshot.itemIdentifiers(inSection: .statuses).last { // if case .status(id: let id, state: _) = snapshot.itemIdentifiers(inSection: .statuses).last {
older = .before(id: id, count: nil) // older = .before(id: id, count: nil)
} // }
} // }
// }
@objc func refresh() { @objc func refresh() {
Task { Task {

View File

@ -18,6 +18,7 @@ class TimelineStatusCollectionViewCell: UICollectionViewListCell, StatusCollecti
$0.textColor = .secondaryLabel $0.textColor = .secondaryLabel
// this needs to have a higher priorty than the content container's zero height constraint // this needs to have a higher priorty than the content container's zero height constraint
$0.setContentHuggingPriority(.defaultHigh, for: .vertical) $0.setContentHuggingPriority(.defaultHigh, for: .vertical)
$0.isUserInteractionEnabled = true
$0.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(reblogLabelPressed))) $0.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(reblogLabelPressed)))
} }