Search results are now displayed
This commit is contained in:
parent
015b60b8f1
commit
a5021e9fc9
@ -52,6 +52,7 @@
|
||||
B9D9C6C32B6A576C00C26A41 /* NotificationsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9D9C6C22B6A576C00C26A41 /* NotificationsView.swift */; };
|
||||
B9D9C6C52B6A587700C26A41 /* NotificationRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9D9C6C42B6A587700C26A41 /* NotificationRow.swift */; };
|
||||
B9D9C6C72B6A590F00C26A41 /* ProfilePicture.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9D9C6C62B6A590F00C26A41 /* ProfilePicture.swift */; };
|
||||
B9DC69292B78D9A500E625B9 /* SearchResultView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9DC69282B78D9A500E625B9 /* SearchResultView.swift */; };
|
||||
B9EBE8562B47256900FB594D /* PostAttachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9EBE8552B47256900FB594D /* PostAttachment.swift */; };
|
||||
B9EBE8582B474FD600FB594D /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9EBE8572B474FD600FB594D /* AppDelegate.swift */; };
|
||||
B9F8FA162B5D3AC30044DAB4 /* SafariView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9F8FA152B5D3AC30044DAB4 /* SafariView.swift */; };
|
||||
@ -151,6 +152,7 @@
|
||||
B9D9C6C22B6A576C00C26A41 /* NotificationsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsView.swift; sourceTree = "<group>"; };
|
||||
B9D9C6C42B6A587700C26A41 /* NotificationRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationRow.swift; sourceTree = "<group>"; };
|
||||
B9D9C6C62B6A590F00C26A41 /* ProfilePicture.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfilePicture.swift; sourceTree = "<group>"; };
|
||||
B9DC69282B78D9A500E625B9 /* SearchResultView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchResultView.swift; sourceTree = "<group>"; };
|
||||
B9EBE8552B47256900FB594D /* PostAttachment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostAttachment.swift; sourceTree = "<group>"; };
|
||||
B9EBE8572B474FD600FB594D /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
B9F8FA152B5D3AC30044DAB4 /* SafariView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafariView.swift; sourceTree = "<group>"; };
|
||||
@ -352,6 +354,7 @@
|
||||
B9D9C6C62B6A590F00C26A41 /* ProfilePicture.swift */,
|
||||
B97491E22B6E96700098BC48 /* SymbolWidth.swift */,
|
||||
B915C4412B6F908C00042DDB /* ProfileView.swift */,
|
||||
B9DC69282B78D9A500E625B9 /* SearchResultView.swift */,
|
||||
);
|
||||
path = Components;
|
||||
sourceTree = "<group>";
|
||||
@ -532,6 +535,7 @@
|
||||
B999DE602B76FB3E00509868 /* ContactRow.swift in Sources */,
|
||||
B999DE5C2B76F8CB00509868 /* ContactsView.swift in Sources */,
|
||||
B9842C0E2B2F21B700D9F3C1 /* CompactPostView.swift in Sources */,
|
||||
B9DC69292B78D9A500E625B9 /* SearchResultView.swift in Sources */,
|
||||
B98BC7492B46CEDA00595441 /* AppearenceView.swift in Sources */,
|
||||
B9D9C6C52B6A587700C26A41 /* NotificationRow.swift in Sources */,
|
||||
B9FB94992B2EEB9400D81C07 /* AddInstanceView.swift in Sources */,
|
||||
|
131
Threaded/Components/SearchResultView.swift
Normal file
131
Threaded/Components/SearchResultView.swift
Normal file
@ -0,0 +1,131 @@
|
||||
//Made by Lumaa
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct SearchResultView: View {
|
||||
@EnvironmentObject private var navigator: Navigator
|
||||
@Environment(AccountManager.self) private var accountManager: AccountManager
|
||||
|
||||
var searchResults: SearchResults
|
||||
var query: String
|
||||
|
||||
var body: some View {
|
||||
if !searchResults.isEmpty {
|
||||
VStack(alignment: .leading) {
|
||||
if !searchResults.accounts.isEmpty {
|
||||
Text("discovery.results.users")
|
||||
.multilineTextAlignment(.leading)
|
||||
.font(.title.bold())
|
||||
.padding(.horizontal)
|
||||
|
||||
accountsView
|
||||
}
|
||||
|
||||
if searchResults.statuses.count > 0 {
|
||||
Text("discovery.results.posts")
|
||||
.multilineTextAlignment(.leading)
|
||||
.font(.title.bold())
|
||||
.padding(.horizontal)
|
||||
|
||||
statusesView
|
||||
}
|
||||
|
||||
if searchResults.hashtags.count > 0 {
|
||||
Text("discovery.results.tags")
|
||||
.multilineTextAlignment(.leading)
|
||||
.font(.title.bold())
|
||||
.padding(.horizontal)
|
||||
|
||||
tagsView
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ContentUnavailableView.search(text: query)
|
||||
}
|
||||
}
|
||||
|
||||
var accountsView: some View {
|
||||
ScrollView(.horizontal, showsIndicators: false) {
|
||||
LazyHStack(spacing: 10) {
|
||||
ForEach(searchResults.accounts) { account in
|
||||
VStack {
|
||||
ProfilePicture(url: account.avatar, size: 64)
|
||||
|
||||
Text(account.displayName?.replacing(/:.+:/, with: "") ?? account.username)
|
||||
.font(.subheadline.bold())
|
||||
.foregroundStyle(Color(uiColor: UIColor.label))
|
||||
.lineLimit(1)
|
||||
|
||||
Text("@\(account.username)")
|
||||
.font(.caption)
|
||||
.foregroundStyle(Color.gray)
|
||||
|
||||
Spacer()
|
||||
|
||||
Button {
|
||||
guard let client = accountManager.getClient() else { return }
|
||||
|
||||
Task {
|
||||
do {
|
||||
let better: Account = try await client.get(endpoint: Accounts.accounts(id: account.id))
|
||||
navigator.navigate(to: .account(acc: better))
|
||||
} catch {
|
||||
print(error)
|
||||
}
|
||||
}
|
||||
} label: {
|
||||
Text("account.view")
|
||||
}
|
||||
.buttonStyle(LargeButton(filled: true, height: 7.5))
|
||||
}
|
||||
.padding(.vertical)
|
||||
.frame(width: 200)
|
||||
.background(Color.gray.opacity(0.2))
|
||||
.clipShape(RoundedRectangle(cornerRadius: 15.0))
|
||||
}
|
||||
.scrollTargetLayout()
|
||||
}
|
||||
}
|
||||
.padding(.horizontal)
|
||||
.scrollClipDisabled()
|
||||
.defaultScrollAnchor(.leading)
|
||||
}
|
||||
|
||||
var tagsView: some View {
|
||||
VStack(spacing: 7.5) {
|
||||
ForEach(searchResults.hashtags) { tag in
|
||||
HStack {
|
||||
VStack(alignment: .leading) {
|
||||
Text("#\(tag.name)")
|
||||
.multilineTextAlignment(.leading)
|
||||
.lineLimit(1)
|
||||
.bold()
|
||||
Text("tag.posts-\(tag.totalUses)")
|
||||
.multilineTextAlignment(.leading)
|
||||
.lineLimit(1)
|
||||
.foregroundStyle(Color.gray)
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
||||
Button {
|
||||
// do stuff
|
||||
} label: {
|
||||
Text("tag.read")
|
||||
}
|
||||
.buttonStyle(LargeButton(filled: true, height: 7.5))
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var statusesView: some View {
|
||||
VStack(spacing: 7.5) {
|
||||
ForEach(searchResults.statuses) { status in
|
||||
CompactPostView(status: status)
|
||||
.padding(.vertical)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -125,4 +125,4 @@ public extension Relationship {
|
||||
}
|
||||
}
|
||||
|
||||
extension Relationship: Sendable {}
|
||||
extension Relationship: Sendable, Equatable {}
|
||||
|
@ -19,6 +19,12 @@ public struct SearchResults: Decodable {
|
||||
|
||||
extension SearchResults: Sendable {}
|
||||
|
||||
extension SearchResults: Equatable {
|
||||
public static func == (lhs: SearchResults, rhs: SearchResults) -> Bool {
|
||||
return lhs.statuses == rhs.statuses && lhs.accounts == rhs.accounts && lhs.relationships == rhs.relationships && lhs.hashtags == rhs.hashtags
|
||||
}
|
||||
}
|
||||
|
||||
public enum Search: Endpoint {
|
||||
case search(query: String, type: String?, offset: Int?, following: Bool?)
|
||||
case accountsSearch(query: String, type: String?, offset: Int?, following: Bool?)
|
||||
|
@ -532,6 +532,36 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"discovery.results.posts" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Found posts"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"discovery.results.tags" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Found tags"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"discovery.results.users" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Found users"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"discovery.search.posts" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
@ -564,6 +594,16 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"discovery.search.tags" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Tags"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"discovery.search.users" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
@ -1697,4 +1737,4 @@
|
||||
}
|
||||
},
|
||||
"version" : "1.0"
|
||||
}
|
||||
}
|
||||
|
@ -9,8 +9,9 @@ struct DiscoveryView: View {
|
||||
|
||||
@State private var searchQuery: String = ""
|
||||
@State private var results: [String : SearchResults] = [:]
|
||||
@State private var querying: Bool = false
|
||||
|
||||
let allTokens = [Token(id: "accounts", name: String(localized: "discovery.search.users")), Token(id: "statuses", name: String(localized: "discovery.search.posts")), Token(id: "hashtags", name: String(localized: "discovery.search.tags"))]
|
||||
let allTokens = [Token(id: "accounts", name: String(localized: "discovery.search.users"), image: "person.3.fill"), Token(id: "statuses", name: String(localized: "discovery.search.posts"), image: "note.text"), Token(id: "hashtags", name: String(localized: "discovery.search.tags"), image: "tag.fill")]
|
||||
@State private var currentTokens = [Token]()
|
||||
|
||||
@State private var suggestedAccounts: [Account] = []
|
||||
@ -19,11 +20,23 @@ struct DiscoveryView: View {
|
||||
@State private var trendingStatuses: [Status] = []
|
||||
@State private var trendingLinks: [Card] = []
|
||||
|
||||
// TODO: "Read" button + search with scopes
|
||||
// TODO: "Read" button
|
||||
|
||||
var body: some View {
|
||||
NavigationStack(path: $navigator.path) {
|
||||
ScrollView {
|
||||
if results != [:] && !querying {
|
||||
SearchResultView(searchResults: results[searchQuery] ?? .init(accounts: [], statuses: [], hashtags: []), query: searchQuery)
|
||||
.environmentObject(navigator)
|
||||
|
||||
Spacer()
|
||||
.foregroundStyle(Color.white)
|
||||
.padding()
|
||||
} else if querying {
|
||||
ProgressView()
|
||||
.progressViewStyle(.circular)
|
||||
}
|
||||
|
||||
VStack(alignment: .leading) {
|
||||
Text("discovery.suggested.users")
|
||||
.multilineTextAlignment(.leading)
|
||||
@ -41,20 +54,24 @@ struct DiscoveryView: View {
|
||||
}
|
||||
}
|
||||
.submitLabel(.search)
|
||||
.onSubmit {
|
||||
Task {
|
||||
.task(id: searchQuery) {
|
||||
if !searchQuery.isEmpty {
|
||||
querying = true
|
||||
await search()
|
||||
querying = false
|
||||
} else {
|
||||
querying = false
|
||||
results = [:]
|
||||
}
|
||||
}
|
||||
.onChange(of: currentTokens) { old, new in
|
||||
guard new.count > 1 else { return }
|
||||
let oldToken = old.first ?? allTokens[0]
|
||||
let newToken = new.last ?? allTokens[1]
|
||||
|
||||
currentTokens.removeAll(where: { $0 == oldToken })
|
||||
currentTokens = [newToken]
|
||||
}
|
||||
.searchable(text: $searchQuery, tokens: $currentTokens, suggestedTokens: .constant(allTokens), prompt: Text("discovery.search.prompt")) { token in
|
||||
Text(token.name)
|
||||
Label(token.name, systemImage: token.image)
|
||||
}
|
||||
.withAppRouter(navigator)
|
||||
.navigationTitle(Text("discovery"))
|
||||
@ -146,7 +163,7 @@ struct DiscoveryView: View {
|
||||
guard let client = accountManager.getClient(), !searchQuery.isEmpty else { return }
|
||||
do {
|
||||
try await Task.sleep(for: .milliseconds(250))
|
||||
var results: SearchResults = try await client.get(endpoint: Search.search(query: searchQuery, type: nil, offset: nil, following: nil), forceVersion: .v2)
|
||||
var results: SearchResults = try await client.get(endpoint: Search.search(query: searchQuery, type: currentTokens.first?.id, offset: nil, following: nil), forceVersion: .v2)
|
||||
// let relationships: [Relationship] = try await client.get(endpoint: Accounts.relationships(ids: results.accounts.map(\.id)))
|
||||
// results.relationships = relationships
|
||||
withAnimation {
|
||||
@ -190,5 +207,6 @@ struct DiscoveryView: View {
|
||||
struct Token: Identifiable, Equatable {
|
||||
var id: String
|
||||
var name: String
|
||||
var image: String
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user