feat: add content warning toggle button

This commit is contained in:
CMK 2022-02-11 20:21:28 +08:00
parent d3e8f85cb3
commit 0bc128ba79
14 changed files with 374 additions and 184 deletions

View File

@ -283,23 +283,23 @@ extension DataSourceFacade {
guard let _status = status.object(in: dependency.context.managedObjectContext) else { return }
let status = _status.reblog ?? _status
let isToggled = status.isContentSensitiveToggled || status.isMediaSensitiveToggled
status.update(isContentSensitiveToggled: !isToggled)
status.update(isMediaSensitiveToggled: !isToggled)
let allToggled = status.isContentSensitiveToggled && status.isMediaSensitiveToggled
status.update(isContentSensitiveToggled: !allToggled)
status.update(isMediaSensitiveToggled: !allToggled)
}
}
static func responseToToggleMediaSensitiveAction(
dependency: NeedsDependency,
status: ManagedObjectRecord<Status>
) async throws {
try await dependency.context.managedObjectContext.perform {
guard let _status = status.object(in: dependency.context.managedObjectContext) else { return }
let status = _status.reblog ?? _status
status.update(isMediaSensitiveToggled: !status.isMediaSensitiveToggled)
}
}
// static func responseToToggleMediaSensitiveAction(
// dependency: NeedsDependency,
// status: ManagedObjectRecord<Status>
// ) async throws {
// try await dependency.context.managedObjectContext.perform {
// guard let _status = status.object(in: dependency.context.managedObjectContext) else { return }
// let status = _status.reblog ?? _status
//
// status.update(isMediaSensitiveToggled: !status.isMediaSensitiveToggled)
// }
// }
}

View File

@ -222,12 +222,11 @@ extension NotificationTableViewCellDelegate where Self: DataSourceProvider {
)
}
func tableViewCell(
_ cell: UITableViewCell, notificationView: NotificationView,
_ cell: UITableViewCell,
notificationView: NotificationView,
statusView: StatusView,
spoilerBannerViewDidPressed bannerView: SpoilerBannerView
spoilerOverlayViewDidPressed overlayView: SpoilerOverlayView
) {
Task {
let source = DataSourceItem.Source(tableViewCell: cell, indexPath: nil)
@ -256,6 +255,38 @@ extension NotificationTableViewCellDelegate where Self: DataSourceProvider {
}
// func tableViewCell(
// _ cell: UITableViewCell, notificationView: NotificationView,
// statusView: StatusView,
// spoilerBannerViewDidPressed bannerView: SpoilerBannerView
// ) {
// Task {
// let source = DataSourceItem.Source(tableViewCell: cell, indexPath: nil)
// guard let item = await item(from: source) else {
// assertionFailure()
// return
// }
// guard case let .notification(notification) = item else {
// assertionFailure("only works for notification item")
// return
// }
// let _status: ManagedObjectRecord<Status>? = try await self.context.managedObjectContext.perform {
// guard let notification = notification.object(in: self.context.managedObjectContext) else { return nil }
// guard let status = notification.status else { return nil }
// return .init(objectID: status.objectID)
// }
// guard let status = _status else {
// assertionFailure()
// return
// }
// try await DataSourceFacade.responseToToggleSensitiveAction(
// dependency: self,
// status: status
// )
// } // end Task
// }
func tableViewCell(
_ cell: UITableViewCell,
notificationView: NotificationView,

View File

@ -126,7 +126,7 @@ extension StatusTableViewCellDelegate where Self: DataSourceProvider & MediaPrev
}
guard !needsToggleMediaSensitive else {
try await DataSourceFacade.responseToToggleMediaSensitiveAction(
try await DataSourceFacade.responseToToggleSensitiveAction(
dependency: self,
status: status
)
@ -362,6 +362,29 @@ extension StatusTableViewCellDelegate where Self: DataSourceProvider {
// MARK: - content warning
extension StatusTableViewCellDelegate where Self: DataSourceProvider {
func tableViewCell(
_ cell: UITableViewCell,
statusView: StatusView,
contentSensitiveeToggleButtonDidPressed button: UIButton
) {
Task {
let source = DataSourceItem.Source(tableViewCell: cell, indexPath: nil)
guard let item = await item(from: source) else {
assertionFailure()
return
}
guard case let .status(status) = item else {
assertionFailure("only works for status data provider")
return
}
try await DataSourceFacade.responseToToggleSensitiveAction(
dependency: self,
status: status
)
} // end Task
}
func tableViewCell(
_ cell: UITableViewCell,
statusView: StatusView,
@ -384,27 +407,27 @@ extension StatusTableViewCellDelegate where Self: DataSourceProvider {
} // end Task
}
func tableViewCell(
_ cell: UITableViewCell,
statusView: StatusView,
spoilerBannerViewDidPressed bannerView: SpoilerBannerView
) {
Task {
let source = DataSourceItem.Source(tableViewCell: cell, indexPath: nil)
guard let item = await item(from: source) else {
assertionFailure()
return
}
guard case let .status(status) = item else {
assertionFailure("only works for status data provider")
return
}
try await DataSourceFacade.responseToToggleSensitiveAction(
dependency: self,
status: status
)
} // end Task
}
// func tableViewCell(
// _ cell: UITableViewCell,
// statusView: StatusView,
// spoilerBannerViewDidPressed bannerView: SpoilerBannerView
// ) {
// Task {
// let source = DataSourceItem.Source(tableViewCell: cell, indexPath: nil)
// guard let item = await item(from: source) else {
// assertionFailure()
// return
// }
// guard case let .status(status) = item else {
// assertionFailure("only works for status data provider")
// return
// }
// try await DataSourceFacade.responseToToggleSensitiveAction(
// dependency: self,
// status: status
// )
// } // end Task
// }
func tableViewCell(
_ cell: UITableViewCell,
@ -422,7 +445,7 @@ extension StatusTableViewCellDelegate where Self: DataSourceProvider {
assertionFailure("only works for status data provider")
return
}
try await DataSourceFacade.responseToToggleMediaSensitiveAction(
try await DataSourceFacade.responseToToggleSensitiveAction(
dependency: self,
status: status
)

View File

@ -27,12 +27,10 @@ protocol NotificationTableViewCellDelegate: AnyObject, AutoGenerateProtocolDeleg
func tableViewCell(_ cell: UITableViewCell, notificationView: NotificationView, menuButton button: UIButton, didSelectAction action: MastodonMenu.Action)
func tableViewCell(_ cell: UITableViewCell, notificationView: NotificationView, statusView: StatusView, metaText: MetaText, didSelectMeta meta: Meta)
func tableViewCell(_ cell: UITableViewCell, notificationView: NotificationView, statusView: StatusView, spoilerOverlayViewDidPressed overlayView: SpoilerOverlayView)
func tableViewCell(_ cell: UITableViewCell, notificationView: NotificationView, statusView: StatusView, spoilerBannerViewDidPressed bannerView: SpoilerBannerView)
func tableViewCell(_ cell: UITableViewCell, notificationView: NotificationView, statusView: StatusView, actionToolbarContainer: ActionToolbarContainer, buttonDidPressed button: UIButton, action: ActionToolbarContainer.Action)
func tableViewCell(_ cell: UITableViewCell, notificationView: NotificationView, quoteStatusView: StatusView, authorAvatarButtonDidPressed button: AvatarButton)
func tableViewCell(_ cell: UITableViewCell, notificationView: NotificationView, quoteStatusView: StatusView, metaText: MetaText, didSelectMeta meta: Meta)
func tableViewCell(_ cell: UITableViewCell, notificationView: NotificationView, quoteStatusView: StatusView, spoilerOverlayViewDidPressed overlayView: SpoilerOverlayView)
func tableViewCell(_ cell: UITableViewCell, notificationView: NotificationView, quoteStatusView: StatusView, spoilerBannerViewDidPressed bannerView: SpoilerBannerView)
func tableViewCell(_ cell: UITableViewCell, notificationView: NotificationView, accessibilityActivate: Void)
// sourcery:end
}
@ -57,10 +55,6 @@ extension NotificationViewDelegate where Self: NotificationViewContainerTableVie
delegate?.tableViewCell(self, notificationView: notificationView, statusView: statusView, spoilerOverlayViewDidPressed: overlayView)
}
func notificationView(_ notificationView: NotificationView, statusView: StatusView, spoilerBannerViewDidPressed bannerView: SpoilerBannerView) {
delegate?.tableViewCell(self, notificationView: notificationView, statusView: statusView, spoilerBannerViewDidPressed: bannerView)
}
func notificationView(_ notificationView: NotificationView, statusView: StatusView, actionToolbarContainer: ActionToolbarContainer, buttonDidPressed button: UIButton, action: ActionToolbarContainer.Action) {
delegate?.tableViewCell(self, notificationView: notificationView, statusView: statusView, actionToolbarContainer: actionToolbarContainer, buttonDidPressed: button, action: action)
}
@ -77,10 +71,6 @@ extension NotificationViewDelegate where Self: NotificationViewContainerTableVie
delegate?.tableViewCell(self, notificationView: notificationView, quoteStatusView: quoteStatusView, spoilerOverlayViewDidPressed: overlayView)
}
func notificationView(_ notificationView: NotificationView, quoteStatusView: StatusView, spoilerBannerViewDidPressed bannerView: SpoilerBannerView) {
delegate?.tableViewCell(self, notificationView: notificationView, quoteStatusView: quoteStatusView, spoilerBannerViewDidPressed: bannerView)
}
func notificationView(_ notificationView: NotificationView, accessibilityActivate: Void) {
delegate?.tableViewCell(self, notificationView: notificationView, accessibilityActivate: accessibilityActivate)
}

View File

@ -175,46 +175,4 @@ extension NotificationTimelineViewController: UITableViewDelegate, AutoGenerateT
}
// MARK: - NotificationTableViewCellDelegate
extension NotificationTimelineViewController: NotificationTableViewCellDelegate {
func tableViewCell(
_ cell: UITableViewCell,
notificationView: NotificationView,
statusView: StatusView,
spoilerOverlayViewDidPressed overlayView: SpoilerOverlayView
) {
guard let diffableDataSource = viewModel.diffableDataSource else { return }
guard let indexPath = tableView.indexPath(for: cell) else { return }
guard let reloadItem = diffableDataSource.itemIdentifier(for: indexPath) else { return }
Task {
let source = DataSourceItem.Source(tableViewCell: cell, indexPath: nil)
guard let item = await item(from: source) else {
assertionFailure()
return
}
guard case let .notification(notification) = item else {
assertionFailure("only works for notification item")
return
}
let _status: ManagedObjectRecord<Status>? = try await self.context.managedObjectContext.perform {
guard let notification = notification.object(in: self.context.managedObjectContext) else { return nil }
guard let status = notification.status else { return nil }
return .init(objectID: status.objectID)
}
guard let status = _status else {
assertionFailure()
return
}
try await DataSourceFacade.responseToToggleSensitiveAction(
dependency: self,
status: status
)
// var snapshot = diffableDataSource.snapshot()
// snapshot.reloadItems([reloadItem])
// diffableDataSource.apply(snapshot, animatingDifferences: false)
} // end Task
}
}
extension NotificationTimelineViewController: NotificationTableViewCellDelegate { }

View File

@ -25,6 +25,7 @@ protocol StatusTableViewCellDelegate: AnyObject, AutoGenerateProtocolDelegate {
// sourcery:inline:StatusTableViewCellDelegate.AutoGenerateProtocolDelegate
func tableViewCell(_ cell: UITableViewCell, statusView: StatusView, headerDidPressed header: UIView)
func tableViewCell(_ cell: UITableViewCell, statusView: StatusView, authorAvatarButtonDidPressed button: AvatarButton)
func tableViewCell(_ cell: UITableViewCell, statusView: StatusView, contentSensitiveeToggleButtonDidPressed button: UIButton)
func tableViewCell(_ cell: UITableViewCell, statusView: StatusView, metaText: MetaText, didSelectMeta meta: Meta)
func tableViewCell(_ cell: UITableViewCell, statusView: StatusView, mediaGridContainerView: MediaGridContainerView, mediaView: MediaView, didSelectMediaViewAt index: Int)
func tableViewCell(_ cell: UITableViewCell, statusView: StatusView, pollTableView tableView: UITableView, didSelectRowAt indexPath: IndexPath)
@ -32,7 +33,6 @@ protocol StatusTableViewCellDelegate: AnyObject, AutoGenerateProtocolDelegate {
func tableViewCell(_ cell: UITableViewCell, statusView: StatusView, actionToolbarContainer: ActionToolbarContainer, buttonDidPressed button: UIButton, action: ActionToolbarContainer.Action)
func tableViewCell(_ cell: UITableViewCell, statusView: StatusView, menuButton button: UIButton, didSelectAction action: MastodonMenu.Action)
func tableViewCell(_ cell: UITableViewCell, statusView: StatusView, spoilerOverlayViewDidPressed overlayView: SpoilerOverlayView)
func tableViewCell(_ cell: UITableViewCell, statusView: StatusView, spoilerBannerViewDidPressed bannerView: SpoilerBannerView)
func tableViewCell(_ cell: UITableViewCell, statusView: StatusView, mediaGridContainerView: MediaGridContainerView, mediaSensitiveButtonDidPressed button: UIButton)
func tableViewCell(_ cell: UITableViewCell, statusView: StatusView, accessibilityActivate: Void)
// sourcery:end
@ -51,6 +51,10 @@ extension StatusViewDelegate where Self: StatusViewContainerTableViewCell {
delegate?.tableViewCell(self, statusView: statusView, authorAvatarButtonDidPressed: button)
}
func statusView(_ statusView: StatusView, contentSensitiveeToggleButtonDidPressed button: UIButton) {
delegate?.tableViewCell(self, statusView: statusView, contentSensitiveeToggleButtonDidPressed: button)
}
func statusView(_ statusView: StatusView, metaText: MetaText, didSelectMeta meta: Meta) {
delegate?.tableViewCell(self, statusView: statusView, metaText: metaText, didSelectMeta: meta)
}
@ -79,10 +83,6 @@ extension StatusViewDelegate where Self: StatusViewContainerTableViewCell {
delegate?.tableViewCell(self, statusView: statusView, spoilerOverlayViewDidPressed: overlayView)
}
func statusView(_ statusView: StatusView, spoilerBannerViewDidPressed bannerView: SpoilerBannerView) {
delegate?.tableViewCell(self, statusView: statusView, spoilerBannerViewDidPressed: bannerView)
}
func statusView(_ statusView: StatusView, mediaGridContainerView: MediaGridContainerView, mediaSensitiveButtonDidPressed button: UIButton) {
delegate?.tableViewCell(self, statusView: statusView, mediaGridContainerView: mediaGridContainerView, mediaSensitiveButtonDidPressed: button)
}

View File

@ -0,0 +1,15 @@
{
"images" : [
{
"filename" : "repeat.small.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"preserves-vector-representation" : true
}
}

View File

@ -0,0 +1,121 @@
%PDF-1.7
1 0 obj
<< >>
endobj
2 0 obj
<< /Length 3 0 R >>
stream
/DeviceRGB CS
/DeviceRGB cs
q
1.000000 0.000000 -0.000000 1.000000 1.997589 2.358398 cm
0.000000 0.000000 0.000000 scn
13.752419 11.631601 m
13.931720 11.631601 14.096325 11.568684 14.225361 11.463720 c
15.313271 10.549767 16.004837 9.176446 16.004837 7.641602 c
16.004837 4.952847 13.882531 2.759784 11.221727 2.646221 c
11.004837 2.641602 l
6.563000 2.641602 l
7.782749 1.421932 l
8.049015 1.155665 8.073221 0.739002 7.855367 0.445391 c
7.782749 0.361271 l
7.516482 0.095004 7.099819 0.070798 6.806207 0.288652 c
6.722089 0.361271 l
4.222089 2.861272 l
3.955822 3.127539 3.931616 3.544202 4.149471 3.837813 c
4.222089 3.921931 l
6.722089 6.421931 l
7.014983 6.714825 7.489855 6.714825 7.782749 6.421931 c
8.049015 6.155664 8.073221 5.739001 7.855367 5.445390 c
7.782749 5.361272 l
6.563000 4.141602 l
11.004837 4.141602 l
12.873401 4.141602 14.399964 5.605879 14.499659 7.449566 c
14.504837 7.641602 l
14.504837 8.722754 14.014629 9.689410 13.244354 10.331430 c
13.095952 10.466222 13.002419 10.662989 13.002419 10.881601 c
13.002419 11.295815 13.338205 11.631601 13.752419 11.631601 c
h
8.222090 14.921932 m
8.488357 15.188198 8.905020 15.212404 9.198631 14.994550 c
9.282749 14.921932 l
11.782749 12.421932 l
11.855368 12.337813 l
12.049016 12.076825 12.051406 11.718611 11.862539 11.455222 c
11.782749 11.361271 l
9.282749 8.861272 l
9.198631 8.788653 l
8.937643 8.595005 8.579429 8.592613 8.316040 8.781481 c
8.222090 8.861272 l
8.149471 8.945390 l
7.955823 9.206378 7.953431 9.564592 8.142298 9.827981 c
8.222090 9.921932 l
9.441000 11.141602 l
5.000000 11.141602 l
3.131437 11.141602 1.604874 9.677324 1.505179 7.833637 c
1.500000 7.641602 l
1.500000 6.558465 1.992010 5.590244 2.764729 4.948239 c
2.910926 4.812664 3.002419 4.617817 3.002419 4.401602 c
3.002419 3.987389 2.666633 3.651602 2.252419 3.651602 c
2.061133 3.651602 1.886572 3.723213 1.754084 3.841089 c
0.681080 4.754352 0.000000 6.118439 0.000000 7.641602 c
0.000000 10.330357 2.122307 12.523419 4.783111 12.636982 c
5.000000 12.641602 l
9.441000 12.641602 l
8.222090 13.861271 l
8.149471 13.945390 l
7.931617 14.239001 7.955823 14.655665 8.222090 14.921932 c
h
f
n
Q
endstream
endobj
3 0 obj
2140
endobj
4 0 obj
<< /Annots []
/Type /Page
/MediaBox [ 0.000000 0.000000 20.000000 20.000000 ]
/Resources 1 0 R
/Contents 2 0 R
/Parent 5 0 R
>>
endobj
5 0 obj
<< /Kids [ 4 0 R ]
/Count 1
/Type /Pages
>>
endobj
6 0 obj
<< /Pages 5 0 R
/Type /Catalog
>>
endobj
xref
0 7
0000000000 65535 f
0000000010 00000 n
0000000034 00000 n
0000002230 00000 n
0000002253 00000 n
0000002426 00000 n
0000002500 00000 n
trailer
<< /ID [ (some) (id) ]
/Root 6 0 R
/Size 7
>>
startxref
2559
%%EOF

View File

@ -23,6 +23,7 @@ public typealias AssetImageTypeAlias = ImageAsset.Image
public enum Asset {
public enum Arrow {
public static let `repeat` = ImageAsset(name: "Arrow/repeat")
public static let repeatSmall = ImageAsset(name: "Arrow/repeat.small")
}
public enum Asset {
public static let email = ImageAsset(name: "Asset/email")

View File

@ -21,7 +21,7 @@ extension MediaGridContainerView.ViewModel {
func bind(view: MediaGridContainerView) {
$isSensitiveToggleButtonDisplay
.sink { isDisplay in
view.sensitiveToggleButtonBlurVisualEffectView.isHidden = !isDisplay
// view.sensitiveToggleButtonBlurVisualEffectView.isHidden = !isDisplay
}
.store(in: &disposeBag)
}

View File

@ -49,21 +49,21 @@ public final class MediaGridContainerView: UIView {
}()
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 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) {
super.init(frame: frame)
@ -79,7 +79,7 @@ public final class MediaGridContainerView: UIView {
extension MediaGridContainerView {
private func _init() {
sensitiveToggleButton.addTarget(self, action: #selector(MediaGridContainerView.sensitiveToggleButtonDidPressed(_:)), for: .touchUpInside)
// sensitiveToggleButton.addTarget(self, action: #selector(MediaGridContainerView.sensitiveToggleButtonDidPressed(_:)), for: .touchUpInside)
}
}
@ -105,8 +105,8 @@ extension MediaGridContainerView {
let mediaView = _mediaViews[0]
layout.layout(in: self, mediaView: mediaView)
layoutSensitiveToggleButton()
bringSubviewToFront(sensitiveToggleButtonBlurVisualEffectView)
// layoutSensitiveToggleButton()
// bringSubviewToFront(sensitiveToggleButtonBlurVisualEffectView)
return mediaView
}
@ -117,8 +117,8 @@ extension MediaGridContainerView {
let mediaViews = Array(_mediaViews[0..<layout.count])
layout.layout(in: self, mediaViews: mediaViews)
layoutSensitiveToggleButton()
bringSubviewToFront(sensitiveToggleButtonBlurVisualEffectView)
// layoutSensitiveToggleButton()
// bringSubviewToFront(sensitiveToggleButtonBlurVisualEffectView)
return mediaViews
}
@ -140,35 +140,34 @@ 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 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),
// ])
// }
}
extension MediaGridContainerView {

View File

@ -19,14 +19,14 @@ public protocol NotificationViewDelegate: AnyObject {
func notificationView(_ notificationView: NotificationView, statusView: StatusView, metaText: MetaText, didSelectMeta meta: Meta)
func notificationView(_ notificationView: NotificationView, statusView: StatusView, spoilerOverlayViewDidPressed overlayView: SpoilerOverlayView)
func notificationView(_ notificationView: NotificationView, statusView: StatusView, spoilerBannerViewDidPressed bannerView: SpoilerBannerView)
// func notificationView(_ notificationView: NotificationView, statusView: StatusView, spoilerBannerViewDidPressed bannerView: SpoilerBannerView)
func notificationView(_ notificationView: NotificationView, statusView: StatusView, actionToolbarContainer: ActionToolbarContainer, buttonDidPressed button: UIButton, action: ActionToolbarContainer.Action)
func notificationView(_ notificationView: NotificationView, quoteStatusView: StatusView, authorAvatarButtonDidPressed button: AvatarButton)
func notificationView(_ notificationView: NotificationView, quoteStatusView: StatusView, metaText: MetaText, didSelectMeta meta: Meta)
func notificationView(_ notificationView: NotificationView, quoteStatusView: StatusView, spoilerOverlayViewDidPressed overlayView: SpoilerOverlayView)
func notificationView(_ notificationView: NotificationView, quoteStatusView: StatusView, spoilerBannerViewDidPressed bannerView: SpoilerBannerView)
// func notificationView(_ notificationView: NotificationView, quoteStatusView: StatusView, spoilerBannerViewDidPressed bannerView: SpoilerBannerView)
// a11y
func notificationView(_ notificationView: NotificationView, accessibilityActivate: Void)
@ -350,6 +350,10 @@ extension NotificationView: StatusViewDelegate {
}
}
public func statusView(_ statusView: StatusView, contentSensitiveeToggleButtonDidPressed button: UIButton) {
assertionFailure()
}
public func statusView(_ statusView: StatusView, metaText: MetaText, didSelectMeta meta: Meta) {
switch statusView {
case self.statusView:
@ -399,16 +403,16 @@ extension NotificationView: StatusViewDelegate {
}
}
public func statusView(_ statusView: StatusView, spoilerBannerViewDidPressed bannerView: SpoilerBannerView) {
switch statusView {
case self.statusView:
delegate?.notificationView(self, statusView: statusView, spoilerBannerViewDidPressed: bannerView)
case quoteStatusView:
delegate?.notificationView(self, quoteStatusView: statusView, spoilerBannerViewDidPressed: bannerView)
default:
assertionFailure()
}
}
// public func statusView(_ statusView: StatusView, spoilerBannerViewDidPressed bannerView: SpoilerBannerView) {
// switch statusView {
// case self.statusView:
// delegate?.notificationView(self, statusView: statusView, spoilerBannerViewDidPressed: bannerView)
// case quoteStatusView:
// delegate?.notificationView(self, quoteStatusView: statusView, spoilerBannerViewDidPressed: bannerView)
// default:
// assertionFailure()
// }
// }
public func statusView(_ statusView: StatusView, mediaGridContainerView: MediaGridContainerView, mediaSensitiveButtonDidPressed button: UIButton) {
assertionFailure()

View File

@ -201,7 +201,7 @@ extension StatusView.ViewModel {
case .none:
return
case .repost(let info):
statusView.headerIconImageView.image = UIImage(systemName: "arrow.2.squarepath")
statusView.headerIconImageView.image = Asset.Arrow.repeatSmall.image.withRenderingMode(.alwaysTemplate)
statusView.headerInfoLabel.configure(content: info.header)
statusView.setHeaderDisplay()
case .reply(let info):
@ -281,12 +281,12 @@ extension StatusView.ViewModel {
.sink { spoilerContent, content, isContentReveal in
if let spoilerContent = spoilerContent {
statusView.spoilerOverlayView.spoilerMetaLabel.configure(content: spoilerContent)
statusView.spoilerBannerView.label.configure(content: spoilerContent)
statusView.setSpoilerBannerViewHidden(isHidden: !isContentReveal)
// statusView.spoilerBannerView.label.configure(content: spoilerContent)
// statusView.setSpoilerBannerViewHidden(isHidden: !isContentReveal)
} else {
statusView.spoilerOverlayView.spoilerMetaLabel.reset()
statusView.spoilerBannerView.label.reset()
// statusView.spoilerBannerView.label.reset()
}
if let content = content {
@ -304,9 +304,18 @@ extension StatusView.ViewModel {
statusView.setSpoilerOverlayViewHidden(isHidden: isContentReveal)
let image = isContentReveal ? UIImage(systemName: "eye.slash.fill") : UIImage(systemName: "eye.fill")
statusView.contentSensitiveeToggleButton.setImage(image, for: .normal)
self.logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): isContentReveal: \(isContentReveal)")
}
.store(in: &disposeBag)
$isSensitive
.sink { isSensitive in
guard isSensitive else { return }
statusView.setContentSensitiveeToggleButtonDisplay()
}
.store(in: &disposeBag)
// visibility
Publishers.CombineLatest(
$visibility,

View File

@ -16,6 +16,7 @@ import MastodonLocalization
public protocol StatusViewDelegate: AnyObject {
func statusView(_ statusView: StatusView, headerDidPressed header: UIView)
func statusView(_ statusView: StatusView, authorAvatarButtonDidPressed button: AvatarButton)
func statusView(_ statusView: StatusView, contentSensitiveeToggleButtonDidPressed button: UIButton)
func statusView(_ statusView: StatusView, metaText: MetaText, didSelectMeta meta: Meta)
func statusView(_ statusView: StatusView, mediaGridContainerView: MediaGridContainerView, mediaView: MediaView, didSelectMediaViewAt index: Int)
func statusView(_ statusView: StatusView, pollTableView tableView: UITableView, didSelectRowAt indexPath: IndexPath)
@ -23,7 +24,7 @@ public protocol StatusViewDelegate: AnyObject {
func statusView(_ statusView: StatusView, actionToolbarContainer: ActionToolbarContainer, buttonDidPressed button: UIButton, action: ActionToolbarContainer.Action)
func statusView(_ statusView: StatusView, menuButton button: UIButton, didSelectAction action: MastodonMenu.Action)
func statusView(_ statusView: StatusView, spoilerOverlayViewDidPressed overlayView: SpoilerOverlayView)
func statusView(_ statusView: StatusView, spoilerBannerViewDidPressed bannerView: SpoilerBannerView)
// func statusView(_ statusView: StatusView, spoilerBannerViewDidPressed bannerView: SpoilerBannerView)
func statusView(_ statusView: StatusView, mediaGridContainerView: MediaGridContainerView, mediaSensitiveButtonDidPressed button: UIButton)
// a11y
@ -101,11 +102,24 @@ public final class StatusView: UIView {
public let menuButton: UIButton = {
let button = HitTestExpandedButton(type: .system)
button.expandEdgeInsets = UIEdgeInsets(top: -20, left: -10, bottom: -5, right: -10)
button.tintColor = Asset.Colors.Label.secondary.color
let image = UIImage(systemName: "ellipsis", withConfiguration: UIImage.SymbolConfiguration(font: .systemFont(ofSize: 15)))
button.setImage(image, for: .normal)
return button
}()
public let contentSensitiveeToggleButton: UIButton = {
let button = HitTestExpandedButton(type: .system)
button.expandEdgeInsets = UIEdgeInsets(top: -5, left: -10, bottom: -20, right: -10)
button.tintColor = Asset.Colors.Label.secondary.color
button.imageView?.contentMode = .scaleAspectFill
button.imageView?.clipsToBounds = false
let image = UIImage(systemName: "eye.slash.fill", withConfiguration: UIImage.SymbolConfiguration(font: .systemFont(ofSize: 15)))
button.setImage(image, for: .normal)
return button
}()
// content
let contentContainer = UIStackView()
public let contentMetaText: MetaText = {
@ -202,7 +216,7 @@ public final class StatusView: UIView {
public let statusVisibilityView = StatusVisibilityView()
// spoiler banner
public let spoilerBannerView = SpoilerBannerView()
// public let spoilerBannerView = SpoilerBannerView()
// toolbar
public let actionToolbarContainer = ActionToolbarContainer()
@ -228,11 +242,12 @@ public final class StatusView: UIView {
}
headerContainerView.isHidden = true
contentSensitiveeToggleButton.isHidden = true
setSpoilerOverlayViewHidden(isHidden: true)
mediaContainerView.isHidden = true
pollContainerView.isHidden = true
statusVisibilityView.isHidden = true
setSpoilerBannerViewHidden(isHidden: true)
// setSpoilerBannerViewHidden(isHidden: true)
}
public override init(frame: CGRect) {
@ -271,6 +286,8 @@ extension StatusView {
authorNameLabel.isUserInteractionEnabled = false
authorUsernameLabel.isUserInteractionEnabled = false
// contentSensitiveeToggleButton
contentSensitiveeToggleButton.addTarget(self, action: #selector(StatusView.contentSensitiveeToggleButtonDidPressed(_:)), for: .touchUpInside)
// dateLabel
dateLabel.isUserInteractionEnabled = false
@ -297,9 +314,9 @@ extension StatusView {
pollVoteButton.addTarget(self, action: #selector(StatusView.pollVoteButtonDidPressed(_:)), for: .touchUpInside)
// statusSpoilerBannerView
let spoilerBannerViewTapGestureRecognizer = UITapGestureRecognizer.singleTapGestureRecognizer
spoilerBannerView.addGestureRecognizer(spoilerBannerViewTapGestureRecognizer)
spoilerBannerViewTapGestureRecognizer.addTarget(self, action: #selector(StatusView.spoilerBannerViewTapGestureRecognizerHandler(_:)))
// let spoilerBannerViewTapGestureRecognizer = UITapGestureRecognizer.singleTapGestureRecognizer
// spoilerBannerView.addGestureRecognizer(spoilerBannerViewTapGestureRecognizer)
// spoilerBannerViewTapGestureRecognizer.addTarget(self, action: #selector(StatusView.spoilerBannerViewTapGestureRecognizerHandler(_:)))
// toolbar
actionToolbarContainer.delegate = self
@ -319,6 +336,10 @@ extension StatusView {
delegate?.statusView(self, authorAvatarButtonDidPressed: avatarButton)
}
@objc private func contentSensitiveeToggleButtonDidPressed(_ sender: UIButton) {
logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)")
delegate?.statusView(self, contentSensitiveeToggleButtonDidPressed: sender)
}
@objc private func pollVoteButtonDidPressed(_ sender: UIButton) {
logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)")
@ -330,10 +351,10 @@ extension StatusView {
delegate?.statusView(self, spoilerOverlayViewDidPressed: spoilerOverlayView)
}
@objc private func spoilerBannerViewTapGestureRecognizerHandler(_ sender: UITapGestureRecognizer) {
logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)")
delegate?.statusView(self, spoilerBannerViewDidPressed: spoilerBannerView)
}
// @objc private func spoilerBannerViewTapGestureRecognizerHandler(_ sender: UITapGestureRecognizer) {
// logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)")
// delegate?.statusView(self, spoilerBannerViewDidPressed: spoilerBannerView)
// }
}
@ -447,7 +468,7 @@ extension StatusView.Style {
statusView.menuButton.setContentHuggingPriority(.required - 2, for: .horizontal)
statusView.menuButton.setContentCompressionResistancePriority(.required - 2, for: .horizontal)
// authorSecondaryMetaContainer: H - [ authorUsername | usernameTrialingDotLabel | dateLabel | (padding) ]
// authorSecondaryMetaContainer: H - [ authorUsername | usernameTrialingDotLabel | dateLabel | (padding) | contentSensitiveeToggleButton ]
let authorSecondaryMetaContainer = UIStackView()
authorSecondaryMetaContainer.axis = .horizontal
authorSecondaryMetaContainer.spacing = 4
@ -463,6 +484,18 @@ extension StatusView.Style {
statusView.dateLabel.setContentHuggingPriority(.required - 1, for: .horizontal)
statusView.dateLabel.setContentCompressionResistancePriority(.required - 1, for: .horizontal)
authorSecondaryMetaContainer.addArrangedSubview(UIView())
statusView.contentSensitiveeToggleButton.translatesAutoresizingMaskIntoConstraints = false
authorSecondaryMetaContainer.addArrangedSubview(statusView.contentSensitiveeToggleButton)
NSLayoutConstraint.activate([
statusView.contentSensitiveeToggleButton.heightAnchor.constraint(equalTo: statusView.authorUsernameLabel.heightAnchor, multiplier: 1.0).priority(.required - 1),
statusView.contentSensitiveeToggleButton.widthAnchor.constraint(equalTo: statusView.contentSensitiveeToggleButton.heightAnchor, multiplier: 1.0).priority(.required - 1),
])
statusView.authorUsernameLabel.setContentHuggingPriority(.required - 1, for: .vertical)
statusView.authorUsernameLabel.setContentCompressionResistancePriority(.required - 1, for: .vertical)
statusView.contentSensitiveeToggleButton.setContentHuggingPriority(.defaultLow, for: .vertical)
statusView.contentSensitiveeToggleButton.setContentHuggingPriority(.defaultLow, for: .horizontal)
statusView.contentSensitiveeToggleButton.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
statusView.contentSensitiveeToggleButton.setContentCompressionResistancePriority(.defaultLow, for: .vertical)
// content container: V - [ contentMetaText ]
statusView.contentContainer.axis = .vertical
@ -527,8 +560,9 @@ extension StatusView.Style {
statusView.statusVisibilityView.preservesSuperviewLayoutMargins = true
statusView.containerStackView.addArrangedSubview(statusView.statusVisibilityView)
statusView.spoilerBannerView.preservesSuperviewLayoutMargins = true
statusView.containerStackView.addArrangedSubview(statusView.spoilerBannerView)
// spoilerBannerView
// statusView.spoilerBannerView.preservesSuperviewLayoutMargins = true
// statusView.containerStackView.addArrangedSubview(statusView.spoilerBannerView)
// action toolbar
statusView.actionToolbarContainer.configure(for: .inline)
@ -577,6 +611,7 @@ extension StatusView.Style {
base(statusView: statusView) // override the base style
statusView.contentContainer.layoutMargins.bottom = 16 // fix contentText align to edge issue
statusView.contentSensitiveeToggleButton.removeFromSuperview()
statusView.menuButton.removeFromSuperview()
statusView.statusVisibilityView.removeFromSuperview()
statusView.actionToolbarContainer.removeFromSuperview()
@ -588,7 +623,7 @@ extension StatusView.Style {
statusView.avatarButton.isUserInteractionEnabled = false
statusView.menuButton.removeFromSuperview()
statusView.statusVisibilityView.removeFromSuperview()
statusView.spoilerBannerView.removeFromSuperview()
// statusView.spoilerBannerView.removeFromSuperview()
statusView.actionToolbarContainer.removeFromSuperview()
}
@ -604,7 +639,7 @@ extension StatusView.Style {
statusView.mediaContainerView.removeFromSuperview()
statusView.pollContainerView.removeFromSuperview()
statusView.statusVisibilityView.removeFromSuperview()
statusView.spoilerBannerView.removeFromSuperview()
// statusView.spoilerBannerView.removeFromSuperview()
statusView.actionToolbarContainer.removeFromSuperview()
}
@ -615,6 +650,10 @@ extension StatusView {
headerContainerView.isHidden = false
}
func setContentSensitiveeToggleButtonDisplay() {
contentSensitiveeToggleButton.isHidden = false
}
func setSpoilerOverlayViewHidden(isHidden: Bool) {
spoilerOverlayView.isHidden = isHidden
spoilerOverlayView.setComponentHidden(isHidden)
@ -632,9 +671,9 @@ extension StatusView {
statusVisibilityView.isHidden = false
}
func setSpoilerBannerViewHidden(isHidden: Bool) {
spoilerBannerView.isHidden = isHidden
}
// func setSpoilerBannerViewHidden(isHidden: Bool) {
// spoilerBannerView.isHidden = isHidden
// }
// content text Width
public var contentMaxLayoutWidth: CGFloat {