feat: add sensitive hint label for status media

This commit is contained in:
CMK 2022-04-18 16:15:24 +08:00
parent c4ab4f68c6
commit 41e1b75c62
5 changed files with 61 additions and 100 deletions

View File

@ -129,6 +129,7 @@
"show_post": "Show Post", "show_post": "Show Post",
"show_user_profile": "Show user profile", "show_user_profile": "Show user profile",
"content_warning": "Content Warning", "content_warning": "Content Warning",
"sensitive_content": "Sensitive Content",
"media_content_warning": "Tap anywhere to reveal", "media_content_warning": "Tap anywhere to reveal",
"tap_to_reveal": "Tap to reveal", "tap_to_reveal": "Tap to reveal",
"poll": { "poll": {

View File

@ -39,6 +39,8 @@ final class NotificationTimelineViewController: UIViewController, NeedsDependenc
return tableView return tableView
}() }()
let cellFrameCache = NSCache<NSNumber, NSValue>()
deinit { deinit {
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
} }
@ -122,6 +124,16 @@ extension NotificationTimelineViewController {
} }
// MARK: - CellFrameCacheContainer
extension NotificationTimelineViewController: CellFrameCacheContainer {
func keyForCache(tableView: UITableView, indexPath: IndexPath) -> NSNumber? {
guard let diffableDataSource = viewModel.diffableDataSource else { return nil }
guard let item = diffableDataSource.itemIdentifier(for: indexPath) else { return nil }
let key = NSNumber(value: item.hashValue)
return key
}
}
extension NotificationTimelineViewController { extension NotificationTimelineViewController {
@objc private func refreshControlValueChanged(_ sender: UIRefreshControl) { @objc private func refreshControlValueChanged(_ sender: UIRefreshControl) {
@ -162,6 +174,13 @@ extension NotificationTimelineViewController: UITableViewDelegate, AutoGenerateT
// sourcery:end // sourcery:end
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
guard let frame = retrieveCellFrame(tableView: tableView, indexPath: indexPath) else {
return 300
}
return ceil(frame.height)
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
guard let item = viewModel.diffableDataSource?.itemIdentifier(for: indexPath) else { guard let item = viewModel.diffableDataSource?.itemIdentifier(for: indexPath) else {
return return
@ -173,6 +192,10 @@ extension NotificationTimelineViewController: UITableViewDelegate, AutoGenerateT
} }
} }
func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
cacheCellFrame(tableView: tableView, didEndDisplaying: cell, forRowAt: indexPath)
}
} }
// MARK: - NotificationTableViewCellDelegate // MARK: - NotificationTableViewCellDelegate

View File

