forked from zelo72/mastodon-ios
feat: add auto complete replace input action
This commit is contained in:
parent
3927f1630a
commit
672bfab200
|
@ -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))
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue