This commit is contained in:
Justin Mazzocchi 2021-01-09 21:56:15 -08:00
parent 846c7987dc
commit 354242b835
No known key found for this signature in database
GPG key ID: E223E6937AAFB01C
12 changed files with 114 additions and 43 deletions

View file

@ -54,4 +54,13 @@ public extension CollectionItem {
public extension CollectionItem.StatusConfiguration {
static let `default` = Self(showContentToggled: false, showAttachmentsToggled: false)
func reply() -> Self {
Self(showContentToggled: showContentToggled,
showAttachmentsToggled: showAttachmentsToggled,
isContextParent: false,
isPinned: false,
isReplyInContext: false,
hasReplyFollowing: true)
}
}

View file

@ -68,6 +68,18 @@ final class NewStatusViewController: UIViewController {
self?.viewModel.post()
}
#if !IS_SHARE_EXTENSION
if let inReplyToViewModel = viewModel.inReplyToViewModel {
let statusView = StatusView(configuration: .init(viewModel: inReplyToViewModel))
statusView.isUserInteractionEnabled = false
statusView.bodyView.alpha = 0.5
statusView.buttonsStackView.isHidden = true
stackView.addArrangedSubview(statusView)
}
#endif
setupViewModelBindings()
}
@ -145,7 +157,9 @@ private extension NewStatusViewController {
let compositionView = CompositionView(
viewModel: compositionViewModel,
parentViewModel: viewModel)
stackView.insertArrangedSubview(compositionView, at: index)
let adjustedIndex = viewModel.inReplyToViewModel == nil ? index : index + 1
stackView.insertArrangedSubview(compositionView, at: adjustedIndex)
compositionView.textView.becomeFirstResponder()
DispatchQueue.main.async {

View file

@ -9,10 +9,10 @@ final class ProfileViewController: TableViewController {
private let viewModel: ProfileViewModel
private var cancellables = Set<AnyCancellable>()
required init(viewModel: ProfileViewModel, identification: Identification) {
required init(viewModel: ProfileViewModel, rootViewModel: RootViewModel, identification: Identification) {
self.viewModel = viewModel
super.init(viewModel: viewModel, identification: identification)
super.init(viewModel: viewModel, rootViewModel: rootViewModel, identification: identification)
}
override func viewDidLoad() {
@ -108,7 +108,7 @@ private extension ProfileViewController {
let reportViewModel = self.viewModel.accountViewModel?.reportViewModel()
else { return }
self.report(viewModel: reportViewModel)
self.report(reportViewModel: reportViewModel)
})
if relationship.blocking {

View file

@ -6,10 +6,12 @@ import SafariServices
import SwiftUI
import ViewModels
// swiftlint:disable file_length
class TableViewController: UITableViewController {
var transitionViewTag = -1
private let viewModel: CollectionViewModel
private let rootViewModel: RootViewModel
private let identification: Identification
private let loadingTableFooterView = LoadingTableFooterView()
private let webfingerIndicatorView = WebfingerIndicatorView()
@ -21,8 +23,9 @@ class TableViewController: UITableViewController {
.init(tableView: tableView, viewModelProvider: viewModel.viewModel(indexPath:))
}()
init(viewModel: CollectionViewModel, identification: Identification) {
init(viewModel: CollectionViewModel, rootViewModel: RootViewModel, identification: Identification) {
self.viewModel = viewModel
self.rootViewModel = rootViewModel
self.identification = identification
super.init(style: .plain)
@ -109,15 +112,6 @@ class TableViewController: UITableViewController {
}
}
extension TableViewController {
func report(viewModel: ReportViewModel) {
let reportViewController = ReportViewController(viewModel: viewModel)
let navigationController = UINavigationController(rootViewController: reportViewController)
present(navigationController, animated: true)
}
}
extension TableViewController: UITableViewDataSourcePrefetching {
func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) {
guard
@ -132,6 +126,13 @@ extension TableViewController: UITableViewDataSourcePrefetching {
}
extension TableViewController {
func report(reportViewModel: ReportViewModel) {
let reportViewController = ReportViewController(viewModel: reportViewModel)
let navigationController = UINavigationController(rootViewController: reportViewController)
present(navigationController, animated: true)
}
func sizeTableHeaderFooterViews() {
// https://useyourloaf.com/blog/variable-height-table-view-header/
if let headerView = tableView.tableHeaderView {
@ -299,32 +300,40 @@ private extension TableViewController {
case let .share(url):
share(url: url)
case let .navigation(navigation):
switch navigation {
case let .collection(collectionService):
show(TableViewController(
viewModel: CollectionItemsViewModel(
collectionService: collectionService,
identification: identification),
identification: identification),
sender: self)
case let .profile(profileService):
show(ProfileViewController(
viewModel: ProfileViewModel(
profileService: profileService,
identification: identification),
identification: identification),
sender: self)
case let .url(url):
present(SFSafariViewController(url: url), animated: true)
case .webfingerStart:
webfingerIndicatorView.startAnimating()
case .webfingerEnd:
webfingerIndicatorView.stopAnimating()
}
handle(navigation: navigation)
case let .attachment(attachmentViewModel, statusViewModel):
present(attachmentViewModel: attachmentViewModel, statusViewModel: statusViewModel)
case let .reply(statusViewModel):
reply(statusViewModel: statusViewModel)
case let .report(reportViewModel):
report(viewModel: reportViewModel)
report(reportViewModel: reportViewModel)
}
}
func handle(navigation: Navigation) {
switch navigation {
case let .collection(collectionService):
show(TableViewController(
viewModel: CollectionItemsViewModel(
collectionService: collectionService,
identification: identification),
rootViewModel: rootViewModel,
identification: identification),
sender: self)
case let .profile(profileService):
show(ProfileViewController(
viewModel: ProfileViewModel(
profileService: profileService,
identification: identification),
rootViewModel: rootViewModel,
identification: identification),
sender: self)
case let .url(url):
present(SFSafariViewController(url: url), animated: true)
case .webfingerStart:
webfingerIndicatorView.startAnimating()
case .webfingerEnd:
webfingerIndicatorView.stopAnimating()
}
}
@ -365,6 +374,18 @@ private extension TableViewController {
}
}
func reply(statusViewModel: StatusViewModel) {
let newStatusViewModel = rootViewModel.newStatusViewModel(
identification: identification,
inReplyTo: statusViewModel)
let newStatusViewController = UIHostingController(rootView: NewStatusView { newStatusViewModel })
let navigationController = UINavigationController(rootViewController: newStatusViewController)
navigationController.modalPresentationStyle = .overFullScreen
present(navigationController, animated: true)
}
func set(expandAllState: ExpandAllState) {
switch expandAllState {
case .hidden:
@ -388,3 +409,4 @@ private extension TableViewController {
present(activityViewController, animated: true, completion: nil)
}
}
// swiftlint:enable file_length

View file

@ -7,6 +7,7 @@ public enum CollectionItemEvent {
case ignorableOutput
case navigation(Navigation)
case attachment(AttachmentViewModel, StatusViewModel)
case reply(StatusViewModel)
case report(ReportViewModel)
case share(URL)
}

View file

@ -0,0 +1,5 @@
// Copyright © 2020 Metabolist. All rights reserved.
import ServiceLayer
public typealias Navigation = ServiceLayer.Navigation

View file

@ -14,6 +14,7 @@ public final class NewStatusViewModel: ObservableObject {
@Published public var canChangeIdentity = true
@Published public var alertItem: AlertItem?
@Published public private(set) var postingState = PostingState.composing
public let inReplyToViewModel: StatusViewModel?
public let events: AnyPublisher<Event, Never>
private let allIdentitiesService: AllIdentitiesService
@ -24,10 +25,12 @@ public final class NewStatusViewModel: ObservableObject {
public init(allIdentitiesService: AllIdentitiesService,
identification: Identification,
environment: AppEnvironment) {
environment: AppEnvironment,
inReplyTo: StatusViewModel?) {
self.allIdentitiesService = allIdentitiesService
self.identification = identification
self.environment = environment
inReplyToViewModel = inReplyTo
compositionViewModels = [CompositionViewModel(eventsSubject: compositionEventsSubject)]
events = eventsSubject.eraseToAnyPublisher()
visibility = identification.identity.preferences.postingDefaultVisibility
@ -109,7 +112,7 @@ public extension NewStatusViewModel {
func post() {
guard let unposted = compositionViewModels.first(where: { !$0.isPosted }) else { return }
post(viewModel: unposted, inReplyToId: nil)
post(viewModel: unposted, inReplyToId: inReplyToViewModel?.id)
}
}

View file

@ -58,11 +58,12 @@ public extension RootViewModel {
instanceURLService: InstanceURLService(environment: environment))
}
func newStatusViewModel(identification: Identification) -> NewStatusViewModel {
func newStatusViewModel(identification: Identification, inReplyTo: StatusViewModel? = nil) -> NewStatusViewModel {
NewStatusViewModel(
allIdentitiesService: allIdentitiesService,
identification: identification,
environment: environment)
environment: environment,
inReplyTo: inReplyTo)
}
}

View file

@ -36,6 +36,7 @@ public extension ShareExtensionNavigationViewModel {
return NewStatusViewModel(
allIdentitiesService: allIdentitiesService,
identification: identification,
environment: environment)
environment: environment,
inReplyTo: nil)
}
}

View file

@ -72,6 +72,8 @@ public extension StatusViewModel {
sensitive || identification.identity.preferences.readingExpandMedia == .hideAll
}
var id: Status.Id { statusService.status.displayStatus.id }
var accountName: String { "@".appending(statusService.status.displayStatus.account.acct) }
var avatarURL: URL {
@ -200,6 +202,14 @@ public extension StatusViewModel {
.eraseToAnyPublisher())
}
func reply() {
let replyViewModel = Self(statusService: statusService, identification: identification)
replyViewModel.configuration = configuration.reply()
eventsSubject.send(Just(.reply(replyViewModel)).setFailureType(to: Error.self).eraseToAnyPublisher())
}
func toggleReblogged() {
eventsSubject.send(
statusService.toggleReblogged()

View file

@ -198,6 +198,10 @@ private extension StatusView {
interactionsStackView.addArrangedSubview(favoritedByButton)
interactionsStackView.distribution = .fillEqually
replyButton.addAction(
UIAction { [weak self] _ in self?.statusConfiguration.viewModel.reply() },
for: .touchUpInside)
reblogButton.addAction(
UIAction { [weak self] _ in self?.statusConfiguration.viewModel.toggleReblogged() },
for: .touchUpInside)

View file

@ -5,10 +5,11 @@ import ViewModels
struct TableView: UIViewControllerRepresentable {
@EnvironmentObject var identification: Identification
@EnvironmentObject var rootViewModel: RootViewModel
let viewModelClosure: () -> CollectionViewModel
func makeUIViewController(context: Context) -> TableViewController {
TableViewController(viewModel: viewModelClosure(), identification: identification)
TableViewController(viewModel: viewModelClosure(), rootViewModel: rootViewModel, identification: identification)
}
func updateUIViewController(_ uiViewController: TableViewController, context: Context) {