Immediately search for events and profiles
Instead of having to click twice Changelog-Changed: Immediately search for events and profiles
This commit is contained in:
@@ -171,7 +171,8 @@
|
||||
4CC7AAF8297F1CEE00430951 /* EventProfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CC7AAF7297F1CEE00430951 /* EventProfile.swift */; };
|
||||
4CC7AAFA297F64AC00430951 /* EventMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CC7AAF9297F64AC00430951 /* EventMenu.swift */; };
|
||||
4CCEB7A929B29DD50078AA28 /* SearchResultsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CCEB7A829B29DD50078AA28 /* SearchResultsModel.swift */; };
|
||||
4CCEB7AB29B2A1320078AA28 /* SearchedEventView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CCEB7AA29B2A1320078AA28 /* SearchedEventView.swift */; };
|
||||
4CCEB7AE29B53D260078AA28 /* SearchingEventView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CCEB7AD29B53D260078AA28 /* SearchingEventView.swift */; };
|
||||
4CCEB7B029B5415A0078AA28 /* SearchingProfileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CCEB7AF29B5415A0078AA28 /* SearchingProfileView.swift */; };
|
||||
4CD7641B28A1641400B6928F /* EndBlock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CD7641A28A1641400B6928F /* EndBlock.swift */; };
|
||||
4CE0E2AF29A2E82100DB4CA2 /* EventHolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CE0E2AE29A2E82100DB4CA2 /* EventHolder.swift */; };
|
||||
4CE0E2B229A3DF6900DB4CA2 /* LoadMoreButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CE0E2B129A3DF6900DB4CA2 /* LoadMoreButton.swift */; };
|
||||
@@ -513,7 +514,8 @@
|
||||
4CC7AAF7297F1CEE00430951 /* EventProfile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventProfile.swift; sourceTree = "<group>"; };
|
||||
4CC7AAF9297F64AC00430951 /* EventMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventMenu.swift; sourceTree = "<group>"; };
|
||||
4CCEB7A829B29DD50078AA28 /* SearchResultsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchResultsModel.swift; sourceTree = "<group>"; };
|
||||
4CCEB7AA29B2A1320078AA28 /* SearchedEventView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SearchedEventView.swift; path = ../../Models/SearchedEventView.swift; sourceTree = "<group>"; };
|
||||
4CCEB7AD29B53D260078AA28 /* SearchingEventView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchingEventView.swift; sourceTree = "<group>"; };
|
||||
4CCEB7AF29B5415A0078AA28 /* SearchingProfileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchingProfileView.swift; sourceTree = "<group>"; };
|
||||
4CD7641A28A1641400B6928F /* EndBlock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EndBlock.swift; sourceTree = "<group>"; };
|
||||
4CE0E2AE29A2E82100DB4CA2 /* EventHolder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventHolder.swift; sourceTree = "<group>"; };
|
||||
4CE0E2B129A3DF6900DB4CA2 /* LoadMoreButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadMoreButton.swift; sourceTree = "<group>"; };
|
||||
@@ -761,6 +763,7 @@
|
||||
4C75EFA227FA576C0006080F /* Views */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4CCEB7AC29B53D180078AA28 /* Search */,
|
||||
4C30AC7029A5676F00E2BD5A /* Notifications */,
|
||||
4CE0E2B029A3DF4700DB4CA2 /* Timeline */,
|
||||
4CE879562996C44A00F758CC /* Zaps */,
|
||||
@@ -930,7 +933,6 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4CC7AAEF297F11C700430951 /* SelectedEventView.swift */,
|
||||
4CCEB7AA29B2A1320078AA28 /* SearchedEventView.swift */,
|
||||
4CC7AAF1297F129C00430951 /* EmbeddedEventView.swift */,
|
||||
4CC7AAF3297F18B400430951 /* ReplyDescription.swift */,
|
||||
4CC7AAF5297F1A6A00430951 /* EventBody.swift */,
|
||||
@@ -952,6 +954,15 @@
|
||||
path = Search;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4CCEB7AC29B53D180078AA28 /* Search */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4CCEB7AD29B53D260078AA28 /* SearchingEventView.swift */,
|
||||
4CCEB7AF29B5415A0078AA28 /* SearchingProfileView.swift */,
|
||||
);
|
||||
path = Search;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4CE0E2B029A3DF4700DB4CA2 /* Timeline */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -1388,6 +1399,7 @@
|
||||
4CE8794829941DA700F758CC /* RelayFilters.swift in Sources */,
|
||||
4CEE2B02280B39E800AB5EEF /* EventActionBar.swift in Sources */,
|
||||
4C3BEFE0281DE1ED00B3DE84 /* DamusState.swift in Sources */,
|
||||
4CCEB7AE29B53D260078AA28 /* SearchingEventView.swift in Sources */,
|
||||
4CF0ABE929844AF100D66079 /* AnyCodable.swift in Sources */,
|
||||
4C0A3F8F280F640A000448DE /* ThreadModel.swift in Sources */,
|
||||
4CC7AAF2297F129C00430951 /* EmbeddedEventView.swift in Sources */,
|
||||
@@ -1396,6 +1408,7 @@
|
||||
4C3BEFD22819DB9B00B3DE84 /* ProfileModel.swift in Sources */,
|
||||
4C0A3F93280F66F5000448DE /* ReplyMap.swift in Sources */,
|
||||
7C95CAEE299DCEF1009DCB67 /* KFOptionSetter+.swift in Sources */,
|
||||
4CCEB7B029B5415A0078AA28 /* SearchingProfileView.swift in Sources */,
|
||||
BAB68BED29543FA3007BA466 /* SelectWalletView.swift in Sources */,
|
||||
3169CAE6294E69C000EE4006 /* EmptyTimelineView.swift in Sources */,
|
||||
4CC7AAF0297F11C700430951 /* SelectedEventView.swift in Sources */,
|
||||
@@ -1408,7 +1421,6 @@
|
||||
4C3A1D3729637E0500558C0F /* PreviewCache.swift in Sources */,
|
||||
4C3EA67528FF7A5A00C48A62 /* take.c in Sources */,
|
||||
4C3AC7A12835A81400E1F516 /* SetupView.swift in Sources */,
|
||||
4CCEB7AB29B2A1320078AA28 /* SearchedEventView.swift in Sources */,
|
||||
4C06670128FC7C5900038D2A /* RelayView.swift in Sources */,
|
||||
4C285C8C28398BC7008A31F1 /* Keys.swift in Sources */,
|
||||
4CACA9DC280C38C000D9BBE8 /* Profiles.swift in Sources */,
|
||||
|
||||
@@ -147,7 +147,7 @@ struct ContentView: View {
|
||||
search_open = false
|
||||
isSideBarOpened = false
|
||||
}
|
||||
|
||||
|
||||
var timelineNavItem: Text {
|
||||
switch selected_timeline {
|
||||
case .home:
|
||||
@@ -199,7 +199,7 @@ struct ContentView: View {
|
||||
EmptyView()
|
||||
}
|
||||
}
|
||||
.navigationBarTitle(timelineNavItem, displayMode: .inline)
|
||||
.navigationBarTitle(timeline_name(selected_timeline), displayMode: .inline)
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .principal) {
|
||||
VStack {
|
||||
@@ -348,7 +348,7 @@ struct ContentView: View {
|
||||
active_profile = ref.ref_id
|
||||
profile_open = true
|
||||
} else if ref.key == "e" {
|
||||
find_event(state: damus_state!, evid: ref.ref_id, find_from: nil) { ev in
|
||||
find_event(state: damus_state!, evid: ref.ref_id, search_type: .event, find_from: nil) { ev in
|
||||
if let ev {
|
||||
active_event = ev
|
||||
}
|
||||
@@ -767,7 +767,7 @@ func setup_notifications() {
|
||||
}
|
||||
|
||||
|
||||
func find_event(state: DamusState, evid: String, find_from: [String]?, callback: @escaping (NostrEvent?) -> ()) {
|
||||
func find_event(state: DamusState, evid: String, search_type: SearchType, find_from: [String]?, callback: @escaping (NostrEvent?) -> ()) {
|
||||
if let ev = state.events.lookup(evid) {
|
||||
callback(ev)
|
||||
return
|
||||
@@ -776,7 +776,13 @@ func find_event(state: DamusState, evid: String, find_from: [String]?, callback:
|
||||
let subid = UUID().description
|
||||
|
||||
var has_event = false
|
||||
var filter = NostrFilter.filter_ids([ evid ])
|
||||
|
||||
var filter = search_type == .event ? NostrFilter.filter_ids([ evid ]) : NostrFilter.filter_authors([ evid ])
|
||||
|
||||
if search_type == .profile {
|
||||
filter.kinds = [0]
|
||||
}
|
||||
|
||||
filter.limit = 1
|
||||
var attempts = 0
|
||||
|
||||
@@ -808,3 +814,20 @@ func find_event(state: DamusState, evid: String, find_from: [String]?, callback:
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func timeline_name(_ timeline: Timeline?) -> String {
|
||||
guard let timeline else {
|
||||
return ""
|
||||
}
|
||||
switch timeline {
|
||||
case .home:
|
||||
return "Home"
|
||||
case .notifications:
|
||||
return "Notifications"
|
||||
case .search:
|
||||
return "Universe 🛸"
|
||||
case .dms:
|
||||
return "DMs"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
//
|
||||
// SearchedEventView.swift
|
||||
// damus
|
||||
//
|
||||
// Created by William Casarin on 2023-03-03.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
enum EventSearchState {
|
||||
case searching
|
||||
case not_found
|
||||
case found(NostrEvent)
|
||||
}
|
||||
|
||||
struct SearchedEventView: View {
|
||||
let state: DamusState
|
||||
let event_id: String
|
||||
@State var search_state: EventSearchState = .searching
|
||||
|
||||
var body: some View {
|
||||
Group {
|
||||
switch search_state {
|
||||
case .not_found:
|
||||
Text("Event could not be found")
|
||||
case .searching:
|
||||
Text("Searching...")
|
||||
case .found(let ev):
|
||||
let thread = ThreadModel(event: ev, damus_state: state)
|
||||
let dest = ThreadView(state: state, thread: thread)
|
||||
NavigationLink(destination: dest) {
|
||||
EventView(damus: state, event: ev)
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
}
|
||||
}
|
||||
.onAppear {
|
||||
find_event(state: state, evid: event_id, find_from: nil) { ev in
|
||||
if let ev {
|
||||
self.search_state = .found(ev)
|
||||
} else {
|
||||
self.search_state = .not_found
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct SearchedEventView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
SearchedEventView(state: test_damus_state(), event_id: "event_id")
|
||||
}
|
||||
}
|
||||
112
damus/Views/Search/SearchingEventView.swift
Normal file
112
damus/Views/Search/SearchingEventView.swift
Normal file
@@ -0,0 +1,112 @@
|
||||
//
|
||||
// SearchingEventView.swift
|
||||
// damus
|
||||
//
|
||||
// Created by William Casarin on 2023-03-05.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
enum SearchState {
|
||||
case searching
|
||||
case found(NostrEvent)
|
||||
case found_profile(String)
|
||||
case not_found
|
||||
}
|
||||
|
||||
enum SearchType {
|
||||
case event
|
||||
case profile
|
||||
}
|
||||
|
||||
struct SearchingEventView: View {
|
||||
let state: DamusState
|
||||
let evid: String
|
||||
let search_type: SearchType
|
||||
@State var search_state: SearchState = .searching
|
||||
|
||||
var bech32_evid: String {
|
||||
guard let bytes = hex_decode(evid) else {
|
||||
return evid
|
||||
}
|
||||
let noteid = bech32_encode(hrp: "note", bytes)
|
||||
return abbrev_pubkey(noteid)
|
||||
}
|
||||
|
||||
var search_name: String {
|
||||
switch search_type {
|
||||
case .profile:
|
||||
return "profile"
|
||||
case .event:
|
||||
return "note"
|
||||
}
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
Group {
|
||||
switch search_state {
|
||||
case .searching:
|
||||
HStack(spacing: 10) {
|
||||
Text("Looking for \(search_name)...", comment: "Label that appears when searching for note or profile")
|
||||
ProgressView()
|
||||
.progressViewStyle(.circular)
|
||||
}
|
||||
case .found(let ev):
|
||||
NavigationLink(destination: ThreadView(state: state, thread: ThreadModel(event: ev, damus_state: state))) {
|
||||
|
||||
EventView(damus: state, event: ev)
|
||||
}
|
||||
.buttonStyle(PlainButtonStyle())
|
||||
case .found_profile(let pk):
|
||||
NavigationLink(destination: ProfileView(damus_state: state, pubkey: pk)) {
|
||||
|
||||
FollowUserView(target: .pubkey(pk), damus_state: state)
|
||||
}
|
||||
.buttonStyle(PlainButtonStyle())
|
||||
case .not_found:
|
||||
Text("\(search_name.capitalized) not found", comment: "When a note or profile is not found when searching for it via its note id")
|
||||
}
|
||||
}
|
||||
.onAppear {
|
||||
|
||||
switch search_type {
|
||||
case .event:
|
||||
if let ev = state.events.lookup(evid) {
|
||||
self.search_state = .found(ev)
|
||||
return
|
||||
}
|
||||
case .profile:
|
||||
if state.profiles.lookup(id: evid) != nil {
|
||||
self.search_state = .found_profile(evid)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
find_event(state: state, evid: evid, search_type: search_type, find_from: nil) { ev in
|
||||
|
||||
if let ev {
|
||||
self.search_state = .found(ev)
|
||||
} else {
|
||||
self.search_state = .not_found
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct SearchingEventView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
let state = test_damus_state()
|
||||
SearchingEventView(state: state, evid: test_event.id, search_type: .event)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
enum EventSearchState {
|
||||
case searching
|
||||
case not_found
|
||||
case found(NostrEvent)
|
||||
case found_profile(String)
|
||||
}
|
||||
|
||||
20
damus/Views/Search/SearchingProfileView.swift
Normal file
20
damus/Views/Search/SearchingProfileView.swift
Normal file
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// SearchingProfileView.swift
|
||||
// damus
|
||||
//
|
||||
// Created by William Casarin on 2023-03-05.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct SearchingProfileView: View {
|
||||
var body: some View {
|
||||
Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
|
||||
}
|
||||
}
|
||||
|
||||
struct SearchingProfileView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
SearchingProfileView()
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ enum Search {
|
||||
struct SearchResultsView: View {
|
||||
let damus_state: DamusState
|
||||
@Binding var search: String
|
||||
|
||||
@State var result: Search? = nil
|
||||
|
||||
func ProfileSearchResult(pk: String, res: Profile) -> some View {
|
||||
@@ -43,36 +44,23 @@ struct SearchResultsView: View {
|
||||
case .profile(let prof):
|
||||
let decoded = try? bech32_decode(prof)
|
||||
let hex = hex_encode(decoded!.data)
|
||||
let prof_view = ProfileView(damus_state: damus_state, pubkey: hex)
|
||||
NavigationLink(destination: prof_view) {
|
||||
Text("Goto profile \(prof)", comment: "Navigation link to go to profile.")
|
||||
}
|
||||
case .hex(let h):
|
||||
let prof_view = ProfileView(damus_state: damus_state, pubkey: h)
|
||||
//let ev_view = ThreadView(damus: damus_state, event_id: h)
|
||||
|
||||
NavigationLink(destination: prof_view) {
|
||||
Text("Goto profile \(h)", comment: "Navigation link to go to profile referenced by hex code.")
|
||||
SearchingEventView(state: damus_state, evid: hex, search_type: .profile)
|
||||
case .hex(let h):
|
||||
//let prof_view = ProfileView(damus_state: damus_state, pubkey: h)
|
||||
//let ev_view = ThreadView(damus: damus_state, event_id: h)
|
||||
|
||||
VStack(spacing: 10) {
|
||||
SearchingEventView(state: damus_state, evid: h, search_type: .event)
|
||||
|
||||
SearchingEventView(state: damus_state, evid: h, search_type: .profile)
|
||||
}
|
||||
/*
|
||||
VStack(spacing: 50) {
|
||||
NavigationLink(destination: ev_view) {
|
||||
Text("Goto post \(h)", comment: "Navigation link to go to post referenced by hex code.")
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
case .note(let nid):
|
||||
/*
|
||||
let decoded = try? bech32_decode(nid)
|
||||
let hex = hex_encode(decoded!.data)
|
||||
let ev_view = ThreadView(state: state, ev: ev)
|
||||
*/
|
||||
Text("Todo: fix this")
|
||||
/*
|
||||
NavigationLink(destination: ev_view) {
|
||||
Text("Goto post \(nid)", comment: "Navigation link to go to post referenced by note ID.")
|
||||
}
|
||||
*/
|
||||
|
||||
SearchingEventView(state: damus_state, evid: hex, search_type: .event)
|
||||
case .none:
|
||||
Text("none", comment: "No search results.")
|
||||
}
|
||||
@@ -81,66 +69,14 @@ struct SearchResultsView: View {
|
||||
}
|
||||
}
|
||||
|
||||
func search_changed(_ new: String) {
|
||||
guard new.count != 0 else {
|
||||
return
|
||||
}
|
||||
|
||||
if new.first! == "#" {
|
||||
let ht = String(new.dropFirst())
|
||||
self.result = .hashtag(ht)
|
||||
return
|
||||
}
|
||||
|
||||
if hex_decode(new) != nil, new.count == 64 {
|
||||
self.result = .hex(new)
|
||||
return
|
||||
}
|
||||
|
||||
if new.starts(with: "npub") {
|
||||
if (try? bech32_decode(new)) != nil {
|
||||
self.result = .profile(new)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if new.starts(with: "note") {
|
||||
if (try? bech32_decode(new)) != nil {
|
||||
self.result = .note(new)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
let profs = damus_state.profiles.profiles.enumerated()
|
||||
let results: [(String, Profile)] = profs.reduce(into: []) { acc, els in
|
||||
let pk = els.element.key
|
||||
let prof = els.element.value.profile
|
||||
let lowname = prof.name.map { $0.lowercased() }
|
||||
let lownip05 = damus_state.profiles.is_validated(pk).map { $0.host.lowercased() }
|
||||
let lowdisp = prof.display_name.map { $0.lowercased() }
|
||||
let ok = new.count == 1 ?
|
||||
((lowname?.starts(with: new) ?? false) ||
|
||||
(lownip05?.starts(with: new) ?? false) ||
|
||||
(lowdisp?.starts(with: new) ?? false)) : (pk.starts(with: new) || String(new.dropFirst()) == pk
|
||||
|| lowname?.contains(new) ?? false
|
||||
|| lownip05?.contains(new) ?? false
|
||||
|| lowdisp?.contains(new) ?? false)
|
||||
if ok {
|
||||
acc.append((pk, prof))
|
||||
}
|
||||
}
|
||||
|
||||
self.result = .profiles(results)
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
MainContent
|
||||
.frame(maxHeight: .infinity)
|
||||
.onAppear {
|
||||
search_changed(search)
|
||||
self.result = search_changed(profiles: damus_state.profiles, search)
|
||||
}
|
||||
.onChange(of: search) { new in
|
||||
search_changed(new)
|
||||
self.result = search_changed(profiles: damus_state.profiles, new)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -152,3 +88,52 @@ struct SearchResultsView_Previews: PreviewProvider {
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
func search_changed(profiles: Profiles, _ new: String) -> Search? {
|
||||
guard new.count != 0 else {
|
||||
return nil
|
||||
}
|
||||
|
||||
if new.first! == "#" {
|
||||
let ht = String(new.dropFirst())
|
||||
return .hashtag(ht)
|
||||
}
|
||||
|
||||
if hex_decode(new) != nil, new.count == 64 {
|
||||
return .hex(new)
|
||||
}
|
||||
|
||||
if new.starts(with: "npub") {
|
||||
if (try? bech32_decode(new)) != nil {
|
||||
return .profile(new)
|
||||
}
|
||||
}
|
||||
|
||||
if new.starts(with: "note") {
|
||||
if (try? bech32_decode(new)) != nil {
|
||||
return .note(new)
|
||||
}
|
||||
}
|
||||
|
||||
let profs = profiles.profiles.enumerated()
|
||||
let results: [(String, Profile)] = profs.reduce(into: []) { acc, els in
|
||||
let pk = els.element.key
|
||||
let prof = els.element.value.profile
|
||||
let lowname = prof.name.map { $0.lowercased() }
|
||||
let lownip05 = profiles.is_validated(pk).map { $0.host.lowercased() }
|
||||
let lowdisp = prof.display_name.map { $0.lowercased() }
|
||||
let ok = new.count == 1 ?
|
||||
((lowname?.starts(with: new) ?? false) ||
|
||||
(lownip05?.starts(with: new) ?? false) ||
|
||||
(lowdisp?.starts(with: new) ?? false)) : (pk.starts(with: new) || String(new.dropFirst()) == pk
|
||||
|| lowname?.contains(new) ?? false
|
||||
|| lownip05?.contains(new) ?? false
|
||||
|| lowdisp?.contains(new) ?? false)
|
||||
if ok {
|
||||
acc.append((pk, prof))
|
||||
}
|
||||
}
|
||||
|
||||
return .profiles(results)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user