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) }
.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 {
func request(identityId: Identity.Id,
endpointClosure: @escaping (Status.Id) -> StatusEndpoint) -> AnyPublisher<Never, Error> {
func fetchAs(identityId: Identity.Id) -> AnyPublisher<Status, Error> {
let client: MastodonAPIClient
do {
@ -162,11 +175,25 @@ private extension StatusService {
return client
.request(ResultsEndpoint.search(.init(query: status.displayStatus.uri, resolve: true, limit: 1)))
.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(contentDatabase.insert(status:))
.eraseToAnyPublisher()

View file

@ -533,8 +533,11 @@ private extension TableViewController {
handle(navigation: navigation)
case let .attachment(attachmentViewModel, statusViewModel):
present(attachmentViewModel: attachmentViewModel, statusViewModel: statusViewModel)
case let .compose(inReplyToViewModel, redraft, directMessageTo):
compose(inReplyToViewModel: inReplyToViewModel, redraft: redraft, directMessageTo: directMessageTo)
case let .compose(identity, inReplyToViewModel, redraft, directMessageTo):
compose(identity: identity,
inReplyToViewModel: inReplyToViewModel,
redraft: redraft,
directMessageTo: directMessageTo)
case let .confirmDelete(statusViewModel, redraft):
confirmDelete(statusViewModel: statusViewModel, redraft: redraft)
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(
identityContext: viewModel.identityContext,
identity: identity,
inReplyTo: inReplyToViewModel,
redraft: redraft,
directMessageTo: directMessageTo)

View file

@ -9,7 +9,10 @@ public enum CollectionItemEvent {
case refresh
case navigation(Navigation)
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 confirmUnfollow(AccountViewModel)
case confirmHideReblogs(AccountViewModel)

View file

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

View file

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

View file

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

View file

@ -242,17 +242,33 @@ public extension StatusViewModel {
.eraseToAnyPublisher())
}
func reply() {
let replyViewModel = Self(statusService: statusService,
identityContext: identityContext,
eventsSubject: .init())
func reply(identity: Identity? = nil) {
if let identity = identity {
let identityContext = self.identityContext
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(
Just(.compose(inReplyTo: replyViewModel))
.setFailureType(to: Error.self)
.eraseToAnyPublisher())
replyViewModel.configuration = configuration
return CollectionItemEvent.compose(identity: identity, inReplyTo: replyViewModel)
}
.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) {

View file

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