mirror of
https://github.com/mastodon/mastodon-ios
synced 2025-04-11 22:58:02 +02:00
Add follow/unfollow-option to user-section (IOS-103)
This commit is contained in:
parent
9b422a95ac
commit
d455da85d2
@ -102,8 +102,10 @@
|
||||
"unknown_language": "Unknown"
|
||||
},
|
||||
"edit_post": "Edit",
|
||||
"bookmark": "Bookmark"
|
||||
"bookmark": "Bookmark",
|
||||
"remove_bookmark": "Remove Bookmark",
|
||||
"follow" = "Follow %s",
|
||||
"unfollow" = "Unfollow %s"
|
||||
},
|
||||
"tabs": {
|
||||
"home": "Home",
|
||||
|
@ -384,6 +384,13 @@ extension DataSourceFacade {
|
||||
composeContext: .editStatus(status: status, statusSource: statusSource),
|
||||
destination: .topLevel)
|
||||
_ = dependency.coordinator.present(scene: .editStatus(viewModel: editStatusViewModel), transition: .modal(animated: true))
|
||||
|
||||
case .followUser(_):
|
||||
|
||||
guard let author = menuContext.author else { return }
|
||||
|
||||
try await DataSourceFacade.responseToUserFollowAction(dependency: dependency,
|
||||
user: author)
|
||||
}
|
||||
} // end func
|
||||
}
|
||||
|
@ -187,6 +187,7 @@ extension NotificationView {
|
||||
}
|
||||
.assign(to: \.isBlocking, on: viewModel)
|
||||
.store(in: &disposeBag)
|
||||
|
||||
// isMyself
|
||||
Publishers.CombineLatest(
|
||||
author.publisher(for: \.domain),
|
||||
@ -199,12 +200,27 @@ extension NotificationView {
|
||||
}
|
||||
.assign(to: \.isMyself, on: viewModel)
|
||||
.store(in: &disposeBag)
|
||||
|
||||
// follow request state
|
||||
notification.publisher(for: \.followRequestState)
|
||||
.assign(to: \.followRequestState, on: viewModel)
|
||||
.store(in: &disposeBag)
|
||||
|
||||
notification.publisher(for: \.transientFollowRequestState)
|
||||
.assign(to: \.transientFollowRequestState, on: viewModel)
|
||||
.store(in: &disposeBag)
|
||||
|
||||
// Following
|
||||
author.publisher(for: \.followingBy)
|
||||
.map { [weak viewModel] followingBy in
|
||||
guard let viewModel = viewModel else { return false }
|
||||
guard let authContext = viewModel.authContext else { return false }
|
||||
return followingBy.contains(where: {
|
||||
$0.id == authContext.mastodonAuthenticationBox.userID && $0.domain == authContext.mastodonAuthenticationBox.domain
|
||||
})
|
||||
}
|
||||
.assign(to: \.isFollowed, on: viewModel)
|
||||
.store(in: &disposeBag)
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -138,6 +138,10 @@ public enum L10n {
|
||||
public static let editPost = L10n.tr("Localizable", "Common.Controls.Actions.EditPost", fallback: "Edit")
|
||||
/// Find people to follow
|
||||
public static let findPeople = L10n.tr("Localizable", "Common.Controls.Actions.FindPeople", fallback: "Find people to follow")
|
||||
/// Follow %@
|
||||
public static func follow(_ p1: Any) -> String {
|
||||
return L10n.tr("Localizable", "Common.Controls.Actions.Follow", String(describing: p1), fallback: "Follow %@")
|
||||
}
|
||||
/// Manually search instead
|
||||
public static let manuallySearch = L10n.tr("Localizable", "Common.Controls.Actions.ManuallySearch", fallback: "Manually search instead")
|
||||
/// Next
|
||||
@ -192,6 +196,10 @@ public enum L10n {
|
||||
public static func unblockDomain(_ p1: Any) -> String {
|
||||
return L10n.tr("Localizable", "Common.Controls.Actions.UnblockDomain", String(describing: p1), fallback: "Unblock %@")
|
||||
}
|
||||
/// Unfollow %@
|
||||
public static func unfollow(_ p1: Any) -> String {
|
||||
return L10n.tr("Localizable", "Common.Controls.Actions.Unfollow", String(describing: p1), fallback: "Unfollow %@")
|
||||
}
|
||||
public enum TranslatePost {
|
||||
/// Translate from %@
|
||||
public static func title(_ p1: Any) -> String {
|
||||
|
@ -69,6 +69,8 @@ Please check your internet connection.";
|
||||
"Common.Controls.Actions.TranslatePost.UnknownLanguage" = "Unknown";
|
||||
"Common.Controls.Actions.TryAgain" = "Try Again";
|
||||
"Common.Controls.Actions.UnblockDomain" = "Unblock %@";
|
||||
"Common.Controls.Actions.Follow" = "Follow %@";
|
||||
"Common.Controls.Actions.Unfollow" = "Unfollow %@";
|
||||
"Common.Controls.Friendship.Block" = "Block";
|
||||
"Common.Controls.Friendship.BlockDomain" = "Block %@";
|
||||
"Common.Controls.Friendship.BlockUser" = "Block %@";
|
||||
|
@ -39,6 +39,7 @@ extension NotificationView {
|
||||
@Published public var isMuting = false
|
||||
@Published public var isBlocking = false
|
||||
@Published public var isTranslated = false
|
||||
@Published public var isFollowed = false
|
||||
|
||||
@Published public var timestamp: Date?
|
||||
|
||||
@ -208,18 +209,19 @@ extension NotificationView.ViewModel {
|
||||
$authorName,
|
||||
$isMuting,
|
||||
$isBlocking,
|
||||
Publishers.CombineLatest(
|
||||
Publishers.CombineLatest3(
|
||||
$isMyself,
|
||||
$isTranslated
|
||||
$isTranslated,
|
||||
$isFollowed
|
||||
)
|
||||
)
|
||||
.sink { [weak self] authorName, isMuting, isBlocking, isMyselfIsTranslated in
|
||||
.sink { [weak self] authorName, isMuting, isBlocking, isMyselfIsTranslatedIsFollowed in
|
||||
guard let name = authorName?.string else {
|
||||
notificationView.menuButton.menu = nil
|
||||
return
|
||||
}
|
||||
|
||||
let (isMyself, isTranslated) = isMyselfIsTranslated
|
||||
let (isMyself, isTranslated, isFollowed) = isMyselfIsTranslatedIsFollowed
|
||||
|
||||
lazy var instanceConfigurationV2: Mastodon.Entity.V2.Instance.Configuration? = {
|
||||
guard
|
||||
@ -243,6 +245,7 @@ extension NotificationView.ViewModel {
|
||||
isBlocking: isBlocking,
|
||||
isMyself: isMyself,
|
||||
isBookmarking: false, // no bookmark action display for notification item
|
||||
isFollowed: isFollowed,
|
||||
isTranslationEnabled: instanceConfigurationV2?.translation?.enabled == true,
|
||||
isTranslated: isTranslated,
|
||||
statusLanguage: ""
|
||||
|
@ -150,6 +150,7 @@ extension StatusAuthorView {
|
||||
public let isBlocking: Bool
|
||||
public let isMyself: Bool
|
||||
public let isBookmarking: Bool
|
||||
public let isFollowed: Bool
|
||||
|
||||
public let isTranslationEnabled: Bool
|
||||
public let isTranslated: Bool
|
||||
@ -175,6 +176,12 @@ extension StatusAuthorView {
|
||||
postActions.append(.shareStatus)
|
||||
|
||||
if menuContext.isMyself == false {
|
||||
|
||||
userActions.append(.followUser(.init(
|
||||
name: menuContext.name,
|
||||
isFollowing: menuContext.isFollowed
|
||||
)))
|
||||
|
||||
userActions.append(.muteUser(.init(
|
||||
name: menuContext.name,
|
||||
isMuting: menuContext.isMuting
|
||||
|
@ -258,6 +258,18 @@ extension StatusView {
|
||||
}
|
||||
.assign(to: \.isMyself, on: viewModel)
|
||||
.store(in: &disposeBag)
|
||||
|
||||
// Following
|
||||
author.publisher(for: \.followingBy)
|
||||
.map { [weak viewModel] followingBy in
|
||||
guard let viewModel = viewModel else { return false }
|
||||
guard let authContext = viewModel.authContext else { return false }
|
||||
return followingBy.contains(where: {
|
||||
$0.id == authContext.mastodonAuthenticationBox.userID && $0.domain == authContext.mastodonAuthenticationBox.domain
|
||||
})
|
||||
}
|
||||
.assign(to: \.isFollowed, on: viewModel)
|
||||
.store(in: &disposeBag)
|
||||
}
|
||||
|
||||
private func configureTimestamp(timestamp: AnyPublisher<Date, Never>) {
|
||||
@ -280,6 +292,7 @@ extension StatusView {
|
||||
|
||||
func revertTranslation() {
|
||||
guard let originalStatus = viewModel.originalStatus else { return }
|
||||
|
||||
viewModel.translatedFromLanguage = nil
|
||||
viewModel.translatedUsingProvider = nil
|
||||
originalStatus.reblog?.update(translatedContent: nil)
|
||||
|
@ -45,6 +45,7 @@ extension StatusView {
|
||||
@Published public var isMyself = false
|
||||
@Published public var isMuting = false
|
||||
@Published public var isBlocking = false
|
||||
@Published public var isFollowed = false
|
||||
|
||||
// Translation
|
||||
@Published public var isCurrentlyTranslating = false
|
||||
@ -656,10 +657,11 @@ extension StatusView.ViewModel {
|
||||
$authorName,
|
||||
$isMyself
|
||||
)
|
||||
let publishersTwo = Publishers.CombineLatest3(
|
||||
let publishersTwo = Publishers.CombineLatest4(
|
||||
$isMuting,
|
||||
$isBlocking,
|
||||
$isBookmark
|
||||
$isBookmark,
|
||||
$isFollowed
|
||||
)
|
||||
let publishersThree = Publishers.CombineLatest(
|
||||
$translatedFromLanguage,
|
||||
@ -673,7 +675,7 @@ extension StatusView.ViewModel {
|
||||
).eraseToAnyPublisher()
|
||||
.sink { tupleOne, tupleTwo, tupleThree in
|
||||
let (authorName, isMyself) = tupleOne
|
||||
let (isMuting, isBlocking, isBookmark) = tupleTwo
|
||||
let (isMuting, isBlocking, isBookmark, isFollowed) = tupleTwo
|
||||
let (translatedFromLanguage, language) = tupleThree
|
||||
|
||||
guard let name = authorName?.string else {
|
||||
@ -704,6 +706,7 @@ extension StatusView.ViewModel {
|
||||
isBlocking: isBlocking,
|
||||
isMyself: isMyself,
|
||||
isBookmarking: isBookmark,
|
||||
isFollowed: isFollowed,
|
||||
isTranslationEnabled: instanceConfigurationV2?.translation?.enabled == true,
|
||||
isTranslated: translatedFromLanguage != nil,
|
||||
statusLanguage: language
|
||||
|
@ -792,7 +792,6 @@ extension StatusView: StatusMetricViewDelegate {
|
||||
// MARK: - MastodonMenuDelegate
|
||||
extension StatusView: MastodonMenuDelegate {
|
||||
public func menuAction(_ action: MastodonMenu.Action) {
|
||||
logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)")
|
||||
delegate?.statusView(self, menuButton: authorView.menuButton, didSelectAction: action)
|
||||
}
|
||||
}
|
||||
|
@ -57,6 +57,7 @@ extension MastodonMenu {
|
||||
case shareStatus
|
||||
case deleteStatus
|
||||
case editStatus
|
||||
case followUser(FollowUserActionContext)
|
||||
|
||||
func build(delegate: MastodonMenuDelegate) -> LabeledAction {
|
||||
switch self {
|
||||
@ -171,6 +172,22 @@ extension MastodonMenu {
|
||||
}
|
||||
|
||||
return editStatusAction
|
||||
case .followUser(let context):
|
||||
let title: String
|
||||
let image: UIImage?
|
||||
if context.isFollowing {
|
||||
title = L10n.Common.Controls.Actions.unfollow(context.name)
|
||||
image = UIImage(systemName: "person.fill.badge.minus")
|
||||
} else {
|
||||
title = L10n.Common.Controls.Actions.follow(context.name)
|
||||
image = UIImage(systemName: "person.fill.badge.plus")
|
||||
}
|
||||
let action = LabeledAction(title: title, image: image) { [weak delegate] in
|
||||
guard let delegate = delegate else { return }
|
||||
delegate.menuAction(self)
|
||||
}
|
||||
return action
|
||||
|
||||
} // end switch
|
||||
} // end func build
|
||||
} // end enum Action
|
||||
@ -236,4 +253,15 @@ extension MastodonMenu {
|
||||
self.language = language
|
||||
}
|
||||
}
|
||||
|
||||
public struct FollowUserActionContext {
|
||||
|
||||
public let name: String
|
||||
public let isFollowing: Bool
|
||||
|
||||
init(name: String, isFollowing: Bool) {
|
||||
self.name = name
|
||||
self.isFollowing = isFollowing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user