forked from zelo72/mastodon-ios
feat: add sensitive hint label for status media
This commit is contained in:
parent
c4ab4f68c6
commit
41e1b75c62
|
@ -129,6 +129,7 @@
|
|||
"show_post": "Show Post",
|
||||
"show_user_profile": "Show user profile",
|
||||
"content_warning": "Content Warning",
|
||||
"sensitive_content": "Sensitive Content",
|
||||
"media_content_warning": "Tap anywhere to reveal",
|
||||
"tap_to_reveal": "Tap to reveal",
|
||||
"poll": {
|
||||
|
|
|
@ -39,6 +39,8 @@ final class NotificationTimelineViewController: UIViewController, NeedsDependenc
|
|||
return tableView
|
||||
}()
|
||||
|
||||
let cellFrameCache = NSCache<NSNumber, NSValue>()
|
||||
|
||||
deinit {
|
||||
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 {
|
||||
|
||||
@objc private func refreshControlValueChanged(_ sender: UIRefreshControl) {
|
||||
|
@ -162,6 +174,13 @@ extension NotificationTimelineViewController: UITableViewDelegate, AutoGenerateT
|
|||
|
||||
// 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) {
|
||||
guard let item = viewModel.diffableDataSource?.itemIdentifier(for: indexPath) else {
|
||||
return
|
||||
|
@ -172,6 +191,10 @@ extension NotificationTimelineViewController: UITableViewDelegate, AutoGenerateT
|
|||
await viewModel.loadMore(item: item)
|
||||
}
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
|
||||
cacheCellFrame(tableView: tableView, didEndDisplaying: cell, forRowAt: indexPath)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -48,22 +48,7 @@ public final class MediaGridContainerView: UIView {
|
|||
return mediaViews
|
||||
}()
|
||||
|
||||
|
||||
// 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
|
||||
// }()
|
||||
let contentWarningOverlay = ContentWarningOverlayView()
|
||||
|
||||
public override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
|
@ -86,7 +71,8 @@ public final class MediaGridContainerView: UIView {
|
|||
|
||||
extension MediaGridContainerView {
|
||||
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]
|
||||
layout.layout(in: self, mediaView: mediaView)
|
||||
|
||||
// layoutSensitiveToggleButton()
|
||||
// bringSubviewToFront(sensitiveToggleButtonBlurVisualEffectView)
|
||||
layoutContentWarningOverlay()
|
||||
bringSubviewToFront(contentWarningOverlay)
|
||||
|
||||
return mediaView
|
||||
}
|
||||
|
@ -124,8 +110,8 @@ extension MediaGridContainerView {
|
|||
let mediaViews = Array(_mediaViews[0..<layout.count])
|
||||
layout.layout(in: self, mediaViews: mediaViews)
|
||||
|
||||
// layoutSensitiveToggleButton()
|
||||
// bringSubviewToFront(sensitiveToggleButtonBlurVisualEffectView)
|
||||
layoutContentWarningOverlay()
|
||||
bringSubviewToFront(contentWarningOverlay)
|
||||
|
||||
return mediaViews
|
||||
}
|
||||
|
@ -147,34 +133,16 @@ extension MediaGridContainerView {
|
|||
}
|
||||
|
||||
extension MediaGridContainerView {
|
||||
// private func layoutSensitiveToggleButton() {
|
||||
// sensitiveToggleButtonBlurVisualEffectView.translatesAutoresizingMaskIntoConstraints = false
|
||||
// addSubview(sensitiveToggleButtonBlurVisualEffectView)
|
||||
// NSLayoutConstraint.activate([
|
||||
// sensitiveToggleButtonBlurVisualEffectView.topAnchor.constraint(equalTo: topAnchor, constant: 16),
|
||||
// trailingAnchor.constraint(equalTo: sensitiveToggleButtonBlurVisualEffectView.trailingAnchor, constant: 16),
|
||||
// ])
|
||||
//
|
||||
// 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),
|
||||
// ])
|
||||
// }
|
||||
private func layoutContentWarningOverlay() {
|
||||
contentWarningOverlay.translatesAutoresizingMaskIntoConstraints = false
|
||||
addSubview(contentWarningOverlay)
|
||||
NSLayoutConstraint.activate([
|
||||
contentWarningOverlay.topAnchor.constraint(equalTo: topAnchor),
|
||||
contentWarningOverlay.leadingAnchor.constraint(equalTo: leadingAnchor),
|
||||
contentWarningOverlay.trailingAnchor.constraint(equalTo: trailingAnchor),
|
||||
contentWarningOverlay.bottomAnchor.constraint(equalTo: bottomAnchor),
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
extension MediaGridContainerView {
|
||||
|
|
|
@ -385,6 +385,7 @@ extension StatusView.ViewModel {
|
|||
|
||||
$isMediaReveal
|
||||
.sink { isMediaReveal in
|
||||
statusView.mediaGridContainerView.contentWarningOverlay.isHidden = isMediaReveal
|
||||
statusView.mediaGridContainerView.viewModel.isSensitiveToggleButtonDisplay = isMediaReveal
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
|
|
|
@ -7,28 +7,24 @@
|
|||
|
||||
import os.log
|
||||
import UIKit
|
||||
|
||||
public protocol ContentWarningOverlayViewDelegate: AnyObject {
|
||||
func contentWarningOverlayViewDidPressed(_ contentWarningOverlayView: ContentWarningOverlayView)
|
||||
}
|
||||
import MastodonLocalization
|
||||
|
||||
public final class ContentWarningOverlayView: UIView {
|
||||
|
||||
public static let blurVisualEffect = UIBlurEffect(style: .systemUltraThinMaterial)
|
||||
|
||||
|
||||
let logger = Logger(subsystem: "ContentWarningOverlayView", category: "View")
|
||||
|
||||
public weak var delegate: ContentWarningOverlayViewDelegate?
|
||||
|
||||
public let blurVisualEffectView = UIVisualEffectView(effect: ContentWarningOverlayView.blurVisualEffect)
|
||||
public let vibrancyVisualEffectView = UIVisualEffectView(effect: UIVibrancyEffect(blurEffect: ContentWarningOverlayView.blurVisualEffect))
|
||||
// let alertImageView: UIImageView = {
|
||||
// let imageView = UIImageView()
|
||||
// imageView.image = Asset.Indices.exclamationmarkTriangleLarge.image.withRenderingMode(.alwaysTemplate)
|
||||
// return imageView
|
||||
// }()
|
||||
|
||||
public let tapGestureRecognizer = UITapGestureRecognizer.singleTapGestureRecognizer
|
||||
let hintLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .systemFont(ofSize: 18, weight: .regular)
|
||||
label.text = L10n.Common.Controls.Status.tapToReveal
|
||||
label.textAlignment = .center
|
||||
label.textColor = .white.withAlphaComponent(0.7)
|
||||
label.layer.shadowOpacity = 0.3
|
||||
label.layer.shadowOffset = CGSize(width: 0, height: 2)
|
||||
label.layer.shadowRadius = 2
|
||||
label.layer.shadowColor = UIColor.black.cgColor
|
||||
return label
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
|
@ -44,40 +40,12 @@ public final class ContentWarningOverlayView: UIView {
|
|||
|
||||
extension ContentWarningOverlayView {
|
||||
private func _init() {
|
||||
// overlay
|
||||
blurVisualEffectView.translatesAutoresizingMaskIntoConstraints = false
|
||||
addSubview(blurVisualEffectView)
|
||||
hintLabel.translatesAutoresizingMaskIntoConstraints = false
|
||||
addSubview(hintLabel)
|
||||
NSLayoutConstraint.activate([
|
||||
blurVisualEffectView.topAnchor.constraint(equalTo: topAnchor),
|
||||
blurVisualEffectView.leadingAnchor.constraint(equalTo: leadingAnchor),
|
||||
blurVisualEffectView.trailingAnchor.constraint(equalTo: trailingAnchor),
|
||||
blurVisualEffectView.bottomAnchor.constraint(equalTo: bottomAnchor),
|
||||
hintLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 8),
|
||||
trailingAnchor.constraint(equalTo: hintLabel.trailingAnchor, constant: 8),
|
||||
centerYAnchor.constraint(equalTo: hintLabel.centerYAnchor, constant: 10),
|
||||
])
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue