chore: show menu in statusCell

This commit is contained in:
sunxiaojian 2021-04-28 19:56:30 +08:00
parent 23491e60b9
commit 273305cda9
6 changed files with 119 additions and 76 deletions

View File

@ -50,6 +50,7 @@ extension NotificationSection {
let frame = CGRect(x: 0, y: 0, width: tableView.readableContentGuide.layoutFrame.width - NotificationStatusTableViewCell.statusPadding.left - NotificationStatusTableViewCell.statusPadding.right, height: tableView.readableContentGuide.layoutFrame.height) let frame = CGRect(x: 0, y: 0, width: tableView.readableContentGuide.layoutFrame.width - NotificationStatusTableViewCell.statusPadding.left - NotificationStatusTableViewCell.statusPadding.right, height: tableView.readableContentGuide.layoutFrame.height)
StatusSection.configure( StatusSection.configure(
cell: cell, cell: cell,
indexPath: indexPath,
dependency: dependency, dependency: dependency,
readableLayoutFrame: frame, readableLayoutFrame: frame,
timestampUpdatePublisher: timestampUpdatePublisher, timestampUpdatePublisher: timestampUpdatePublisher,

View File

@ -41,6 +41,7 @@ extension ReportSection {
let status = managedObjectContext.object(with: objectID) as! Status let status = managedObjectContext.object(with: objectID) as! Status
StatusSection.configure( StatusSection.configure(
cell: cell, cell: cell,
indexPath: indexPath,
dependency: dependency, dependency: dependency,
readableLayoutFrame: tableView.readableContentGuide.layoutFrame, readableLayoutFrame: tableView.readableContentGuide.layoutFrame,
timestampUpdatePublisher: timestampUpdatePublisher, timestampUpdatePublisher: timestampUpdatePublisher,

View File

@ -49,6 +49,7 @@ extension StatusSection {
let timelineIndex = managedObjectContext.object(with: objectID) as! HomeTimelineIndex let timelineIndex = managedObjectContext.object(with: objectID) as! HomeTimelineIndex
StatusSection.configure( StatusSection.configure(
cell: cell, cell: cell,
indexPath: indexPath,
dependency: dependency, dependency: dependency,
readableLayoutFrame: tableView.readableContentGuide.layoutFrame, readableLayoutFrame: tableView.readableContentGuide.layoutFrame,
timestampUpdatePublisher: timestampUpdatePublisher, timestampUpdatePublisher: timestampUpdatePublisher,
@ -71,6 +72,7 @@ extension StatusSection {
let status = managedObjectContext.object(with: objectID) as! Status let status = managedObjectContext.object(with: objectID) as! Status
StatusSection.configure( StatusSection.configure(
cell: cell, cell: cell,
indexPath: indexPath,
dependency: dependency, dependency: dependency,
readableLayoutFrame: tableView.readableContentGuide.layoutFrame, readableLayoutFrame: tableView.readableContentGuide.layoutFrame,
timestampUpdatePublisher: timestampUpdatePublisher, timestampUpdatePublisher: timestampUpdatePublisher,
@ -136,6 +138,7 @@ extension StatusSection {
static func configure( static func configure(
cell: StatusCell, cell: StatusCell,
indexPath: IndexPath,
dependency: NeedsDependency, dependency: NeedsDependency,
readableLayoutFrame: CGRect?, readableLayoutFrame: CGRect?,
timestampUpdatePublisher: AnyPublisher<Date, Never>, timestampUpdatePublisher: AnyPublisher<Date, Never>,
@ -223,7 +226,6 @@ extension StatusSection {
meta.blurhashImagePublisher() meta.blurhashImagePublisher()
.receive(on: DispatchQueue.main) .receive(on: DispatchQueue.main)
.sink { [weak cell] image in .sink { [weak cell] image in
guard let cell = cell else { return }
blurhashOverlayImageView.image = image blurhashOverlayImageView.image = image
image?.pngData().flatMap { image?.pngData().flatMap {
blurhashImageCache.setObject($0 as NSData, forKey: blurhashImageDataKey) blurhashImageCache.setObject($0 as NSData, forKey: blurhashImageDataKey)
@ -401,16 +403,16 @@ extension StatusSection {
.store(in: &cell.disposeBag) .store(in: &cell.disposeBag)
} }
if let statusTableViewCell = cell as? StatusTableViewCell {
// toolbar // toolbar
StatusSection.configureActionToolBar( StatusSection.configureActionToolBar(
cell: cell, cell: statusTableViewCell,
indexPath: indexPath,
dependency: dependency, dependency: dependency,
status: status, status: status,
requestUserID: requestUserID requestUserID: requestUserID
) )
// separator line // separator line
if let statusTableViewCell = cell as? StatusTableViewCell {
statusTableViewCell.separatorLine.isHidden = statusItemAttribute.isSeparatorLineHidden statusTableViewCell.separatorLine.isHidden = statusItemAttribute.isSeparatorLineHidden
} }
@ -434,8 +436,10 @@ extension StatusSection {
guard let dependency = dependency else { return } guard let dependency = dependency else { return }
guard case .update(let object) = change.changeType, guard case .update(let object) = change.changeType,
let status = object as? Status else { return } let status = object as? Status else { return }
guard let cell = cell as? StatusTableViewCell else { return }
StatusSection.configureActionToolBar( StatusSection.configureActionToolBar(
cell: cell, cell: cell,
indexPath: indexPath,
dependency: dependency, dependency: dependency,
status: status, status: status,
requestUserID: requestUserID requestUserID: requestUserID
@ -593,7 +597,8 @@ extension StatusSection {
} }
static func configureActionToolBar( static func configureActionToolBar(
cell: StatusCell, cell: StatusTableViewCell,
indexPath: IndexPath,
dependency: NeedsDependency, dependency: NeedsDependency,
status: Status, status: Status,
requestUserID: String requestUserID: String
@ -623,7 +628,7 @@ extension StatusSection {
cell.statusView.actionToolbarContainer.favoriteButton.setTitle(favoriteCountTitle, for: .normal) cell.statusView.actionToolbarContainer.favoriteButton.setTitle(favoriteCountTitle, for: .normal)
cell.statusView.actionToolbarContainer.isFavoriteButtonHighlight = isLike cell.statusView.actionToolbarContainer.isFavoriteButtonHighlight = isLike
self.setupStatusMoreButtonMenu(cell: cell, dependency: dependency, status: status) self.setupStatusMoreButtonMenu(cell: cell, indexPath: indexPath, dependency: dependency, status: status)
} }
static func configurePoll( static func configurePoll(
@ -752,37 +757,35 @@ extension StatusSection {
} }
private static func setupStatusMoreButtonMenu( private static func setupStatusMoreButtonMenu(
cell: StatusCell, cell: StatusTableViewCell,
indexPath: IndexPath,
dependency: NeedsDependency, dependency: NeedsDependency,
status: Status) { status: Status) {
cell.statusView.actionToolbarContainer.moreButton.menu = nil guard let userProvider = dependency as? UserProvider else { fatalError() }
guard let authenticationBox = dependency.context.authenticationService.activeMastodonAuthenticationBox.value else { guard let authenticationBox = dependency.context.authenticationService.activeMastodonAuthenticationBox.value else {
return return
} }
let author = (status.reblog ?? status).author let author = (status.reblog ?? status).author
guard authenticationBox.userID != author.id else { let canReport = authenticationBox.userID != author.id
return
} let isMuting = (author.mutingBy ?? Set()).map(\.id).contains(authenticationBox.userID)
var children: [UIMenuElement] = [] let isBlocking = (author.blockingBy ?? Set()).map(\.id).contains(authenticationBox.userID)
let name = author.displayNameWithFallback
let reportAction = UIAction(title: L10n.Common.Controls.Actions.reportUser(name), image: UIImage(systemName: "exclamationmark.bubble"), identifier: nil, discoverabilityTitle: nil, attributes: [], state: .off) { cell.statusView.actionToolbarContainer.moreButton.showsMenuAsPrimaryAction = true
[weak dependency] _ in cell.statusView.actionToolbarContainer.moreButton.menu = UserProviderFacade.createProfileActionMenu(
guard let dependency = dependency else { return } for: author,
let viewModel = ReportViewModel( isMuting: isMuting,
context: dependency.context, isBlocking: isBlocking,
domain: authenticationBox.domain, canReport: canReport,
user: status.author, provider: userProvider,
status: status) cell: cell,
dependency.coordinator.present( indexPath: indexPath,
scene: .report(viewModel: viewModel), sourceView: cell.statusView.actionToolbarContainer.moreButton,
from: nil, barButtonItem: nil,
transition: .modal(animated: true, completion: nil) shareUser: nil,
shareStatus: status
) )
} }
children.append(reportAction)
cell.statusView.actionToolbarContainer.moreButton.menu = UIMenu(title: "", options: [], children: children)
cell.statusView.actionToolbarContainer.moreButton.showsMenuAsPrimaryAction = true
}
} }

View File

@ -57,20 +57,29 @@ extension UserProviderFacade {
extension UserProviderFacade { extension UserProviderFacade {
static func toggleUserBlockRelationship( static func toggleUserBlockRelationship(
provider: UserProvider provider: UserProvider,
cell: UITableViewCell?,
indexPath: IndexPath?
) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Relationship>, Error> { ) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Relationship>, Error> {
// prepare authentication // prepare authentication
guard let activeMastodonAuthenticationBox = provider.context.authenticationService.activeMastodonAuthenticationBox.value else { guard let activeMastodonAuthenticationBox = provider.context.authenticationService.activeMastodonAuthenticationBox.value else {
assertionFailure() assertionFailure()
return Fail(error: APIService.APIError.implicit(.authenticationMissing)).eraseToAnyPublisher() return Fail(error: APIService.APIError.implicit(.authenticationMissing)).eraseToAnyPublisher()
} }
if let cell = cell, let indexPath = indexPath {
return _toggleUserBlockRelationship(
context: provider.context,
activeMastodonAuthenticationBox: activeMastodonAuthenticationBox,
mastodonUser: provider.mastodonUser(for: cell, indexPath: indexPath).eraseToAnyPublisher()
)
} else {
return _toggleUserBlockRelationship( return _toggleUserBlockRelationship(
context: provider.context, context: provider.context,
activeMastodonAuthenticationBox: activeMastodonAuthenticationBox, activeMastodonAuthenticationBox: activeMastodonAuthenticationBox,
mastodonUser: provider.mastodonUser().eraseToAnyPublisher() mastodonUser: provider.mastodonUser().eraseToAnyPublisher()
) )
} }
}
private static func _toggleUserBlockRelationship( private static func _toggleUserBlockRelationship(
context: AppContext, context: AppContext,
@ -97,20 +106,29 @@ extension UserProviderFacade {
extension UserProviderFacade { extension UserProviderFacade {
static func toggleUserMuteRelationship( static func toggleUserMuteRelationship(
provider: UserProvider provider: UserProvider,
cell: UITableViewCell?,
indexPath: IndexPath?
) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Relationship>, Error> { ) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Relationship>, Error> {
// prepare authentication // prepare authentication
guard let activeMastodonAuthenticationBox = provider.context.authenticationService.activeMastodonAuthenticationBox.value else { guard let activeMastodonAuthenticationBox = provider.context.authenticationService.activeMastodonAuthenticationBox.value else {
assertionFailure() assertionFailure()
return Fail(error: APIService.APIError.implicit(.authenticationMissing)).eraseToAnyPublisher() return Fail(error: APIService.APIError.implicit(.authenticationMissing)).eraseToAnyPublisher()
} }
if let cell = cell, let indexPath = indexPath {
return _toggleUserMuteRelationship(
context: provider.context,
activeMastodonAuthenticationBox: activeMastodonAuthenticationBox,
mastodonUser: provider.mastodonUser(for: cell, indexPath: indexPath).eraseToAnyPublisher()
)
} else {
return _toggleUserMuteRelationship( return _toggleUserMuteRelationship(
context: provider.context, context: provider.context,
activeMastodonAuthenticationBox: activeMastodonAuthenticationBox, activeMastodonAuthenticationBox: activeMastodonAuthenticationBox,
mastodonUser: provider.mastodonUser().eraseToAnyPublisher() mastodonUser: provider.mastodonUser().eraseToAnyPublisher()
) )
} }
}
private static func _toggleUserMuteRelationship( private static func _toggleUserMuteRelationship(
context: AppContext, context: AppContext,
@ -140,10 +158,14 @@ extension UserProviderFacade {
for mastodonUser: MastodonUser, for mastodonUser: MastodonUser,
isMuting: Bool, isMuting: Bool,
isBlocking: Bool, isBlocking: Bool,
needsShareAction: Bool, canReport: Bool,
provider: UserProvider, provider: UserProvider,
cell: UITableViewCell?,
indexPath: IndexPath?,
sourceView: UIView?, sourceView: UIView?,
barButtonItem: UIBarButtonItem? barButtonItem: UIBarButtonItem?,
shareUser: MastodonUser?,
shareStatus: Status?
) -> UIMenu { ) -> UIMenu {
var children: [UIMenuElement] = [] var children: [UIMenuElement] = []
let name = mastodonUser.displayNameWithFallback let name = mastodonUser.displayNameWithFallback
@ -159,7 +181,9 @@ extension UserProviderFacade {
guard let provider = provider else { return } guard let provider = provider else { return }
UserProviderFacade.toggleUserMuteRelationship( UserProviderFacade.toggleUserMuteRelationship(
provider: provider provider: provider,
cell: cell,
indexPath: indexPath
) )
.sink { _ in .sink { _ in
// do nothing // do nothing
@ -186,7 +210,9 @@ extension UserProviderFacade {
guard let provider = provider else { return } guard let provider = provider else { return }
UserProviderFacade.toggleUserBlockRelationship( UserProviderFacade.toggleUserBlockRelationship(
provider: provider provider: provider,
cell: cell,
indexPath: indexPath
) )
.sink { _ in .sink { _ in
// do nothing // do nothing
@ -201,7 +227,7 @@ extension UserProviderFacade {
let blockMenu = UIMenu(title: L10n.Common.Controls.Firendship.blockUser(name), image: UIImage(systemName: "hand.raised"), options: [], children: [blockAction]) let blockMenu = UIMenu(title: L10n.Common.Controls.Firendship.blockUser(name), image: UIImage(systemName: "hand.raised"), options: [], children: [blockAction])
children.append(blockMenu) children.append(blockMenu)
} }
if canReport {
let reportAction = UIAction(title: L10n.Common.Controls.Actions.reportUser(name), image: UIImage(systemName: "flag"), identifier: nil, discoverabilityTitle: nil, attributes: [], state: .off) { [weak provider] _ in let reportAction = UIAction(title: L10n.Common.Controls.Actions.reportUser(name), image: UIImage(systemName: "flag"), identifier: nil, discoverabilityTitle: nil, attributes: [], state: .off) { [weak provider] _ in
guard let provider = provider else { return } guard let provider = provider else { return }
guard let authenticationBox = provider.context.authenticationService.activeMastodonAuthenticationBox.value else { guard let authenticationBox = provider.context.authenticationService.activeMastodonAuthenticationBox.value else {
@ -219,11 +245,12 @@ extension UserProviderFacade {
) )
} }
children.append(reportAction) children.append(reportAction)
}
if needsShareAction { if let shareUser = shareUser {
let shareAction = UIAction(title: L10n.Common.Controls.Actions.shareUser(name), image: UIImage(systemName: "square.and.arrow.up"), identifier: nil, discoverabilityTitle: nil, attributes: [], state: .off) { [weak provider] _ in let shareAction = UIAction(title: L10n.Common.Controls.Actions.shareUser(name), image: UIImage(systemName: "square.and.arrow.up"), identifier: nil, discoverabilityTitle: nil, attributes: [], state: .off) { [weak provider] _ in
guard let provider = provider else { return } guard let provider = provider else { return }
let activityViewController = createActivityViewControllerForMastodonUser(mastodonUser: mastodonUser, dependency: provider) let activityViewController = createActivityViewControllerForMastodonUser(mastodonUser: shareUser, dependency: provider)
provider.coordinator.present( provider.coordinator.present(
scene: .activityViewController( scene: .activityViewController(
activityViewController: activityViewController, activityViewController: activityViewController,

View File

@ -377,7 +377,18 @@ extension ProfileViewController {
let isMuting = relationshipActionOptionSet.contains(.muting) let isMuting = relationshipActionOptionSet.contains(.muting)
let isBlocking = relationshipActionOptionSet.contains(.blocking) let isBlocking = relationshipActionOptionSet.contains(.blocking)
let needsShareAction = self.viewModel.isMeBarButtonItemsHidden.value let needsShareAction = self.viewModel.isMeBarButtonItemsHidden.value
self.moreMenuBarButtonItem.menu = UserProviderFacade.createProfileActionMenu(for: mastodonUser, isMuting: isMuting, isBlocking: isBlocking, needsShareAction: needsShareAction, provider: self, sourceView: nil, barButtonItem: self.moreMenuBarButtonItem) self.moreMenuBarButtonItem.menu = UserProviderFacade.createProfileActionMenu(
for: mastodonUser,
isMuting: isMuting,
isBlocking: isBlocking,
canReport: true,
provider: self,
cell: nil,
indexPath: nil,
sourceView: nil,
barButtonItem: self.moreMenuBarButtonItem,
shareUser: needsShareAction ? mastodonUser : nil,
shareStatus: nil)
} }
.store(in: &disposeBag) .store(in: &disposeBag)
viewModel.isRelationshipActionButtonHidden viewModel.isRelationshipActionButtonHidden
@ -692,7 +703,7 @@ extension ProfileViewController: ProfileHeaderViewDelegate {
) )
let unmuteAction = UIAlertAction(title: L10n.Common.Controls.Firendship.unmute, style: .default) { [weak self] _ in let unmuteAction = UIAlertAction(title: L10n.Common.Controls.Firendship.unmute, style: .default) { [weak self] _ in
guard let self = self else { return } guard let self = self else { return }
UserProviderFacade.toggleUserMuteRelationship(provider: self) UserProviderFacade.toggleUserMuteRelationship(provider: self, cell: nil, indexPath: nil)
.sink { _ in .sink { _ in
// do nothing // do nothing
} receiveValue: { _ in } receiveValue: { _ in
@ -714,7 +725,7 @@ extension ProfileViewController: ProfileHeaderViewDelegate {
) )
let unblockAction = UIAlertAction(title: L10n.Common.Controls.Firendship.unblock, style: .default) { [weak self] _ in let unblockAction = UIAlertAction(title: L10n.Common.Controls.Firendship.unblock, style: .default) { [weak self] _ in
guard let self = self else { return } guard let self = self else { return }
UserProviderFacade.toggleUserBlockRelationship(provider: self) UserProviderFacade.toggleUserBlockRelationship(provider: self, cell: nil, indexPath: nil)
.sink { _ in .sink { _ in
// do nothing // do nothing
} receiveValue: { _ in } receiveValue: { _ in

View File

@ -54,7 +54,7 @@ extension SearchViewController: SearchRecommendAccountsCollectionViewCellDelegat
) )
let unmuteAction = UIAlertAction(title: L10n.Common.Controls.Firendship.unmute, style: .default) { [weak self] _ in let unmuteAction = UIAlertAction(title: L10n.Common.Controls.Firendship.unmute, style: .default) { [weak self] _ in
guard let self = self else { return } guard let self = self else { return }
UserProviderFacade.toggleUserMuteRelationship(provider: self) UserProviderFacade.toggleUserMuteRelationship(provider: self, cell: nil, indexPath: nil)
.sink { _ in .sink { _ in
// do nothing // do nothing
} receiveValue: { _ in } receiveValue: { _ in
@ -76,7 +76,7 @@ extension SearchViewController: SearchRecommendAccountsCollectionViewCellDelegat
) )
let unblockAction = UIAlertAction(title: L10n.Common.Controls.Firendship.unblock, style: .default) { [weak self] _ in let unblockAction = UIAlertAction(title: L10n.Common.Controls.Firendship.unblock, style: .default) { [weak self] _ in
guard let self = self else { return } guard let self = self else { return }
UserProviderFacade.toggleUserBlockRelationship(provider: self) UserProviderFacade.toggleUserBlockRelationship(provider: self, cell: nil, indexPath: nil)
.sink { _ in .sink { _ in
// do nothing // do nothing
} receiveValue: { _ in } receiveValue: { _ in