Reply long press account menu

This commit is contained in:
Justin Mazzocchi 2021-03-21 16:23:41 -07:00
parent f3040eaad5
commit 12d0cf5ca0
No known key found for this signature in database
GPG key ID: E223E6937AAFB01C
8 changed files with 82 additions and 20 deletions

View file

@ -146,11 +146,24 @@ public extension StatusService {
.flatMap { contentDatabase.update(id: status.displayStatus.id, poll: $0) } .flatMap { contentDatabase.update(id: status.displayStatus.id, poll: $0) }
.eraseToAnyPublisher() .eraseToAnyPublisher()
} }
func asIdentity(id: Identity.Id) -> AnyPublisher<Self, Error> {
fetchAs(identityId: id).tryMap {
Self(environment: environment,
status: $0,
mastodonAPIClient: try MastodonAPIClient.forIdentity(id: id, environment: environment),
contentDatabase: try ContentDatabase(
id: id,
useHomeTimelineLastReadId: true,
inMemory: environment.inMemoryContent,
appGroup: AppEnvironment.appGroup,
keychain: environment.keychain)) }
.eraseToAnyPublisher()
}
} }
private extension StatusService { private extension StatusService {
func request(identityId: Identity.Id, func fetchAs(identityId: Identity.Id) -> AnyPublisher<Status, Error> {
endpointClosure: @escaping (Status.Id) -> StatusEndpoint) -> AnyPublisher<Never, Error> {
let client: MastodonAPIClient let client: MastodonAPIClient
do { do {
@ -162,11 +175,25 @@ private extension StatusService {
return client return client
.request(ResultsEndpoint.search(.init(query: status.displayStatus.uri, resolve: true, limit: 1))) .request(ResultsEndpoint.search(.init(query: status.displayStatus.uri, resolve: true, limit: 1)))
.tryMap { .tryMap {
guard let id = $0.statuses.first?.id else { throw APIError.unableToFetchRemoteStatus } guard let status = $0.statuses.first else { throw APIError.unableToFetchRemoteStatus }
return id return status
} }
.flatMap { client.request(endpointClosure($0)) } .eraseToAnyPublisher()
}
func request(identityId: Identity.Id,
endpointClosure: @escaping (Status.Id) -> StatusEndpoint) -> AnyPublisher<Never, Error> {
let client: MastodonAPIClient
do {
client = try MastodonAPIClient.forIdentity(id: identityId, environment: environment)
} catch {
return Fail(error: error).eraseToAnyPublisher()
}
return fetchAs(identityId: identityId)
.flatMap { client.request(endpointClosure($0.id)) }
.flatMap { _ in mastodonAPIClient.request(StatusEndpoint.status(id: status.displayStatus.id)) } .flatMap { _ in mastodonAPIClient.request(StatusEndpoint.status(id: status.displayStatus.id)) }
.flatMap(contentDatabase.insert(status:)) .flatMap(contentDatabase.insert(status:))
.eraseToAnyPublisher() .eraseToAnyPublisher()

View file

@ -533,8 +533,11 @@ 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, directMessageTo): case let .compose(identity, inReplyToViewModel, redraft, directMessageTo):
compose(inReplyToViewModel: inReplyToViewModel, redraft: redraft, directMessageTo: directMessageTo) compose(identity: identity,
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):
@ -613,9 +616,13 @@ private extension TableViewController {
} }
} }
func compose(inReplyToViewModel: StatusViewModel?, redraft: Status?, directMessageTo: AccountViewModel?) { func compose(identity: Identity?,
inReplyToViewModel: StatusViewModel?,
redraft: Status?,
directMessageTo: AccountViewModel?) {
rootViewModel?.navigationViewModel?.presentedNewStatusViewModel = rootViewModel?.newStatusViewModel( rootViewModel?.navigationViewModel?.presentedNewStatusViewModel = rootViewModel?.newStatusViewModel(
identityContext: viewModel.identityContext, identityContext: viewModel.identityContext,
identity: identity,
inReplyTo: inReplyToViewModel, inReplyTo: inReplyToViewModel,
redraft: redraft, redraft: redraft,
directMessageTo: directMessageTo) directMessageTo: directMessageTo)

View file

@ -9,7 +9,10 @@ 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? = nil, redraft: Status? = nil, directMessageTo: AccountViewModel? = nil) case compose(identity: Identity? = nil,
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

@ -26,6 +26,7 @@ public final class NewStatusViewModel: ObservableObject {
public init(allIdentitiesService: AllIdentitiesService, public init(allIdentitiesService: AllIdentitiesService,
identityContext: IdentityContext, identityContext: IdentityContext,
environment: AppEnvironment, environment: AppEnvironment,
identity: Identity?,
inReplyTo: StatusViewModel?, inReplyTo: StatusViewModel?,
redraft: Status?, redraft: Status?,
directMessageTo: AccountViewModel?, directMessageTo: AccountViewModel?,
@ -37,7 +38,7 @@ public final class NewStatusViewModel: ObservableObject {
events = eventsSubject.eraseToAnyPublisher() events = eventsSubject.eraseToAnyPublisher()
visibility = redraft?.visibility visibility = redraft?.visibility
?? inReplyTo?.visibility ?? inReplyTo?.visibility
?? identityContext.identity.preferences.postingDefaultVisibility ?? (identity ?? identityContext.identity).preferences.postingDefaultVisibility
if let inReplyTo = inReplyTo { if let inReplyTo = inReplyTo {
switch inReplyTo.visibility { switch inReplyTo.visibility {
@ -74,7 +75,7 @@ public final class NewStatusViewModel: ObservableObject {
} }
mentions.formUnion(inReplyTo.mentions.map(\.acct) mentions.formUnion(inReplyTo.mentions.map(\.acct)
.filter { $0 != identityContext.identity.account?.username } .filter { $0 != (identity ?? identityContext.identity).account?.username }
.map("@".appending)) .map("@".appending))
compositionViewModel.text = mentions.joined(separator: " ").appending(" ") compositionViewModel.text = mentions.joined(separator: " ").appending(" ")
@ -95,6 +96,10 @@ public final class NewStatusViewModel: ObservableObject {
compositionEventsSubject compositionEventsSubject
.sink { [weak self] in self?.handle(event: $0) } .sink { [weak self] in self?.handle(event: $0) }
.store(in: &cancellables) .store(in: &cancellables)
if let identity = identity {
setIdentity(identity)
}
} }
} }

View file

@ -65,6 +65,7 @@ public extension RootViewModel {
func newStatusViewModel( func newStatusViewModel(
identityContext: IdentityContext, identityContext: IdentityContext,
identity: Identity? = nil,
inReplyTo: StatusViewModel? = nil, inReplyTo: StatusViewModel? = nil,
redraft: Status? = nil, redraft: Status? = nil,
directMessageTo: AccountViewModel? = nil) -> NewStatusViewModel { directMessageTo: AccountViewModel? = nil) -> NewStatusViewModel {
@ -72,6 +73,7 @@ public extension RootViewModel {
allIdentitiesService: allIdentitiesService, allIdentitiesService: allIdentitiesService,
identityContext: identityContext, identityContext: identityContext,
environment: environment, environment: environment,
identity: identity,
inReplyTo: inReplyTo, inReplyTo: inReplyTo,
redraft: redraft, redraft: redraft,
directMessageTo: directMessageTo, directMessageTo: directMessageTo,

View file

@ -37,6 +37,7 @@ public extension ShareExtensionNavigationViewModel {
allIdentitiesService: allIdentitiesService, allIdentitiesService: allIdentitiesService,
identityContext: identityContext, identityContext: identityContext,
environment: environment, environment: environment,
identity: nil,
inReplyTo: nil, inReplyTo: nil,
redraft: nil, redraft: nil,
directMessageTo: nil, directMessageTo: nil,

View file

@ -242,17 +242,33 @@ public extension StatusViewModel {
.eraseToAnyPublisher()) .eraseToAnyPublisher())
} }
func reply() { func reply(identity: Identity? = nil) {
let replyViewModel = Self(statusService: statusService, if let identity = identity {
identityContext: identityContext, let identityContext = self.identityContext
eventsSubject: .init()) let configuration = self.configuration.reply()
replyViewModel.configuration = configuration.reply() eventsSubject.send(statusService.asIdentity(id: identity.id).map {
let replyViewModel = Self(statusService: $0,
identityContext: identityContext,
eventsSubject: .init())
eventsSubject.send( replyViewModel.configuration = configuration
Just(.compose(inReplyTo: replyViewModel))
.setFailureType(to: Error.self) return CollectionItemEvent.compose(identity: identity, inReplyTo: replyViewModel)
.eraseToAnyPublisher()) }
.eraseToAnyPublisher())
} else {
let replyViewModel = Self(statusService: statusService,
identityContext: identityContext,
eventsSubject: .init())
replyViewModel.configuration = configuration.reply()
eventsSubject.send(
Just(.compose(inReplyTo: replyViewModel))
.setFailureType(to: Error.self)
.eraseToAnyPublisher())
}
} }
func toggleReblogged(identityId: Identity.Id? = nil) { func toggleReblogged(identityId: Identity.Id? = nil) {

View file

@ -605,6 +605,7 @@ private extension StatusView {
replyButton.setCountTitle(count: viewModel.repliesCount, isContextParent: isContextParent) replyButton.setCountTitle(count: viewModel.repliesCount, isContextParent: isContextParent)
replyButton.isEnabled = isAuthenticated replyButton.isEnabled = isAuthenticated
replyButton.menu = authenticatedIdentitiesMenu { viewModel.reply(identity: $0) }
if viewModel.identityContext.appPreferences.showReblogAndFavoriteCounts || isContextParent { if viewModel.identityContext.appPreferences.showReblogAndFavoriteCounts || isContextParent {
reblogButton.setCountTitle(count: viewModel.reblogsCount, isContextParent: isContextParent) reblogButton.setCountTitle(count: viewModel.reblogsCount, isContextParent: isContextParent)