mirror of
https://github.com/metabolist/metatext.git
synced 2024-11-22 00:01:00 +00:00
Replying
This commit is contained in:
parent
846c7987dc
commit
354242b835
12 changed files with 114 additions and 43 deletions
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
5
ViewModels/Sources/ViewModels/Entities/Navigation.swift
Normal file
5
ViewModels/Sources/ViewModels/Entities/Navigation.swift
Normal file
|
@ -0,0 +1,5 @@
|
|||
// Copyright © 2020 Metabolist. All rights reserved.
|
||||
|
||||
import ServiceLayer
|
||||
|
||||
public typealias Navigation = ServiceLayer.Navigation
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ public extension ShareExtensionNavigationViewModel {
|
|||
return NewStatusViewModel(
|
||||
allIdentitiesService: allIdentitiesService,
|
||||
identification: identification,
|
||||
environment: environment)
|
||||
environment: environment,
|
||||
inReplyTo: nil)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in a new issue