DM button

This commit is contained in:
Justin Mazzocchi 2021-03-01 16:53:36 -08:00
parent b235344268
commit a0141f7750
No known key found for this signature in database
GPG key ID: E223E6937AAFB01C
10 changed files with 61 additions and 13 deletions

View file

@ -11,6 +11,7 @@
"account.block-and-report" = "Block & report"; "account.block-and-report" = "Block & report";
"account.block.confirm-%@" = "Block %@?"; "account.block.confirm-%@" = "Block %@?";
"account.blocked" = "Blocked"; "account.blocked" = "Blocked";
"account.direct-message" = "Direct message";
"account.domain-block-%@" = "Block domain %@"; "account.domain-block-%@" = "Block domain %@";
"account.domain-block.confirm-%@" = "Block domain %@?"; "account.domain-block.confirm-%@" = "Block domain %@?";
"account.domain-unblock-%@" = "Unblock domain %@"; "account.domain-unblock-%@" = "Unblock domain %@";

View file

@ -495,8 +495,8 @@ private extension TableViewController {
handle(navigation: navigation) handle(navigation: navigation)
case let .attachment(attachmentViewModel, statusViewModel): case let .attachment(attachmentViewModel, statusViewModel):
present(attachmentViewModel: attachmentViewModel, statusViewModel: statusViewModel) present(attachmentViewModel: attachmentViewModel, statusViewModel: statusViewModel)
case let .compose(inReplyToViewModel, redraft): case let .compose(inReplyToViewModel, redraft, directMessageTo):
compose(inReplyToViewModel: inReplyToViewModel, redraft: redraft) compose(inReplyToViewModel: inReplyToViewModel, redraft: redraft, directMessageTo: directMessageTo)
case let .confirmDelete(statusViewModel, redraft): case let .confirmDelete(statusViewModel, redraft):
confirmDelete(statusViewModel: statusViewModel, redraft: redraft) confirmDelete(statusViewModel: statusViewModel, redraft: redraft)
case let .confirmUnfollow(accountViewModel): case let .confirmUnfollow(accountViewModel):
@ -595,11 +595,12 @@ private extension TableViewController {
} }
} }
func compose(inReplyToViewModel: StatusViewModel?, redraft: Status?) { func compose(inReplyToViewModel: StatusViewModel?, redraft: Status?, directMessageTo: AccountViewModel?) {
rootViewModel?.navigationViewModel?.presentedNewStatusViewModel = rootViewModel?.newStatusViewModel( rootViewModel?.navigationViewModel?.presentedNewStatusViewModel = rootViewModel?.newStatusViewModel(
identityContext: viewModel.identityContext, identityContext: viewModel.identityContext,
inReplyTo: inReplyToViewModel, inReplyTo: inReplyToViewModel,
redraft: redraft) redraft: redraft,
directMessageTo: directMessageTo)
} }
func confirmDelete(statusViewModel: StatusViewModel, redraft: Bool) { func confirmDelete(statusViewModel: StatusViewModel, redraft: Bool) {

View file

@ -9,7 +9,7 @@ public enum CollectionItemEvent {
case refresh case refresh
case navigation(Navigation) case navigation(Navigation)
case attachment(AttachmentViewModel, StatusViewModel) case attachment(AttachmentViewModel, StatusViewModel)
case compose(inReplyTo: StatusViewModel?, redraft: Status?) case compose(inReplyTo: StatusViewModel? = nil, redraft: Status? = nil, directMessageTo: AccountViewModel? = nil)
case confirmDelete(StatusViewModel, redraft: Bool) case confirmDelete(StatusViewModel, redraft: Bool)
case confirmUnfollow(AccountViewModel) case confirmUnfollow(AccountViewModel)
case confirmHideReblogs(AccountViewModel) case confirmHideReblogs(AccountViewModel)

View file

@ -358,6 +358,15 @@ extension CollectionItemsViewModel: CollectionViewModel {
} }
} }
extension CollectionItemsViewModel {
func sendDirectMessage(accountViewModel: AccountViewModel) {
eventsSubject.send(
Just(.compose(directMessageTo: accountViewModel))
.setFailureType(to: Error.self)
.eraseToAnyPublisher())
}
}
private extension CollectionItemsViewModel { private extension CollectionItemsViewModel {
private static let lastReadIdDebounceInterval: TimeInterval = 0.5 private static let lastReadIdDebounceInterval: TimeInterval = 0.5

View file

@ -29,6 +29,7 @@ public final class NewStatusViewModel: ObservableObject {
environment: AppEnvironment, environment: AppEnvironment,
inReplyTo: StatusViewModel?, inReplyTo: StatusViewModel?,
redraft: Status?, redraft: Status?,
directMessageTo: AccountViewModel?,
extensionContext: NSExtensionContext?) { extensionContext: NSExtensionContext?) {
self.allIdentitiesService = allIdentitiesService self.allIdentitiesService = allIdentitiesService
self.identityContext = identityContext self.identityContext = identityContext
@ -78,6 +79,9 @@ public final class NewStatusViewModel: ObservableObject {
.map("@".appending)) .map("@".appending))
compositionViewModel.text = mentions.joined(separator: " ").appending(" ") compositionViewModel.text = mentions.joined(separator: " ").appending(" ")
} else if let directMessageTo = directMessageTo {
compositionViewModel.text = directMessageTo.accountName.appending(" ")
visibility = .direct
} }
compositionViewModels = [compositionViewModel] compositionViewModels = [compositionViewModel]

