Ferrite/Ferrite/Views/ContentView.swift
kingbri 7202a95bb2 Ferrite: Parallel tasks and logging
Make all tasks run in parallel to increase responsiveness and efficiency
when fetching new data.

However, parallel tasks means that toast errors are no longer feasible.
Instead, add a logging system which has a more detailed view of
app messages and direct the user there if there is an error.

Signed-off-by: kingbri <bdashore3@proton.me>
2023-03-09 18:48:28 -05:00

147 lines
5.3 KiB
Swift

//
// ContentView.swift
// Ferrite
//
// Created by Brian Dashore on 7/1/22.
//
import SwiftUI
import SwiftUIX
struct ContentView: View {
@EnvironmentObject var scrapingModel: ScrapingViewModel
@EnvironmentObject var debridManager: DebridManager
@EnvironmentObject var navModel: NavigationViewModel
@EnvironmentObject var pluginManager: PluginManager
@EnvironmentObject var logManager: LoggingManager
@AppStorage("Behavior.UsesRandomSearchText") var usesRandomSearchText: Bool = false
@State private var isEditingSearch = false
@State private var isSearching = false
@State private var searchText: String = ""
@State private var lastSearchTextIndex: Int = -1
@State private var searchBarText: String = "Search"
let searchBarTextArray: [String] = [
"What's on your mind?",
"Discover something interesting",
"Find an engaging show",
"Feeling adventurous?",
"Look for something new",
"The classics are a good idea"
]
var body: some View {
NavView {
List {
ForEach(scrapingModel.searchResults, id: \.self) { result in
if result.source == scrapingModel.filteredSource?.name || scrapingModel.filteredSource == nil {
SearchResultButtonView(result: result)
}
}
}
.listStyle(.insetGrouped)
.inlinedList(inset: Application.shared.osVersion.majorVersion > 14 ? 20 : -20)
.overlay {
if
scrapingModel.searchResults.isEmpty,
isSearching,
scrapingModel.runningSearchTask == nil
{
Text("No results found")
}
}
.onChange(of: searchText) { newText in
if newText.isEmpty, isSearching {
searchBarText = getSearchBarText()
}
}
.onChange(of: scrapingModel.searchResults) { _ in
// Cleans up any leftover search results in the event of an abrupt cancellation
if !isSearching {
scrapingModel.searchResults = []
}
}
.onChange(of: navModel.selectedTab) { tab in
// Cancel the search if tab is switched while search is in progress
if tab != .search, scrapingModel.runningSearchTask != nil {
scrapingModel.searchResults = []
scrapingModel.runningSearchTask?.cancel()
scrapingModel.runningSearchTask = nil
isSearching = false
searchText = ""
}
}
.navigationTitle("Search")
.navigationSearchBar {
SearchBar(
searchBarText,
text: $searchText,
isEditing: $isEditingSearch,
onCommit: {
if let runningSearchTask = scrapingModel.runningSearchTask, runningSearchTask.isCancelled {
scrapingModel.runningSearchTask = nil
return
}
scrapingModel.runningSearchTask = Task {
isSearching = true
let sources = pluginManager.fetchInstalledSources()
await scrapingModel.scanSources(
sources: sources,
searchText: searchText,
debridManager: debridManager
)
logManager.hideIndeterminateToast()
scrapingModel.runningSearchTask = nil
}
}
)
.showsCancelButton(isEditingSearch || isSearching)
.onCancel {
scrapingModel.searchResults = []
scrapingModel.runningSearchTask?.cancel()
scrapingModel.runningSearchTask = nil
isSearching = false
searchText = ""
searchBarText = getSearchBarText()
}
}
.navigationSearchBarHiddenWhenScrolling(false)
.customScopeBar {
SearchFilterHeaderView()
.environmentObject(scrapingModel)
.environmentObject(debridManager)
}
}
.backport.onAppear {
searchBarText = getSearchBarText()
}
}
// Fetches random searchbar text if enabled, otherwise deinit the last case value
func getSearchBarText() -> String {
if usesRandomSearchText {
let num = Int.random(in: 0 ..< searchBarTextArray.count - 1)
if num == lastSearchTextIndex {
lastSearchTextIndex = num + 1
return searchBarTextArray[safe: num + 1] ?? "Search"
} else {
lastSearchTextIndex = num
return searchBarTextArray[safe: num] ?? "Search"
}
} else {
lastSearchTextIndex = -1
return "Search"
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}