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:
parent
ebf3835403
commit
3661b5ce90
|
@ -117,7 +117,7 @@ extension DataSourceFacade {
|
||||||
let composeViewModel = ComposeViewModel(
|
let composeViewModel = ComposeViewModel(
|
||||||
context: provider.context,
|
context: provider.context,
|
||||||
authContext: provider.authContext,
|
authContext: provider.authContext,
|
||||||
kind: .reply(status: status)
|
destination: .reply(parent: status)
|
||||||
)
|
)
|
||||||
_ = provider.coordinator.present(
|
_ = provider.coordinator.present(
|
||||||
scene: .compose(viewModel: composeViewModel),
|
scene: .compose(viewModel: composeViewModel),
|
||||||
|
|
|
@ -100,7 +100,7 @@ extension StatusTableViewControllerNavigateableCore where Self: DataSourceProvid
|
||||||
let composeViewModel = ComposeViewModel(
|
let composeViewModel = ComposeViewModel(
|
||||||
context: self.context,
|
context: self.context,
|
||||||
authContext: authContext,
|
authContext: authContext,
|
||||||
kind: .reply(status: status)
|
destination: .reply(parent: status)
|
||||||
)
|
)
|
||||||
_ = self.coordinator.present(
|
_ = self.coordinator.present(
|
||||||
scene: .compose(viewModel: composeViewModel),
|
scene: .compose(viewModel: composeViewModel),
|
||||||
|
|
|
@ -34,7 +34,8 @@ final class ComposeViewController: UIViewController, NeedsDependency {
|
||||||
return ComposeContentViewModel(
|
return ComposeContentViewModel(
|
||||||
context: context,
|
context: context,
|
||||||
authContext: viewModel.authContext,
|
authContext: viewModel.authContext,
|
||||||
kind: viewModel.kind
|
destination: viewModel.destination,
|
||||||
|
initialContent: viewModel.initialContent
|
||||||
)
|
)
|
||||||
}()
|
}()
|
||||||
private(set) lazy var composeContentViewController: ComposeContentViewController = {
|
private(set) lazy var composeContentViewController: ComposeContentViewController = {
|
||||||
|
|
|
@ -29,7 +29,8 @@ final class ComposeViewModel {
|
||||||
// input
|
// input
|
||||||
let context: AppContext
|
let context: AppContext
|
||||||
let authContext: AuthContext
|
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
|
let traitCollectionDidChangePublisher = CurrentValueSubject<Void, Never>(Void()) // use CurrentValueSubject to make initial event emit
|
||||||
|
|
||||||
|
@ -41,17 +42,19 @@ final class ComposeViewModel {
|
||||||
init(
|
init(
|
||||||
context: AppContext,
|
context: AppContext,
|
||||||
authContext: AuthContext,
|
authContext: AuthContext,
|
||||||
kind: ComposeContentViewModel.Kind
|
destination: ComposeContentViewModel.Destination,
|
||||||
|
initialContent: String = ""
|
||||||
) {
|
) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.authContext = authContext
|
self.authContext = authContext
|
||||||
self.kind = kind
|
self.destination = destination
|
||||||
|
self.initialContent = initialContent
|
||||||
// end init
|
// end init
|
||||||
|
|
||||||
self.title = {
|
self.title = {
|
||||||
switch kind {
|
switch destination {
|
||||||
case .post, .hashtag, .mention: return L10n.Scene.Compose.Title.newPost
|
case .topLevel: return L10n.Scene.Compose.Title.newPost
|
||||||
case .reply: return L10n.Scene.Compose.Title.newReply
|
case .reply: return L10n.Scene.Compose.Title.newReply
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
|
@ -162,10 +162,13 @@ extension HashtagTimelineViewController {
|
||||||
|
|
||||||
@objc private func composeBarButtonItemPressed(_ sender: UIBarButtonItem) {
|
@objc private func composeBarButtonItemPressed(_ sender: UIBarButtonItem) {
|
||||||
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
|
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(
|
let composeViewModel = ComposeViewModel(
|
||||||
context: context,
|
context: context,
|
||||||
authContext: viewModel.authContext,
|
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))
|
_ = coordinator.present(scene: .compose(viewModel: composeViewModel), from: self, transition: .modal(animated: true, completion: nil))
|
||||||
}
|
}
|
||||||
|
|
|
@ -538,10 +538,13 @@ extension ProfileViewController {
|
||||||
@objc private func replyBarButtonItemPressed(_ sender: UIBarButtonItem) {
|
@objc private func replyBarButtonItemPressed(_ sender: UIBarButtonItem) {
|
||||||
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
|
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
|
||||||
guard let mastodonUser = viewModel.user else { return }
|
guard let mastodonUser = viewModel.user else { return }
|
||||||
|
let mention = "@" + mastodonUser.acct
|
||||||
|
UITextChecker.learnWord(mention)
|
||||||
let composeViewModel = ComposeViewModel(
|
let composeViewModel = ComposeViewModel(
|
||||||
context: context,
|
context: context,
|
||||||
authContext: viewModel.authContext,
|
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))
|
_ = coordinator.present(scene: .compose(viewModel: composeViewModel), from: self, transition: .modal(animated: true, completion: nil))
|
||||||
}
|
}
|
||||||
|
|
|
@ -379,7 +379,7 @@ extension MainTabBarController {
|
||||||
let composeViewModel = ComposeViewModel(
|
let composeViewModel = ComposeViewModel(
|
||||||
context: context,
|
context: context,
|
||||||
authContext: authContext,
|
authContext: authContext,
|
||||||
kind: .post
|
destination: .topLevel
|
||||||
)
|
)
|
||||||
_ = coordinator.present(scene: .compose(viewModel: composeViewModel), from: nil, transition: .modal(animated: true, completion: nil))
|
_ = coordinator.present(scene: .compose(viewModel: composeViewModel), from: nil, transition: .modal(animated: true, completion: nil))
|
||||||
}
|
}
|
||||||
|
@ -804,7 +804,7 @@ extension MainTabBarController {
|
||||||
let composeViewModel = ComposeViewModel(
|
let composeViewModel = ComposeViewModel(
|
||||||
context: context,
|
context: context,
|
||||||
authContext: authContext,
|
authContext: authContext,
|
||||||
kind: .post
|
destination: .topLevel
|
||||||
)
|
)
|
||||||
_ = coordinator.present(scene: .compose(viewModel: composeViewModel), from: nil, transition: .modal(animated: true, completion: nil))
|
_ = coordinator.present(scene: .compose(viewModel: composeViewModel), from: nil, transition: .modal(animated: true, completion: nil))
|
||||||
}
|
}
|
||||||
|
|
|
@ -227,7 +227,7 @@ extension SidebarViewController: UICollectionViewDelegate {
|
||||||
let composeViewModel = ComposeViewModel(
|
let composeViewModel = ComposeViewModel(
|
||||||
context: context,
|
context: context,
|
||||||
authContext: authContext,
|
authContext: authContext,
|
||||||
kind: .post
|
destination: .topLevel
|
||||||
)
|
)
|
||||||
_ = coordinator.present(scene: .compose(viewModel: composeViewModel), from: self, transition: .modal(animated: true, completion: nil))
|
_ = coordinator.present(scene: .compose(viewModel: composeViewModel), from: self, transition: .modal(animated: true, completion: nil))
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -117,7 +117,7 @@ extension ThreadViewController {
|
||||||
let composeViewModel = ComposeViewModel(
|
let composeViewModel = ComposeViewModel(
|
||||||
context: context,
|
context: context,
|
||||||
authContext: viewModel.authContext,
|
authContext: viewModel.authContext,
|
||||||
kind: .reply(status: threadContext.status)
|
destination: .reply(parent: threadContext.status)
|
||||||
)
|
)
|
||||||
_ = coordinator.present(
|
_ = coordinator.present(
|
||||||
scene: .compose(viewModel: composeViewModel),
|
scene: .compose(viewModel: composeViewModel),
|
||||||
|
|
|
@ -185,7 +185,7 @@ extension SceneDelegate {
|
||||||
let composeViewModel = ComposeViewModel(
|
let composeViewModel = ComposeViewModel(
|
||||||
context: AppContext.shared,
|
context: AppContext.shared,
|
||||||
authContext: authContext,
|
authContext: authContext,
|
||||||
kind: .post
|
destination: .topLevel
|
||||||
)
|
)
|
||||||
_ = coordinator?.present(scene: .compose(viewModel: composeViewModel), from: nil, transition: .modal(animated: true, completion: nil))
|
_ = 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")
|
logger.debug("\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): present compose scene")
|
||||||
|
|
|
@ -47,10 +47,7 @@ extension ComposeContentViewModel {
|
||||||
}
|
}
|
||||||
.store(in: &disposeBag)
|
.store(in: &disposeBag)
|
||||||
|
|
||||||
switch kind {
|
if case .reply(let status) = destination {
|
||||||
case .post:
|
|
||||||
break
|
|
||||||
case .reply(let status):
|
|
||||||
let cell = composeReplyToTableViewCell
|
let cell = composeReplyToTableViewCell
|
||||||
// bind frame publisher
|
// bind frame publisher
|
||||||
cell.$framePublisher
|
cell.$framePublisher
|
||||||
|
@ -66,10 +63,6 @@ extension ComposeContentViewModel {
|
||||||
guard let replyTo = status.object(in: context.managedObjectContext) else { return }
|
guard let replyTo = status.object(in: context.managedObjectContext) else { return }
|
||||||
cell.statusView.configure(status: replyTo)
|
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 {
|
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||||
switch Section.allCases[section] {
|
switch Section.allCases[section] {
|
||||||
case .replyTo:
|
case .replyTo:
|
||||||
switch kind {
|
switch destination {
|
||||||
case .reply: return 1
|
case .reply: return 1
|
||||||
default: return 0
|
default: return 0
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ public final class ComposeContentViewModel: NSObject, ObservableObject {
|
||||||
|
|
||||||
// input
|
// input
|
||||||
let context: AppContext
|
let context: AppContext
|
||||||
let kind: Kind
|
let destination: Destination
|
||||||
weak var delegate: ComposeContentViewModelDelegate?
|
weak var delegate: ComposeContentViewModelDelegate?
|
||||||
|
|
||||||
@Published var viewLayoutFrame = ViewLayoutFrame()
|
@Published var viewLayoutFrame = ViewLayoutFrame()
|
||||||
|
@ -59,8 +59,7 @@ public final class ComposeContentViewModel: NSObject, ObservableObject {
|
||||||
customEmojiPickerInputViewModel.configure(textInput: textView)
|
customEmojiPickerInputViewModel.configure(textInput: textView)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// for hashtag: "#<hashtag> "
|
// allow dismissing the compose view without confirmation if content == intialContent
|
||||||
// for mention: "@<mention> "
|
|
||||||
@Published public var initialContent = ""
|
@Published public var initialContent = ""
|
||||||
@Published public var content = ""
|
@Published public var content = ""
|
||||||
@Published public var contentWeightedLength = 0
|
@Published public var contentWeightedLength = 0
|
||||||
|
@ -138,11 +137,12 @@ public final class ComposeContentViewModel: NSObject, ObservableObject {
|
||||||
public init(
|
public init(
|
||||||
context: AppContext,
|
context: AppContext,
|
||||||
authContext: AuthContext,
|
authContext: AuthContext,
|
||||||
kind: Kind
|
destination: Destination,
|
||||||
|
initialContent: String
|
||||||
) {
|
) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.authContext = authContext
|
self.authContext = authContext
|
||||||
self.kind = kind
|
self.destination = destination
|
||||||
self.visibility = {
|
self.visibility = {
|
||||||
// default private when user locked
|
// default private when user locked
|
||||||
var visibility: Mastodon.Entity.Status.Visibility = {
|
var visibility: Mastodon.Entity.Status.Visibility = {
|
||||||
|
@ -152,8 +152,7 @@ public final class ComposeContentViewModel: NSObject, ObservableObject {
|
||||||
return author.locked ? .private : .public
|
return author.locked ? .private : .public
|
||||||
}()
|
}()
|
||||||
// set visibility for reply post
|
// set visibility for reply post
|
||||||
switch kind {
|
if case .reply(let record) = destination {
|
||||||
case .reply(let record):
|
|
||||||
context.managedObjectContext.performAndWait {
|
context.managedObjectContext.performAndWait {
|
||||||
guard let status = record.object(in: context.managedObjectContext) else {
|
guard let status = record.object(in: context.managedObjectContext) else {
|
||||||
assertionFailure()
|
assertionFailure()
|
||||||
|
@ -173,8 +172,6 @@ public final class ComposeContentViewModel: NSObject, ObservableObject {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
return visibility
|
return visibility
|
||||||
}()
|
}()
|
||||||
|
@ -185,7 +182,8 @@ public final class ComposeContentViewModel: NSObject, ObservableObject {
|
||||||
// end init
|
// end init
|
||||||
|
|
||||||
// setup initial value
|
// setup initial value
|
||||||
switch kind {
|
let initialContentWithSpace = initialContent.isEmpty ? "" : initialContent + " "
|
||||||
|
switch destination {
|
||||||
case .reply(let record):
|
case .reply(let record):
|
||||||
context.managedObjectContext.performAndWait {
|
context.managedObjectContext.performAndWait {
|
||||||
guard let status = record.object(in: context.managedObjectContext) else {
|
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 initialComposeContent = mentionAccts.joined(separator: " ")
|
||||||
let preInsertedContent: String? = initialComposeContent.isEmpty ? nil : initialComposeContent + " "
|
let preInsertedContent = initialComposeContent.isEmpty ? "" : initialComposeContent + " "
|
||||||
self.initialContent = preInsertedContent ?? ""
|
self.initialContent = preInsertedContent + initialContentWithSpace
|
||||||
self.content = preInsertedContent ?? ""
|
self.content = preInsertedContent + initialContentWithSpace
|
||||||
}
|
}
|
||||||
case .hashtag(let hashtag):
|
case .topLevel:
|
||||||
let initialComposeContent = "#" + hashtag
|
self.initialContent = initialContentWithSpace
|
||||||
UITextChecker.learnWord(initialComposeContent)
|
self.content = initialContentWithSpace
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// set limit
|
// set limit
|
||||||
let _configuration: Mastodon.Entity.Instance.Configuration? = {
|
let _configuration: Mastodon.Entity.Instance.Configuration? = {
|
||||||
var configuration: Mastodon.Entity.Instance.Configuration? = nil
|
var configuration: Mastodon.Entity.Instance.Configuration? = nil
|
||||||
|
@ -443,11 +427,9 @@ extension ComposeContentViewModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ComposeContentViewModel {
|
extension ComposeContentViewModel {
|
||||||
public enum Kind {
|
public enum Destination {
|
||||||
case post
|
case topLevel
|
||||||
case hashtag(hashtag: String)
|
case reply(parent: ManagedObjectRecord<Status>)
|
||||||
case mention(user: ManagedObjectRecord<MastodonUser>)
|
|
||||||
case reply(status: ManagedObjectRecord<Status>)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum ScrollViewState {
|
public enum ScrollViewState {
|
||||||
|
@ -530,10 +512,10 @@ extension ComposeContentViewModel {
|
||||||
return MastodonStatusPublisher(
|
return MastodonStatusPublisher(
|
||||||
author: author,
|
author: author,
|
||||||
replyTo: {
|
replyTo: {
|
||||||
switch self.kind {
|
if case .reply(let status) = destination {
|
||||||
case .reply(let status): return status
|
return status
|
||||||
default: return nil
|
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}(),
|
}(),
|
||||||
isContentWarningComposing: isContentWarningActive,
|
isContentWarningComposing: isContentWarningActive,
|
||||||
contentWarning: contentWarning,
|
contentWarning: contentWarning,
|
||||||
|
|
Loading…
Reference in New Issue