View file

@ -76,6 +76,12 @@ public extension ProfileViewModel {
func fetchProfile() -> AnyPublisher<Never, Never> { func fetchProfile() -> AnyPublisher<Never, Never> {
profileService.fetchProfile().assignErrorsToAlertItem(to: \.alertItem, on: self) profileService.fetchProfile().assignErrorsToAlertItem(to: \.alertItem, on: self)
} }
func sendDirectMessage() {
guard let accountViewModel = accountViewModel else { return }
collectionViewModel.value.sendDirectMessage(accountViewModel: accountViewModel)
}
} }
extension ProfileViewModel: CollectionViewModel { extension ProfileViewModel: CollectionViewModel {

View file

@ -68,13 +68,15 @@ public extension RootViewModel {
func newStatusViewModel( func newStatusViewModel(
identityContext: IdentityContext, identityContext: IdentityContext,
inReplyTo: StatusViewModel? = nil, inReplyTo: StatusViewModel? = nil,
redraft: Status? = nil) -> NewStatusViewModel { redraft: Status? = nil,
directMessageTo: AccountViewModel? = nil) -> NewStatusViewModel {
NewStatusViewModel( NewStatusViewModel(
allIdentitiesService: allIdentitiesService, allIdentitiesService: allIdentitiesService,
identityContext: identityContext, identityContext: identityContext,
environment: environment, environment: environment,
inReplyTo: inReplyTo, inReplyTo: inReplyTo,
redraft: redraft, redraft: redraft,
directMessageTo: directMessageTo,
extensionContext: nil) extensionContext: nil)
} }
} }

View file

@ -39,6 +39,7 @@ public extension ShareExtensionNavigationViewModel {
environment: environment, environment: environment,
inReplyTo: nil, inReplyTo: nil,
redraft: nil, redraft: nil,
directMessageTo: nil,
extensionContext: extensionContext) extensionContext: extensionContext)
} }
} }

View file

@ -250,7 +250,7 @@ public extension StatusViewModel {
replyViewModel.configuration = configuration.reply() replyViewModel.configuration = configuration.reply()
eventsSubject.send( eventsSubject.send(
Just(.compose(inReplyTo: replyViewModel, redraft: nil)) Just(.compose(inReplyTo: replyViewModel))
.setFailureType(to: Error.self) .setFailureType(to: Error.self)
.eraseToAnyPublisher()) .eraseToAnyPublisher())
} }

View file

