mirror of
https://github.com/Dimillian/IceCubesApp.git
synced 2025-01-24 06:48:10 +00:00
Less chatty api calling (#79)
* Limit API calls for instance searching * Limit api calls * Fix empty/initial state * Limit API calls * Delegate empty view logic to viewmodel * When you boosted, display You boosted
This commit is contained in:
parent
a49175fe69
commit
75e9516089
5 changed files with 48 additions and 20 deletions
|
@ -6,6 +6,7 @@ import DesignSystem
|
||||||
import NukeUI
|
import NukeUI
|
||||||
import Shimmer
|
import Shimmer
|
||||||
import AppAccount
|
import AppAccount
|
||||||
|
import Combine
|
||||||
|
|
||||||
struct AddAccountView: View {
|
struct AddAccountView: View {
|
||||||
@Environment(\.dismiss) private var dismiss
|
@Environment(\.dismiss) private var dismiss
|
||||||
|
@ -23,6 +24,8 @@ struct AddAccountView: View {
|
||||||
@State private var signInClient: Client?
|
@State private var signInClient: Client?
|
||||||
@State private var instances: [InstanceSocial] = []
|
@State private var instances: [InstanceSocial] = []
|
||||||
@State private var instanceFetchError: String?
|
@State private var instanceFetchError: String?
|
||||||
|
|
||||||
|
private let instanceNamePublisher = PassthroughSubject<String, Never>()
|
||||||
|
|
||||||
@FocusState private var isInstanceURLFieldFocused: Bool
|
@FocusState private var isInstanceURLFieldFocused: Bool
|
||||||
|
|
||||||
|
@ -68,6 +71,9 @@ struct AddAccountView: View {
|
||||||
isSigninIn = false
|
isSigninIn = false
|
||||||
}
|
}
|
||||||
.onChange(of: instanceName) { newValue in
|
.onChange(of: instanceName) { newValue in
|
||||||
|
instanceNamePublisher.send(newValue)
|
||||||
|
}
|
||||||
|
.onReceive(instanceNamePublisher.debounce(for: .milliseconds(500), scheduler: DispatchQueue.main)) { newValue in
|
||||||
let client = Client(server: newValue)
|
let client = Client(server: newValue)
|
||||||
Task {
|
Task {
|
||||||
do {
|
do {
|
||||||
|
|
|
@ -5,6 +5,7 @@ import Env
|
||||||
import DesignSystem
|
import DesignSystem
|
||||||
import NukeUI
|
import NukeUI
|
||||||
import Shimmer
|
import Shimmer
|
||||||
|
import Combine
|
||||||
|
|
||||||
struct AddRemoteTimelineView: View {
|
struct AddRemoteTimelineView: View {
|
||||||
@Environment(\.dismiss) private var dismiss
|
@Environment(\.dismiss) private var dismiss
|
||||||
|
@ -15,6 +16,8 @@ struct AddRemoteTimelineView: View {
|
||||||
@State private var instanceName: String = ""
|
@State private var instanceName: String = ""
|
||||||
@State private var instance: Instance?
|
@State private var instance: Instance?
|
||||||
@State private var instances: [InstanceSocial] = []
|
@State private var instances: [InstanceSocial] = []
|
||||||
|
|
||||||
|
private let instanceNamePublisher = PassthroughSubject<String, Never>()
|
||||||
|
|
||||||
@FocusState private var isInstanceURLFieldFocused: Bool
|
@FocusState private var isInstanceURLFieldFocused: Bool
|
||||||
|
|
||||||
|
@ -55,12 +58,15 @@ struct AddRemoteTimelineView: View {
|
||||||
Button("Cancel", action: { dismiss() })
|
Button("Cancel", action: { dismiss() })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onChange(of: instanceName, perform: { newValue in
|
.onChange(of: instanceName) { newValue in
|
||||||
|
instanceNamePublisher.send(newValue)
|
||||||
|
}
|
||||||
|
.onReceive(instanceNamePublisher.debounce(for: .milliseconds(500), scheduler: DispatchQueue.main)) { newValue in
|
||||||
Task {
|
Task {
|
||||||
let client = Client(server: newValue)
|
let client = Client(server: newValue)
|
||||||
instance = try? await client.get(endpoint: Instances.instance)
|
instance = try? await client.get(endpoint: Instances.instance)
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
.onAppear {
|
.onAppear {
|
||||||
isInstanceURLFieldFocused = true
|
isInstanceURLFieldFocused = true
|
||||||
let client = InstanceSocialClient()
|
let client = InstanceSocialClient()
|
||||||
|
|
|
@ -26,10 +26,7 @@ public struct ExploreView: View {
|
||||||
}
|
}
|
||||||
} else if !viewModel.isLoaded {
|
} else if !viewModel.isLoaded {
|
||||||
loadingView
|
loadingView
|
||||||
} else if viewModel.trendingLinks.isEmpty &&
|
} else if viewModel.allSectionsEmpty {
|
||||||
viewModel.trendingTags.isEmpty &&
|
|
||||||
viewModel.trendingStatuses.isEmpty &&
|
|
||||||
viewModel.suggestedAccounts.isEmpty {
|
|
||||||
EmptyView(iconName: "magnifyingglass",
|
EmptyView(iconName: "magnifyingglass",
|
||||||
title: "Search your instance",
|
title: "Search your instance",
|
||||||
message: "From this screen you can search anything on \(client.server)")
|
message: "From this screen you can search anything on \(client.server)")
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import Models
|
import Models
|
||||||
import Network
|
import Network
|
||||||
|
import Combine
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
class ExploreViewModel: ObservableObject {
|
class ExploreViewModel: ObservableObject {
|
||||||
|
@ -37,21 +38,14 @@ class ExploreViewModel: ObservableObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var allSectionsEmpty: Bool {
|
||||||
|
trendingLinks.isEmpty && trendingTags.isEmpty && trendingStatuses.isEmpty && suggestedAccounts.isEmpty
|
||||||
|
}
|
||||||
|
|
||||||
@Published var tokens: [Token] = []
|
@Published var tokens: [Token] = []
|
||||||
@Published var suggestedToken: [Token] = []
|
@Published var suggestedToken: [Token] = []
|
||||||
@Published var searchQuery = "" {
|
@Published var searchQuery = ""
|
||||||
didSet {
|
|
||||||
if searchQuery.starts(with: "@") {
|
|
||||||
suggestedToken = [.user, .statuses]
|
|
||||||
} else if searchQuery.starts(with: "#") {
|
|
||||||
suggestedToken = [.tag]
|
|
||||||
} else {
|
|
||||||
suggestedToken = []
|
|
||||||
}
|
|
||||||
search()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@Published var results: [String: SearchResults] = [:]
|
@Published var results: [String: SearchResults] = [:]
|
||||||
@Published var isLoaded = false
|
@Published var isLoaded = false
|
||||||
@Published var suggestedAccounts: [Account] = []
|
@Published var suggestedAccounts: [Account] = []
|
||||||
|
@ -61,6 +55,27 @@ class ExploreViewModel: ObservableObject {
|
||||||
@Published var trendingLinks: [Card] = []
|
@Published var trendingLinks: [Card] = []
|
||||||
|
|
||||||
private var searchTask: Task<Void, Never>?
|
private var searchTask: Task<Void, Never>?
|
||||||
|
private var cancellables = Set<AnyCancellable>()
|
||||||
|
|
||||||
|
init() {
|
||||||
|
$searchQuery
|
||||||
|
.removeDuplicates()
|
||||||
|
.debounce(for: .milliseconds(500), scheduler: DispatchQueue.main)
|
||||||
|
.sink(receiveValue: { [weak self] newValue in
|
||||||
|
guard let self else { return }
|
||||||
|
|
||||||
|
if self.searchQuery.starts(with: "@") {
|
||||||
|
self.suggestedToken = [.user, .statuses]
|
||||||
|
} else if self.searchQuery.starts(with: "#") {
|
||||||
|
self.suggestedToken = [.tag]
|
||||||
|
} else {
|
||||||
|
self.suggestedToken = []
|
||||||
|
}
|
||||||
|
|
||||||
|
self.search()
|
||||||
|
})
|
||||||
|
.store(in: &cancellables)
|
||||||
|
}
|
||||||
|
|
||||||
func fetchTrending() async {
|
func fetchTrending() async {
|
||||||
guard let client else { return }
|
guard let client else { return }
|
||||||
|
|
|
@ -98,8 +98,12 @@ public struct StatusRowView: View {
|
||||||
HStack(spacing: 2) {
|
HStack(spacing: 2) {
|
||||||
Image(systemName:"arrow.left.arrow.right.circle.fill")
|
Image(systemName:"arrow.left.arrow.right.circle.fill")
|
||||||
AvatarView(url: viewModel.status.account.avatar, size: .boost)
|
AvatarView(url: viewModel.status.account.avatar, size: .boost)
|
||||||
EmojiTextApp(viewModel.status.account.safeDisplayName.asMarkdown, emojis: viewModel.status.account.emojis)
|
if viewModel.status.account.username != account.account?.username {
|
||||||
Text("boosted")
|
EmojiTextApp(viewModel.status.account.safeDisplayName.asMarkdown, emojis: viewModel.status.account.emojis)
|
||||||
|
Text("boosted")
|
||||||
|
} else {
|
||||||
|
Text("You boosted")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.font(.footnote)
|
.font(.footnote)
|
||||||
.foregroundColor(.gray)
|
.foregroundColor(.gray)
|
||||||
|
|
Loading…
Reference in a new issue