@ -48,22 +48,7 @@ public final class MediaGridContainerView: UIView {
return mediaViews return mediaViews
}() }()
let contentWarningOverlay = ContentWarningOverlayView()
// let sensitiveToggleButtonBlurVisualEffectView: UIVisualEffectView = {
// let visualEffectView = UIVisualEffectView(effect: ContentWarningOverlayView.blurVisualEffect)
// visualEffectView.layer.masksToBounds = true
// visualEffectView.layer.cornerRadius = MediaGridContainerView.sensitiveToggleButtonSize.width / 2
// visualEffectView.layer.cornerCurve = .continuous
// return visualEffectView
// }()
// let sensitiveToggleButtonVibrancyVisualEffectView = UIVisualEffectView(effect: UIVibrancyEffect(blurEffect: ContentWarningOverlayView.blurVisualEffect))
// let sensitiveToggleButton: HitTestExpandedButton = {
// let button = HitTestExpandedButton(type: .system)
// button.contentEdgeInsets = UIEdgeInsets(top: 4, left: 4, bottom: 4, right: 4)
// button.imageView?.contentMode = .scaleAspectFit
// button.setImage(UIImage(systemName: "eye.slash.fill"), for: .normal)
// return button
// }()
public override init(frame: CGRect) { public override init(frame: CGRect) {
super.init(frame: frame) super.init(frame: frame)
@ -86,7 +71,8 @@ public final class MediaGridContainerView: UIView {
extension MediaGridContainerView { extension MediaGridContainerView {
private func _init() { private func _init() {
// sensitiveToggleButton.addTarget(self, action: #selector(MediaGridContainerView.sensitiveToggleButtonDidPressed(_:)), for: .touchUpInside) contentWarningOverlay.isUserInteractionEnabled = false
contentWarningOverlay.isHidden = true
} }
} }
@ -112,8 +98,8 @@ extension MediaGridContainerView {
let mediaView = _mediaViews[0] let mediaView = _mediaViews[0]
layout.layout(in: self, mediaView: mediaView) layout.layout(in: self, mediaView: mediaView)
// layoutSensitiveToggleButton() layoutContentWarningOverlay()
// bringSubviewToFront(sensitiveToggleButtonBlurVisualEffectView) bringSubviewToFront(contentWarningOverlay)
return mediaView return mediaView
} }
@ -124,8 +110,8 @@ extension MediaGridContainerView {
let mediaViews = Array(_mediaViews[0..<layout.count]) let mediaViews = Array(_mediaViews[0..<layout.count])
layout.layout(in: self, mediaViews: mediaViews) layout.layout(in: self, mediaViews: mediaViews)
// layoutSensitiveToggleButton() layoutContentWarningOverlay()
// bringSubviewToFront(sensitiveToggleButtonBlurVisualEffectView) bringSubviewToFront(contentWarningOverlay)
return mediaViews return mediaViews
} }
@ -147,34 +133,16 @@ extension MediaGridContainerView {
} }
extension MediaGridContainerView { extension MediaGridContainerView {
// private func layoutSensitiveToggleButton() { private func layoutContentWarningOverlay() {
// sensitiveToggleButtonBlurVisualEffectView.translatesAutoresizingMaskIntoConstraints = false contentWarningOverlay.translatesAutoresizingMaskIntoConstraints = false
// addSubview(sensitiveToggleButtonBlurVisualEffectView) addSubview(contentWarningOverlay)
// NSLayoutConstraint.activate([ NSLayoutConstraint.activate([
// sensitiveToggleButtonBlurVisualEffectView.topAnchor.constraint(equalTo: topAnchor, constant: 16), contentWarningOverlay.topAnchor.constraint(equalTo: topAnchor),
// trailingAnchor.constraint(equalTo: sensitiveToggleButtonBlurVisualEffectView.trailingAnchor, constant: 16), contentWarningOverlay.leadingAnchor.constraint(equalTo: leadingAnchor),
// ]) contentWarningOverlay.trailingAnchor.constraint(equalTo: trailingAnchor),
// contentWarningOverlay.bottomAnchor.constraint(equalTo: bottomAnchor),
// sensitiveToggleButtonVibrancyVisualEffectView.translatesAutoresizingMaskIntoConstraints = false ])
// sensitiveToggleButtonBlurVisualEffectView.contentView.addSubview(sensitiveToggleButtonVibrancyVisualEffectView) }
// NSLayoutConstraint.activate([
// sensitiveToggleButtonVibrancyVisualEffectView.topAnchor.constraint(equalTo: sensitiveToggleButtonBlurVisualEffectView.contentView.topAnchor),
// sensitiveToggleButtonVibrancyVisualEffectView.leadingAnchor.constraint(equalTo: sensitiveToggleButtonBlurVisualEffectView.contentView.leadingAnchor),
// sensitiveToggleButtonVibrancyVisualEffectView.trailingAnchor.constraint(equalTo: sensitiveToggleButtonBlurVisualEffectView.contentView.trailingAnchor),
// sensitiveToggleButtonVibrancyVisualEffectView.bottomAnchor.constraint(equalTo: sensitiveToggleButtonBlurVisualEffectView.contentView.bottomAnchor),
// ])
//
// sensitiveToggleButton.translatesAutoresizingMaskIntoConstraints = false
// sensitiveToggleButtonVibrancyVisualEffectView.contentView.addSubview(sensitiveToggleButton)
// NSLayoutConstraint.activate([
// sensitiveToggleButton.topAnchor.constraint(equalTo: sensitiveToggleButtonVibrancyVisualEffectView.contentView.topAnchor),
// sensitiveToggleButton.leadingAnchor.constraint(equalTo: sensitiveToggleButtonVibrancyVisualEffectView.contentView.leadingAnchor),
// sensitiveToggleButtonVibrancyVisualEffectView.contentView.trailingAnchor.constraint(equalTo: sensitiveToggleButton.trailingAnchor),
// sensitiveToggleButtonVibrancyVisualEffectView.contentView.bottomAnchor.constraint(equalTo: sensitiveToggleButton.bottomAnchor),
// sensitiveToggleButton.widthAnchor.constraint(equalToConstant: MediaGridContainerView.sensitiveToggleButtonSize.width).priority(.required - 1),
// sensitiveToggleButton.heightAnchor.constraint(equalToConstant: MediaGridContainerView.sensitiveToggleButtonSize.height).priority(.required - 1),
// ])
// }
} }
extension MediaGridContainerView { extension MediaGridContainerView {

View File

@ -385,6 +385,7 @@ extension StatusView.ViewModel {
$isMediaReveal $isMediaReveal
.sink { isMediaReveal in .sink { isMediaReveal in
statusView.mediaGridContainerView.contentWarningOverlay.isHidden = isMediaReveal
statusView.mediaGridContainerView.viewModel.isSensitiveToggleButtonDisplay = isMediaReveal statusView.mediaGridContainerView.viewModel.isSensitiveToggleButtonDisplay = isMediaReveal
} }
.store(in: &disposeBag) .store(in: &disposeBag)

View File

@ -7,28 +7,24 @@
import os.log import os.log
import UIKit import UIKit
import MastodonLocalization
public protocol ContentWarningOverlayViewDelegate: AnyObject {
func contentWarningOverlayViewDidPressed(_ contentWarningOverlayView: ContentWarningOverlayView)
}
public final class ContentWarningOverlayView: UIView { public final class ContentWarningOverlayView: UIView {
public static let blurVisualEffect = UIBlurEffect(style: .systemUltraThinMaterial)
let logger = Logger(subsystem: "ContentWarningOverlayView", category: "View") let logger = Logger(subsystem: "ContentWarningOverlayView", category: "View")
public weak var delegate: ContentWarningOverlayViewDelegate? let hintLabel: UILabel = {
let label = UILabel()
public let blurVisualEffectView = UIVisualEffectView(effect: ContentWarningOverlayView.blurVisualEffect) label.font = .systemFont(ofSize: 18, weight: .regular)
public let vibrancyVisualEffectView = UIVisualEffectView(effect: UIVibrancyEffect(blurEffect: ContentWarningOverlayView.blurVisualEffect)) label.text = L10n.Common.Controls.Status.tapToReveal
// let alertImageView: UIImageView = { label.textAlignment = .center
// let imageView = UIImageView() label.textColor = .white.withAlphaComponent(0.7)
// imageView.image = Asset.Indices.exclamationmarkTriangleLarge.image.withRenderingMode(.alwaysTemplate) label.layer.shadowOpacity = 0.3
// return imageView label.layer.shadowOffset = CGSize(width: 0, height: 2)
// }() label.layer.shadowRadius = 2
label.layer.shadowColor = UIColor.black.cgColor
public let tapGestureRecognizer = UITapGestureRecognizer.singleTapGestureRecognizer return label
}()
override init(frame: CGRect) { override init(frame: CGRect) {
super.init(frame: frame) super.init(frame: frame)
@ -44,40 +40,12 @@ public final class ContentWarningOverlayView: UIView {
extension ContentWarningOverlayView { extension ContentWarningOverlayView {
private func _init() { private func _init() {
// overlay hintLabel.translatesAutoresizingMaskIntoConstraints = false
blurVisualEffectView.translatesAutoresizingMaskIntoConstraints = false addSubview(hintLabel)
addSubview(blurVisualEffectView)
NSLayoutConstraint.activate([ NSLayoutConstraint.activate([
blurVisualEffectView.topAnchor.constraint(equalTo: topAnchor), hintLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 8),
blurVisualEffectView.leadingAnchor.constraint(equalTo: leadingAnchor), trailingAnchor.constraint(equalTo: hintLabel.trailingAnchor, constant: 8),
blurVisualEffectView.trailingAnchor.constraint(equalTo: trailingAnchor), centerYAnchor.constraint(equalTo: hintLabel.centerYAnchor, constant: 10),
blurVisualEffectView.bottomAnchor.constraint(equalTo: bottomAnchor),
]) ])
vibrancyVisualEffectView.translatesAutoresizingMaskIntoConstraints = false
blurVisualEffectView.contentView.addSubview(vibrancyVisualEffectView)
NSLayoutConstraint.activate([
vibrancyVisualEffectView.topAnchor.constraint(equalTo: blurVisualEffectView.contentView.topAnchor),
vibrancyVisualEffectView.leadingAnchor.constraint(equalTo: blurVisualEffectView.contentView.leadingAnchor),
vibrancyVisualEffectView.trailingAnchor.constraint(equalTo: blurVisualEffectView.contentView.trailingAnchor),
vibrancyVisualEffectView.bottomAnchor.constraint(equalTo: blurVisualEffectView.contentView.bottomAnchor),
])
// alertImageView.translatesAutoresizingMaskIntoConstraints = false
// vibrancyVisualEffectView.contentView.addSubview(alertImageView)
// NSLayoutConstraint.activate([
// alertImageView.centerXAnchor.constraint(equalTo: vibrancyVisualEffectView.contentView.centerXAnchor),
// alertImageView.centerYAnchor.constraint(equalTo: vibrancyVisualEffectView.contentView.centerYAnchor),
// ])
tapGestureRecognizer.addTarget(self, action: #selector(ContentWarningOverlayView.tapGestureRecognizerHandler(_:)))
addGestureRecognizer(tapGestureRecognizer)
}
}
extension ContentWarningOverlayView {
@objc private func tapGestureRecognizerHandler(_ sender: UITapGestureRecognizer) {
logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)")
delegate?.contentWarningOverlayViewDidPressed(self)
} }
} }