@ -13,6 +13,7 @@ final class AccountHeaderView: UIView {
let avatarImageView = SDAnimatedImageView() let avatarImageView = SDAnimatedImageView()
let avatarButton = UIButton() let avatarButton = UIButton()
let relationshipButtonsStackView = UIStackView() let relationshipButtonsStackView = UIStackView()
let directMessageButton = UIButton()
let followButton = UIButton(type: .system) let followButton = UIButton(type: .system)
let unfollowButton = UIButton(type: .system) let unfollowButton = UIButton(type: .system)
let notifyButton = UIButton() let notifyButton = UIButton()
@ -216,10 +217,18 @@ final class AccountHeaderView: UIView {
override func layoutSubviews() { override func layoutSubviews() {
super.layoutSubviews() super.layoutSubviews()
for button in [followButton, unfollowButton, notifyButton, unnotifyButton] { if let pointSize = followingButton.titleLabel?.font.pointSize {
let inset = (followButton.bounds.height - (button.titleLabel?.bounds.height ?? 0)) / 2 relationshipButtonsStackView.heightAnchor
.constraint(equalToConstant: pointSize + .defaultSpacing * 2).isActive = true
}
for button in [followButton, unfollowButton] {
let inset = (button.bounds.height - (button.titleLabel?.bounds.height ?? 0))
button.contentEdgeInsets = .init(top: 0, left: inset, bottom: 0, right: inset) button.contentEdgeInsets = .init(top: 0, left: inset, bottom: 0, right: inset)
}
for button in [directMessageButton, followButton, unfollowButton, notifyButton, unnotifyButton] {
button.layer.cornerRadius = button.bounds.height / 2 button.layer.cornerRadius = button.bounds.height / 2
} }
} }
@ -299,19 +308,30 @@ private extension AccountHeaderView {
relationshipButtonsStackView.spacing = .defaultSpacing relationshipButtonsStackView.spacing = .defaultSpacing
relationshipButtonsStackView.addArrangedSubview(UIView()) relationshipButtonsStackView.addArrangedSubview(UIView())
for button in [followButton, unfollowButton, notifyButton, unnotifyButton] { for button in [directMessageButton, notifyButton, unnotifyButton, followButton, unfollowButton] {
relationshipButtonsStackView.addArrangedSubview(button) relationshipButtonsStackView.addArrangedSubview(button)
button.titleLabel?.font = .preferredFont(forTextStyle: .headline) button.titleLabel?.font = .preferredFont(forTextStyle: .headline)
button.titleLabel?.adjustsFontForContentSizeCategory = true button.titleLabel?.adjustsFontForContentSizeCategory = true
button.backgroundColor = .secondarySystemBackground button.backgroundColor = .secondarySystemBackground
} }
directMessageButton.setImage(
UIImage(
systemName: "envelope",
withConfiguration: UIImage.SymbolConfiguration(scale: .small)),
for: .normal)
directMessageButton.accessibilityLabel = NSLocalizedString("account.direct-message", comment: "")
directMessageButton.addAction(
UIAction { [weak self] _ in self?.viewModel.sendDirectMessage() },
for: .touchUpInside)
followButton.setImage( followButton.setImage(
UIImage( UIImage(
systemName: "person.badge.plus", systemName: "person.badge.plus",
withConfiguration: UIImage.SymbolConfiguration(scale: .small)), withConfiguration: UIImage.SymbolConfiguration(scale: .small)),
for: .normal) for: .normal)
followButton.isHidden = true followButton.isHidden = true
followButton.titleLabel?.adjustsFontSizeToFitWidth = true
followButton.addAction( followButton.addAction(
UIAction { [weak self] _ in self?.viewModel.accountViewModel?.follow() }, UIAction { [weak self] _ in self?.viewModel.accountViewModel?.follow() },
for: .touchUpInside) for: .touchUpInside)
@ -323,14 +343,16 @@ private extension AccountHeaderView {
for: .normal) for: .normal)
unfollowButton.setTitle(NSLocalizedString("account.following", comment: ""), for: .normal) unfollowButton.setTitle(NSLocalizedString("account.following", comment: ""), for: .normal)
unfollowButton.isHidden = true unfollowButton.isHidden = true
unfollowButton.titleLabel?.adjustsFontSizeToFitWidth = true
unfollowButton.addAction( unfollowButton.addAction(
UIAction { [weak self] _ in self?.viewModel.accountViewModel?.confirmUnfollow() }, UIAction { [weak self] _ in self?.viewModel.accountViewModel?.confirmUnfollow() },
for: .touchUpInside) for: .touchUpInside)
notifyButton.setImage( notifyButton.setImage(
UIImage(systemName: "bell", UIImage(systemName: "bell",
withConfiguration: UIImage.SymbolConfiguration(scale: .large)), withConfiguration: UIImage.SymbolConfiguration(scale: .medium)),
for: .normal) for: .normal)
notifyButton.imageView?.contentMode = .scaleAspectFit
notifyButton.accessibilityLabel = NSLocalizedString("account.notify", comment: "") notifyButton.accessibilityLabel = NSLocalizedString("account.notify", comment: "")
notifyButton.tintColor = .secondaryLabel notifyButton.tintColor = .secondaryLabel
notifyButton.isHidden = true notifyButton.isHidden = true
@ -340,7 +362,7 @@ private extension AccountHeaderView {
unnotifyButton.setImage( unnotifyButton.setImage(
UIImage(systemName: "bell.fill", UIImage(systemName: "bell.fill",
withConfiguration: UIImage.SymbolConfiguration(scale: .large)), withConfiguration: UIImage.SymbolConfiguration(scale: .medium)),
for: .normal) for: .normal)
unnotifyButton.accessibilityLabel = NSLocalizedString("account.unnotify", comment: "") unnotifyButton.accessibilityLabel = NSLocalizedString("account.unnotify", comment: "")
unnotifyButton.isHidden = true unnotifyButton.isHidden = true
@ -505,7 +527,9 @@ private extension AccountHeaderView {
equalTo: headerImageView.bottomAnchor, equalTo: headerImageView.bottomAnchor,
constant: .defaultSpacing), constant: .defaultSpacing),
relationshipButtonsStackView.trailingAnchor.constraint(equalTo: readableContentGuide.trailingAnchor), relationshipButtonsStackView.trailingAnchor.constraint(equalTo: readableContentGuide.trailingAnchor),
relationshipButtonsStackView.bottomAnchor.constraint(equalTo: avatarBackgroundView.bottomAnchor), directMessageButton.widthAnchor.constraint(equalTo: directMessageButton.heightAnchor),
notifyButton.widthAnchor.constraint(equalTo: notifyButton.heightAnchor),
unnotifyButton.widthAnchor.constraint(equalTo: unnotifyButton.heightAnchor),
baseStackView.topAnchor.constraint(equalTo: avatarBackgroundView.bottomAnchor, constant: .defaultSpacing), baseStackView.topAnchor.constraint(equalTo: avatarBackgroundView.bottomAnchor, constant: .defaultSpacing),
baseStackView.leadingAnchor.constraint(equalTo: readableContentGuide.leadingAnchor), baseStackView.leadingAnchor.constraint(equalTo: readableContentGuide.leadingAnchor),
baseStackView.trailingAnchor.constraint(equalTo: readableContentGuide.trailingAnchor), baseStackView.trailingAnchor.constraint(equalTo: readableContentGuide.trailingAnchor),