From a7f792c3016a61f300f9cc19ecf1e9043d714994 Mon Sep 17 00:00:00 2001 From: Nathan Mattes Date: Mon, 20 May 2024 11:30:27 +0200 Subject: [PATCH] Update menu for profiles (IOS-231) --- .../Provider/DataSourceFacade+Status.swift | 10 ++- ...er+NotificationTableViewCellDelegate.swift | 4 +- .../Scene/Profile/ProfileViewController.swift | 62 ++++++++-------- .../View/Content/StatusAuthorView.swift | 2 +- .../MastodonUI/View/Menu/MastodonMenu.swift | 73 ++++++++----------- 5 files changed, 69 insertions(+), 82 deletions(-) diff --git a/Mastodon/Protocol/Provider/DataSourceFacade+Status.swift b/Mastodon/Protocol/Provider/DataSourceFacade+Status.swift index 7fe8fe639..91ea06633 100644 --- a/Mastodon/Protocol/Provider/DataSourceFacade+Status.swift +++ b/Mastodon/Protocol/Provider/DataSourceFacade+Status.swift @@ -398,14 +398,14 @@ extension DataSourceFacade { } try await responseToStatusFavoriteAction(provider: dependency, status: status) - case .copyLink: + case .copyStatusLink: guard let status: MastodonStatus = menuContext.statusViewModel?.originalStatus?.reblog ?? menuContext.statusViewModel?.originalStatus else { assertionFailure() return } UIPasteboard.general.string = status.entity.url - case .openInBrowser: + case .openStatusInBrowser: guard let status: MastodonStatus = menuContext.statusViewModel?.originalStatus?.reblog ?? menuContext.statusViewModel?.originalStatus, let urlString = status.entity.url, @@ -415,6 +415,12 @@ extension DataSourceFacade { return } + dependency.coordinator.present(scene: .safari(url: url), transition: .safariPresent(animated: true)) + case .copyProfileLink(let url): + UIPasteboard.general.string = url?.absoluteString + case .openUserInBrowser(let url): + guard let url else { return } + dependency.coordinator.present(scene: .safari(url: url), transition: .safariPresent(animated: true)) } } diff --git a/Mastodon/Protocol/Provider/DataSourceProvider+NotificationTableViewCellDelegate.swift b/Mastodon/Protocol/Provider/DataSourceProvider+NotificationTableViewCellDelegate.swift index 9e7f6e047..aa71991d3 100644 --- a/Mastodon/Protocol/Provider/DataSourceProvider+NotificationTableViewCellDelegate.swift +++ b/Mastodon/Protocol/Provider/DataSourceProvider+NotificationTableViewCellDelegate.swift @@ -61,10 +61,8 @@ extension NotificationTableViewCellDelegate where Self: DataSourceProvider & Aut barButtonItem: nil ) ) - case .translateStatus(_), .showOriginal, .shareUser(_), .blockDomain(_), .bookmarkStatus(_), .hideReblogs(_), .shareStatus, .deleteStatus, .editStatus, .followUser(_), .boostStatus(_), .favoriteStatus(_), .copyLink, .openInBrowser: - // Do Nothing + case .translateStatus(_), .showOriginal, .shareUser(_), .blockDomain(_), .bookmarkStatus(_), .hideReblogs(_), .shareStatus, .deleteStatus, .editStatus, .followUser(_), .boostStatus(_), .favoriteStatus(_), .copyStatusLink, .openStatusInBrowser, .openUserInBrowser(_), .copyProfileLink(_): break - } } } diff --git a/Mastodon/Scene/Profile/ProfileViewController.swift b/Mastodon/Scene/Profile/ProfileViewController.swift index 4d35a361c..8820e8c05 100644 --- a/Mastodon/Scene/Profile/ProfileViewController.swift +++ b/Mastodon/Scene/Profile/ProfileViewController.swift @@ -417,6 +417,7 @@ extension ProfileViewController { .store(in: &disposeBag) } + // This More-button is only visible for other users, but not myself private func bindMoreBarButtonItem() { Publishers.CombineLatest3( viewModel.$account, @@ -428,30 +429,41 @@ extension ProfileViewController { let name = user.displayNameWithFallback - var menuActions: [MastodonMenu.Action] = [ - .muteUser(.init(name: name, isMuting: relationship.muting)), - .blockUser(.init(name: name, isBlocking: relationship.blocking)) + var items: [MastodonMenu.Submenu] = [] + + items.append(MastodonMenu.Submenu(actions: [ + .shareUser(.init(name: name)), + .openUserInBrowser(URL(string: user.url)), + .copyProfileLink(URL(string: user.url)) + ])) + + + var relationshipActions: [MastodonMenu.Action] = [ + .followUser(.init(name: name, isFollowing: relationship.following)), + .muteUser(.init(name: name, isMuting: relationship.muting)) + ] + + if relationship.following { + relationshipActions.append(.hideReblogs(.init(showReblogs: relationship.showingReblogs))) + } + + items.append(MastodonMenu.Submenu(actions: relationshipActions)) + + var destructiveActions: [MastodonMenu.Action] = [ + .blockUser(.init(name: name, isBlocking: relationship.blocking)), + .reportUser(.init(name: name)), ] if myDomain != domain { - menuActions.append( + destructiveActions.append( .blockDomain(.init(domain: domain, isBlocking: relationship.domainBlocking)) ) } - menuActions.append(contentsOf: [ - .reportUser(.init(name: name)), - .shareUser(.init(name: name)), - ]) - - if relationship.following { - let showReblogs = relationship.showingReblogs// me.showingReblogsBy.contains(user) - let context = MastodonMenu.HideReblogsActionContext(showReblogs: showReblogs) - menuActions.insert(.hideReblogs(context), at: 1) - } + items.append(MastodonMenu.Submenu(actions: destructiveActions)) let menu = MastodonMenu.setupMenu( - submenus: [MastodonMenu.Submenu(actions: menuActions)], + submenus: items, delegate: self ) return menu @@ -929,10 +941,7 @@ extension ProfileViewController: ProfileAboutViewControllerDelegate { extension ProfileViewController: MastodonMenuDelegate { func menuAction(_ action: MastodonMenu.Action) { switch action { - case .muteUser(_), - .blockUser(_), - .blockDomain(_), - .hideReblogs(_): + case .muteUser(_), .blockUser(_), .blockDomain(_), .hideReblogs(_), .reportUser(_), .shareUser(_), .openUserInBrowser(_), .copyProfileLink(_), .followUser(_): Task { try await DataSourceFacade.responseToMenuAction( dependency: self, @@ -944,20 +953,7 @@ extension ProfileViewController: MastodonMenuDelegate { barButtonItem: self.moreMenuBarButtonItem )) } - case .reportUser(_), .shareUser(_): - Task { - try await DataSourceFacade.responseToMenuAction( - dependency: self, - action: action, - menuContext: DataSourceFacade.MenuContext( - author: viewModel.account, - statusViewModel: nil, - button: nil, - barButtonItem: self.moreMenuBarButtonItem - )) - } - - case .translateStatus(_), .showOriginal, .bookmarkStatus(_), .shareStatus, .deleteStatus, .editStatus, .followUser(_), .boostStatus(_), .favoriteStatus(_), .copyLink, .openInBrowser: + case .translateStatus(_), .showOriginal, .bookmarkStatus(_), .shareStatus, .deleteStatus, .editStatus, .boostStatus(_), .favoriteStatus(_), .copyStatusLink, .openStatusInBrowser: break } } diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/StatusAuthorView.swift b/MastodonSDK/Sources/MastodonUI/View/Content/StatusAuthorView.swift index ee85e3fa9..9f6fe6ad9 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/StatusAuthorView.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/StatusAuthorView.swift @@ -186,7 +186,7 @@ extension StatusAuthorView { items.append(MastodonMenu.Submenu(actions: [action])) } - items.append(MastodonMenu.Submenu(actions: [.shareStatus, .openInBrowser, .copyLink])) + items.append(MastodonMenu.Submenu(actions: [.shareStatus, .openStatusInBrowser, .copyStatusLink])) if menuContext.isMyself { items.append(MastodonMenu.Submenu(actions: [.deleteStatus])) diff --git a/MastodonSDK/Sources/MastodonUI/View/Menu/MastodonMenu.swift b/MastodonSDK/Sources/MastodonUI/View/Menu/MastodonMenu.swift index 40d13c787..4c023c30e 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Menu/MastodonMenu.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Menu/MastodonMenu.swift @@ -76,16 +76,17 @@ extension MastodonMenu { case blockDomain(BlockDomainActionContext) case boostStatus(BoostStatusActionContext) case favoriteStatus(FavoriteStatusActionContext) - case copyLink - case openInBrowser + case copyStatusLink + case openStatusInBrowser + case openUserInBrowser(URL?) + case copyProfileLink(URL?) func build(delegate: MastodonMenuDelegate) -> LabeledAction { switch self { case .hideReblogs(let context): let title = context.showReblogs ? L10n.Common.Controls.Friendship.hideReblogs : L10n.Common.Controls.Friendship.showReblogs let reblogAction = LabeledAction(title: title, image: UIImage(systemName: "arrow.2.squarepath")) { [weak delegate] in - guard let delegate = delegate else { return } - delegate.menuAction(self) + delegate?.menuAction(self) } return reblogAction @@ -100,8 +101,7 @@ extension MastodonMenu { image = UIImage(systemName: "speaker.slash") } let muteAction = LabeledAction(title: title, image: image) { [weak delegate] in - guard let delegate = delegate else { return } - delegate.menuAction(self) + delegate?.menuAction(self) } return muteAction case .blockUser(let context): @@ -115,8 +115,7 @@ extension MastodonMenu { image = UIImage(systemName: "hand.raised") } let blockAction = LabeledAction(title: title, image: image, attributes: .destructive) { [weak delegate] in - guard let delegate = delegate else { return } - delegate.menuAction(self) + delegate?.menuAction(self) } return blockAction case .reportUser(let context): @@ -125,8 +124,7 @@ extension MastodonMenu { image: UIImage(systemName: "flag"), attributes: .destructive ) { [weak delegate] in - guard let delegate = delegate else { return } - delegate.menuAction(self) + delegate?.menuAction(self) } return reportAction case .shareUser(let context): @@ -134,8 +132,7 @@ extension MastodonMenu { title: L10n.Common.Controls.Actions.shareUser(context.name), image: UIImage(systemName: "square.and.arrow.up") ) { [weak delegate] in - guard let delegate = delegate else { return } - delegate.menuAction(self) + delegate?.menuAction(self) } return shareAction case .bookmarkStatus(let context): @@ -149,8 +146,7 @@ extension MastodonMenu { image = UIImage(systemName: "bookmark") } let action = LabeledAction(title: title, image: image) { [weak delegate] in - guard let delegate = delegate else { return } - delegate.menuAction(self) + delegate?.menuAction(self) } return action case .shareStatus: @@ -158,8 +154,7 @@ extension MastodonMenu { title: L10n.Common.Controls.Actions.sharePost, image: UIImage(systemName: "square.and.arrow.up") ) { [weak delegate] in - guard let delegate = delegate else { return } - delegate.menuAction(self) + delegate?.menuAction(self) } return action case .deleteStatus: @@ -168,8 +163,7 @@ extension MastodonMenu { image: UIImage(systemName: "minus.circle"), attributes: .destructive ) { [weak delegate] in - guard let delegate = delegate else { return } - delegate.menuAction(self) + delegate?.menuAction(self) } return deleteAction case let .translateStatus(context): @@ -178,8 +172,7 @@ extension MastodonMenu { title: L10n.Common.Controls.Actions.TranslatePost.title(language), image: UIImage(systemName: "character.book.closed") ) { [weak delegate] in - guard let delegate = delegate else { return } - delegate.menuAction(self) + delegate?.menuAction(self) } return translateAction case .showOriginal: @@ -187,8 +180,7 @@ extension MastodonMenu { title: L10n.Common.Controls.Status.Translation.showOriginal, image: UIImage(systemName: "character.book.closed") ) { [weak delegate] in - guard let delegate = delegate else { return } - delegate.menuAction(self) + delegate?.menuAction(self) } return action @@ -198,8 +190,7 @@ extension MastodonMenu { image: UIImage(systemName: "pencil") ) { [weak delegate] in - guard let delegate else { return } - delegate.menuAction(self) + delegate?.menuAction(self) } return editStatusAction @@ -214,26 +205,22 @@ extension MastodonMenu { image = UIImage(systemName: "person.fill.badge.plus") } let action = LabeledAction(title: title, image: image) { [weak delegate] in - guard let delegate else { return } - delegate.menuAction(self) + delegate?.menuAction(self) } return action case .blockDomain(let context): - let title: String - let image: UIImage? - if context.isBlocking { - title = L10n.Common.Controls.Actions.unblockDomain(context.domain) - image = UIImage(systemName: "hand.raised.slash.fill") - } else { - title = L10n.Common.Controls.Actions.blockDomain(context.domain) - image = UIImage(systemName: "hand.raised.fill") - } - let action = LabeledAction(title: title, image: image) { [weak delegate] in - guard let delegate else { return } + let title: String - delegate.menuAction(self) - } - return action + if context.isBlocking { + title = L10n.Common.Controls.Actions.unblockDomain(context.domain) + } else { + title = L10n.Common.Controls.Actions.blockDomain(context.domain) + } + + let action = LabeledAction(title: title, image: UIImage(systemName: "globe"), attributes: .destructive) { [weak delegate] in + delegate?.menuAction(self) + } + return action case .boostStatus(let context): let title: String @@ -263,12 +250,12 @@ extension MastodonMenu { delegate?.menuAction(self) } - case .copyLink: + case .copyStatusLink, .copyProfileLink(_): return LabeledAction(title: L10n.Common.Controls.Status.Actions.copyLink, image: UIImage(systemName: "doc.on.doc")) { [weak delegate] in delegate?.menuAction(self) } - case .openInBrowser: + case .openStatusInBrowser, .openUserInBrowser(_): return LabeledAction(title: L10n.Common.Controls.Actions.openInBrowser, image: UIImage(systemName: "safari")) { [weak delegate] in delegate?.menuAction(self) } @@ -343,7 +330,7 @@ extension MastodonMenu { public let name: String public let isFollowing: Bool - init(name: String, isFollowing: Bool) { + public init(name: String, isFollowing: Bool) { self.name = name self.isFollowing = isFollowing }