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