Use AnyAccount instead of EitherAccount for compose autocomplete

This commit is contained in:
Shadowfacts 2022-09-15 21:05:18 -04:00
parent 8f8d50efbd
commit 80c4fcce82
2 changed files with 21 additions and 55 deletions

View File

@ -48,7 +48,7 @@ struct ComposeAutocompleteMentionsView: View {
@ObservedObject private var preferences = Preferences.shared
// can't use AccountProtocol because of associated type requirements
@State private var accounts: [EitherAccount] = []
@State private var accounts: [AnyAccount] = []
@State private var searchRequest: URLSessionTask?
@ -56,26 +56,20 @@ struct ComposeAutocompleteMentionsView: View {
ScrollView(.horizontal) {
// can't use LazyHStack because changing the contents of the ForEach causes the ScrollView to hang
HStack(spacing: 8) {
ForEach(accounts, id: \.id) { (account) in
ForEach(accounts, id: \.value.id) { (account) in
Button {
uiState.currentInput?.autocomplete(with: "@\(account.acct)")
uiState.currentInput?.autocomplete(with: "@\(account.value.acct)")
} label: {
HStack(spacing: 4) {
ComposeAvatarImageView(url: account.avatar)
ComposeAvatarImageView(url: account.value.avatar)
.frame(width: 30, height: 30)
.cornerRadius(preferences.avatarStyle.cornerRadiusFraction * 30)
VStack(alignment: .leading) {
switch account {
case let .pachyderm(underlying):
AccountDisplayNameLabel(account: underlying, fontSize: 14)
.foregroundColor(Color(UIColor.label))
case let .coreData(underlying):
AccountDisplayNameLabel(account: underlying, fontSize: 14)
.foregroundColor(Color(UIColor.label))
}
AccountDisplayNameLabel(account: account.value, fontSize: 14)
.foregroundColor(Color(UIColor.label))
Text(verbatim: "@\(account.acct)")
Text(verbatim: "@\(account.value.acct)")
.font(.system(size: 12))
.foregroundColor(Color(UIColor.label))
}
@ -110,7 +104,7 @@ struct ComposeAutocompleteMentionsView: View {
request.predicate = NSPredicate(format: "displayName LIKE %@ OR acct LIKE %@", wildcardedQuery, wildcardedQuery)
if let results = try? mastodonController.persistentContainer.viewContext.fetch(request) {
loadAccounts(results.map { .coreData($0) }, query: query)
loadAccounts(results.map { .init(value: $0) }, query: query)
}
}
@ -131,27 +125,27 @@ struct ComposeAutocompleteMentionsView: View {
DispatchQueue.main.async {
// if the query has changed, don't bother loading the now-outdated results
if case .mention(query) = uiState.autocompleteState {
self.loadAccounts(accounts.map { .pachyderm($0) }, query: query)
self.loadAccounts(accounts.map { .init(value: $0) }, query: query)
}
}
}
}
private func loadAccounts(_ accounts: [EitherAccount], query: String) {
private func loadAccounts(_ accounts: [AnyAccount], query: String) {
// when sorting account suggestions, ignore the domain component of the acct unless the user is typing it themself
let ignoreDomain = !query.contains("@")
self.accounts =
accounts.map { (account: EitherAccount) -> (EitherAccount, (matched: Bool, score: Int)) in
let fuzzyStr = ignoreDomain ? String(account.acct.split(separator: "@").first!) : account.acct
accounts.map { (account) -> (AnyAccount, (matched: Bool, score: Int)) in
let fuzzyStr = ignoreDomain ? String(account.value.acct.split(separator: "@").first!) : account.value.acct
let res = (account, FuzzyMatcher.match(pattern: query, str: fuzzyStr))
return res
}
.filter(\.1.matched)
.map { (account, res) -> (EitherAccount, Int) in
.map { (account, res) -> (AnyAccount, Int) in
// give higher weight to accounts that the user follows or is followed by
var score = res.score
if let relationship = mastodonController.persistentContainer.relationship(forAccount: account.id) {
if let relationship = mastodonController.persistentContainer.relationship(forAccount: account.value.id) {
if relationship.following {
score += 3
}
@ -165,39 +159,11 @@ struct ComposeAutocompleteMentionsView: View {
.map(\.0)
}
private enum EitherAccount: Equatable {
case pachyderm(Account)
case coreData(AccountMO)
private struct AnyAccount: Equatable {
let value: any AccountProtocol
var id: String {
switch self {
case let .pachyderm(account):
return account.id
case let .coreData(account):
return account.id
}
}
var acct: String {
switch self {
case let .pachyderm(account):
return account.acct
case let .coreData(account):
return account.acct
}
}
var avatar: URL? {
switch self {
case let .pachyderm(account):
return account.avatar
case let .coreData(account):
return account.avatar
}
}
static func ==(lhs: EitherAccount, rhs: EitherAccount) -> Bool {
return lhs.id == rhs.id
static func ==(lhs: AnyAccount, rhs: AnyAccount) -> Bool {
return lhs.value.id == rhs.value.id
}
}
}

View File

@ -12,13 +12,13 @@ import WebURLFoundationExtras
private let emojiRegex = try! NSRegularExpression(pattern: ":(\\w+):", options: [])
struct AccountDisplayNameLabel<Account: AccountProtocol>: View {
let account: Account
struct AccountDisplayNameLabel: View {
let account: any AccountProtocol
let fontSize: Int
@State var text: Text
@State var emojiRequests = [ImageCache.Request]()
init(account: Account, fontSize: Int) {
init(account: any AccountProtocol, fontSize: Int) {
self.account = account
self.fontSize = fontSize
let name = account.displayName.isEmpty ? account.username : account.displayName