feat: add auto complete replace input action

This commit is contained in:
CMK 2021-05-18 15:06:00 +08:00
parent 3927f1630a
commit 672bfab200
5 changed files with 51 additions and 2 deletions

View File

@ -47,6 +47,7 @@ extension AutoCompleteItem: Hashable {
hasher.combine(account.id)
case .emoji(let emoji):
hasher.combine(emoji.shortcode)
hasher.combine(emoji.url)
case .bottomLoader:
hasher.combine(String(describing: AutoCompleteItem.bottomLoader.self))
}

View File

@ -37,6 +37,7 @@ extension AutoCompleteSection {
return cell
case .bottomLoader:
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: TimelineBottomLoaderTableViewCell.self), for: indexPath) as! TimelineBottomLoaderTableViewCell
cell.startAnimating()
return cell
}
}

View File

@ -9,12 +9,18 @@ import os.log
import UIKit
import Combine
protocol AutoCompleteViewControllerDelegate: AnyObject {
func autoCompleteViewController(_ viewController: AutoCompleteViewController, didSelectItem item: AutoCompleteItem)
}
final class AutoCompleteViewController: UIViewController {
static let chevronViewHeight: CGFloat = 24
var viewModel: AutoCompleteViewModel!
var disposeBag = Set<AnyCancellable>()
weak var delegate: AutoCompleteViewControllerDelegate?
let chevronView = AutoCompleteTopChevronView()
let containerBackgroundView: UIView = {
@ -26,6 +32,7 @@ final class AutoCompleteViewController: UIViewController {
let tableView: UITableView = {
let tableView = ControlContainableTableView()
tableView.register(AutoCompleteTableViewCell.self, forCellReuseIdentifier: String(describing: AutoCompleteTableViewCell.self))
tableView.register(TimelineBottomLoaderTableViewCell.self, forCellReuseIdentifier: String(describing: TimelineBottomLoaderTableViewCell.self))
tableView.rowHeight = UITableView.automaticDimension
tableView.separatorStyle = .none
tableView.backgroundColor = .clear
@ -96,6 +103,10 @@ extension AutoCompleteViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: indexPath: %s", ((#file as NSString).lastPathComponent), #line, #function, indexPath.debugDescription)
tableView.deselectRow(at: indexPath, animated: true)
guard let diffableDataSource = viewModel.diffableDataSource else { return }
guard let item = diffableDataSource.itemIdentifier(for: indexPath) else { return }
delegate?.autoCompleteViewController(self, didSelectItem: item)
}
func tableView(_ tableView: UITableView, didHighlightRowAt indexPath: IndexPath) {

View File

@ -99,9 +99,9 @@ extension AutoCompleteViewModel.State {
let searchPattern = ArraySlice(String(searchText.dropFirst()))
let passthroughs = emojiTrie.passthrough(searchPattern)
let matchingEmojis = passthroughs
.map { $0.values } // [Set<Emoji>]
.map { $0.values } // [Set<Emoji>]
.map { set in set.compactMap { $0 as? Mastodon.Entity.Emoji } } // [[Emoji]]
.flatMap { $0 } // [Emoji]
.flatMap { $0 } // [Emoji]
let items: [AutoCompleteItem] = matchingEmojis.map { emoji in
AutoCompleteItem.emoji(emoji: emoji)
}

View File

@ -98,6 +98,7 @@ final class ComposeViewController: UIViewController, NeedsDependency {
private(set) lazy var autoCompleteViewController: AutoCompleteViewController = {
let viewController = AutoCompleteViewController()
viewController.viewModel = AutoCompleteViewModel(context: context)
viewController.delegate = self
viewModel.customEmojiViewModel
.assign(to: \.value, on: viewController.viewModel.customEmojiViewModel)
.store(in: &disposeBag)
@ -1221,3 +1222,38 @@ extension ComposeViewController: ComposeStatusPollExpiresOptionCollectionViewCel
viewModel.pollExpiresOptionAttribute.expiresOption.value = expiresOption
}
}
// MARK: - AutoCompleteViewControllerDelegate
extension ComposeViewController: AutoCompleteViewControllerDelegate {
func autoCompleteViewController(_ viewController: AutoCompleteViewController, didSelectItem item: AutoCompleteItem) {
guard let info = viewModel.autoCompleteInfo.value else { return }
let _replacedText: String? = {
var text: String
switch item {
case .hashtag(let hashtag):
text = "#" + hashtag.name
case .hashtagV1(let hashtagName):
text = "#" + hashtagName
case .account(let account):
text = "@" + account.acct
case .emoji(let emoji):
text = ":" + emoji.shortcode + ":"
case .bottomLoader:
return nil
}
text.append(" ")
return text
}()
guard let replacedText = _replacedText else { return }
guard let textEditorView = textEditorView() else { return }
let text = textEditorView.text
do {
try textEditorView.updateByReplacing(range: NSRange(info.toHighlightEndRange, in: text), with: replacedText)
viewModel.autoCompleteInfo.value = nil
} catch {
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: auto complete fail %s", ((#file as NSString).lastPathComponent), #line, #function, error.localizedDescription)
}
}
}