1
0
mirror of https://github.com/mastodon/mastodon-ios.git synced 2025-02-03 02:37:37 +01:00

Refactor compose intialization

- split ComposeContentViewModel.Kind into Destination (top level/reply) and an initial content string
- replies get the mentions prepended to the initial content string
This commit is contained in:
Jed Fox 2022-12-03 13:25:07 -05:00
parent ebf3835403
commit 3661b5ce90
No known key found for this signature in database
GPG Key ID: 0B61D18EA54B47E1
12 changed files with 49 additions and 64 deletions

View File

@ -117,7 +117,7 @@ extension DataSourceFacade {
let composeViewModel = ComposeViewModel(
context: provider.context,
authContext: provider.authContext,
kind: .reply(status: status)
destination: .reply(parent: status)
)
_ = provider.coordinator.present(
scene: .compose(viewModel: composeViewModel),

View File

@ -100,7 +100,7 @@ extension StatusTableViewControllerNavigateableCore where Self: DataSourceProvid
let composeViewModel = ComposeViewModel(
context: self.context,
authContext: authContext,
kind: .reply(status: status)
destination: .reply(parent: status)
)
_ = self.coordinator.present(
scene: .compose(viewModel: composeViewModel),

View File

@ -34,7 +34,8 @@ final class ComposeViewController: UIViewController, NeedsDependency {
return ComposeContentViewModel(
context: context,
authContext: viewModel.authContext,
kind: viewModel.kind
destination: viewModel.destination,
initialContent: viewModel.initialContent
)
}()
private(set) lazy var composeContentViewController: ComposeContentViewController = {

View File

@ -29,7 +29,8 @@ final class ComposeViewModel {
// input
let context: AppContext
let authContext: AuthContext
let kind: ComposeContentViewModel.Kind
let destination: ComposeContentViewModel.Destination
let initialContent: String
let traitCollectionDidChangePublisher = CurrentValueSubject<Void, Never>(Void()) // use CurrentValueSubject to make initial event emit
@ -41,17 +42,19 @@ final class ComposeViewModel {
init(
context: AppContext,
authContext: AuthContext,
kind: ComposeContentViewModel.Kind
destination: ComposeContentViewModel.Destination,
initialContent: String = ""
) {
self.context = context
self.authContext = authContext
self.kind = kind
self.destination = destination
self.initialContent = initialContent
// end init
self.title = {
switch kind {
case .post, .hashtag, .mention: return L10n.Scene.Compose.Title.newPost
case .reply: return L10n.Scene.Compose.Title.newReply
switch destination {
case .topLevel: return L10n.Scene.Compose.Title.newPost
case .reply: return L10n.Scene.Compose.Title.newReply
}
}()
}

View File

@ -162,10 +162,13 @@ extension HashtagTimelineViewController {
@objc private func composeBarButtonItemPressed(_ sender: UIBarButtonItem) {
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
let hashtag = "#" + viewModel.hashtag
UITextChecker.learnWord(hashtag)
let composeViewModel = ComposeViewModel(
context: context,
authContext: viewModel.authContext,
kind: .hashtag(hashtag: viewModel.hashtag)
destination: .topLevel,
initialContent: hashtag
)
_ = coordinator.present(scene: .compose(viewModel: composeViewModel), from: self, transition: .modal(animated: true, completion: nil))
}

View File

@ -538,10 +538,13 @@ extension ProfileViewController {
@objc private func replyBarButtonItemPressed(_ sender: UIBarButtonItem) {
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
guard let mastodonUser = viewModel.user else { return }
let mention = "@" + mastodonUser.acct
UITextChecker.learnWord(mention)
let composeViewModel = ComposeViewModel(
context: context,
authContext: viewModel.authContext,
kind: .mention(user: mastodonUser.asRecord)
destination: .topLevel,
initialContent: mention
)
_ = coordinator.present(scene: .compose(viewModel: composeViewModel), from: self, transition: .modal(animated: true, completion: nil))
}

View File

@ -379,7 +379,7 @@ extension MainTabBarController {
let composeViewModel = ComposeViewModel(
context: context,
authContext: authContext,
kind: .post
destination: .topLevel
)
_ = coordinator.present(scene: .compose(viewModel: composeViewModel), from: nil, transition: .modal(animated: true, completion: nil))
}
@ -804,7 +804,7 @@ extension MainTabBarController {
let composeViewModel = ComposeViewModel(
context: context,
authContext: authContext,
kind: .post
destination: .topLevel
)
_ = coordinator.present(scene: .compose(viewModel: composeViewModel), from: nil, transition: .modal(animated: true, completion: nil))
}

View File

@ -227,7 +227,7 @@ extension SidebarViewController: UICollectionViewDelegate {
let composeViewModel = ComposeViewModel(
context: context,
authContext: authContext,
kind: .post
destination: .topLevel
)
_ = coordinator.present(scene: .compose(viewModel: composeViewModel), from: self, transition: .modal(animated: true, completion: nil))
default:

View File

@ -117,7 +117,7 @@ extension ThreadViewController {
let composeViewModel = ComposeViewModel(
context: context,
authContext: viewModel.authContext,
kind: .reply(status: threadContext.status)
destination: .reply(parent: threadContext.status)
)
_ = coordinator.present(
scene: .compose(viewModel: composeViewModel),

View File

@ -185,7 +185,7 @@ extension SceneDelegate {
let composeViewModel = ComposeViewModel(
context: AppContext.shared,
authContext: authContext,
kind: .post
destination: .topLevel
)
_ = coordinator?.present(scene: .compose(viewModel: composeViewModel), from: nil, transition: .modal(animated: true, completion: nil))
logger.debug("\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): present compose scene")

View File

@ -47,10 +47,7 @@ extension ComposeContentViewModel {
}
.store(in: &disposeBag)
switch kind {
case .post:
break
case .reply(let status):
if case .reply(let status) = destination {
let cell = composeReplyToTableViewCell
// bind frame publisher
cell.$framePublisher
@ -66,10 +63,6 @@ extension ComposeContentViewModel {
guard let replyTo = status.object(in: context.managedObjectContext) else { return }
cell.statusView.configure(status: replyTo)
}
case .hashtag:
break
case .mention:
break
}
}
}
@ -83,7 +76,7 @@ extension ComposeContentViewModel: UITableViewDataSource {
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
switch Section.allCases[section] {
case .replyTo:
switch kind {
switch destination {
case .reply: return 1
default: return 0
}

View File

@ -32,7 +32,7 @@ public final class ComposeContentViewModel: NSObject, ObservableObject {
// input
let context: AppContext
let kind: Kind
let destination: Destination
weak var delegate: ComposeContentViewModelDelegate?
@Published var viewLayoutFrame = ViewLayoutFrame()
@ -59,8 +59,7 @@ public final class ComposeContentViewModel: NSObject, ObservableObject {
customEmojiPickerInputViewModel.configure(textInput: textView)
}
}
// for hashtag: "#<hashtag> "
// for mention: "@<mention> "
// allow dismissing the compose view without confirmation if content == intialContent
@Published public var initialContent = ""
@Published public var content = ""
@Published public var contentWeightedLength = 0
@ -138,11 +137,12 @@ public final class ComposeContentViewModel: NSObject, ObservableObject {
public init(
context: AppContext,
authContext: AuthContext,
kind: Kind
destination: Destination,
initialContent: String
) {
self.context = context
self.authContext = authContext
self.kind = kind
self.destination = destination
self.visibility = {
// default private when user locked
var visibility: Mastodon.Entity.Status.Visibility = {
@ -152,8 +152,7 @@ public final class ComposeContentViewModel: NSObject, ObservableObject {
return author.locked ? .private : .public
}()
// set visibility for reply post
switch kind {
case .reply(let record):
if case .reply(let record) = destination {
context.managedObjectContext.performAndWait {
guard let status = record.object(in: context.managedObjectContext) else {
assertionFailure()
@ -173,8 +172,6 @@ public final class ComposeContentViewModel: NSObject, ObservableObject {
break
}
}
default:
break
}
return visibility
}()
@ -185,7 +182,8 @@ public final class ComposeContentViewModel: NSObject, ObservableObject {
// end init
// setup initial value
switch kind {
let initialContentWithSpace = initialContent.isEmpty ? "" : initialContent + " "
switch destination {
case .reply(let record):
context.managedObjectContext.performAndWait {
guard let status = record.object(in: context.managedObjectContext) else {
@ -214,29 +212,15 @@ public final class ComposeContentViewModel: NSObject, ObservableObject {
}
let initialComposeContent = mentionAccts.joined(separator: " ")
let preInsertedContent: String? = initialComposeContent.isEmpty ? nil : initialComposeContent + " "
self.initialContent = preInsertedContent ?? ""
self.content = preInsertedContent ?? ""
let preInsertedContent = initialComposeContent.isEmpty ? "" : initialComposeContent + " "
self.initialContent = preInsertedContent + initialContentWithSpace
self.content = preInsertedContent + initialContentWithSpace
}
case .hashtag(let hashtag):
let initialComposeContent = "#" + hashtag
UITextChecker.learnWord(initialComposeContent)
let preInsertedContent = initialComposeContent + " "
self.initialContent = preInsertedContent
self.content = preInsertedContent
case .mention(let record):
context.managedObjectContext.performAndWait {
guard let user = record.object(in: context.managedObjectContext) else { return }
let initialComposeContent = "@" + user.acct
UITextChecker.learnWord(initialComposeContent)
let preInsertedContent = initialComposeContent + " "
self.initialContent = preInsertedContent
self.content = preInsertedContent
}
case .post:
break
case .topLevel:
self.initialContent = initialContentWithSpace
self.content = initialContentWithSpace
}
// set limit
let _configuration: Mastodon.Entity.Instance.Configuration? = {
var configuration: Mastodon.Entity.Instance.Configuration? = nil
@ -443,11 +427,9 @@ extension ComposeContentViewModel {
}
extension ComposeContentViewModel {
public enum Kind {
case post
case hashtag(hashtag: String)
case mention(user: ManagedObjectRecord<MastodonUser>)
case reply(status: ManagedObjectRecord<Status>)
public enum Destination {
case topLevel
case reply(parent: ManagedObjectRecord<Status>)
}
public enum ScrollViewState {
@ -530,10 +512,10 @@ extension ComposeContentViewModel {
return MastodonStatusPublisher(
author: author,
replyTo: {
switch self.kind {
case .reply(let status): return status
default: return nil
if case .reply(let status) = destination {
return status
}
return nil
}(),
isContentWarningComposing: isContentWarningActive,
contentWarning: contentWarning,