Tusker/Tusker/Screens/Customize Timelines/CustomizeTimelinesView.swift

149 lines
4.6 KiB
Swift

//
// CustomizeTimelinesView.swift
// Tusker
//
// Created by Shadowfacts on 11/30/22.
// Copyright © 2022 Shadowfacts. All rights reserved.
//
import SwiftUI
import Pachyderm
struct CustomizeTimelinesView: View {
let mastodonController: MastodonController
var body: some View {
CustomizeTimelinesList()
.environmentObject(mastodonController)
.environment(\.managedObjectContext, mastodonController.persistentContainer.viewContext)
}
}
struct CustomizeTimelinesList: View {
@EnvironmentObject private var mastodonController: MastodonController
@ObservedObject private var preferences = Preferences.shared
@FetchRequest(sortDescriptors: []) private var filters: FetchedResults<FilterMO>
@Environment(\.dismiss) private var dismiss
@State private var deletionError: (any Error)?
var body: some View {
if #available(iOS 16.0, *) {
NavigationStack {
navigationBody
}
} else {
NavigationView {
navigationBody
}
.navigationViewStyle(.stack)
}
}
private var unexpiredFilters: [FilterMO] {
filters.filter { $0.expiresAt == nil || $0.expiresAt! > Date() }.sorted(using: SemiCaseSensitiveComparator.keyPath(\.titleOrKeyword))
}
private var expiredFilters: [FilterMO] {
filters.filter { $0.expiresAt != nil && $0.expiresAt! <= Date() }.sorted(using: SemiCaseSensitiveComparator.keyPath(\.titleOrKeyword))
}
private var navigationBody: some View {
List {
PinnedTimelinesView(accountPreferences: mastodonController.accountPreferences)
Section {
Toggle(isOn: $preferences.hideReblogsInTimelines) {
Text("Hide Reblogs")
}
Toggle(isOn: $preferences.hideRepliesInTimelines) {
Text("Hide Replies")
}
} header: {
Text("Home Timeline")
}
Section {
filtersForEach(unexpiredFilters)
NavigationLink {
EditFilterView(filter: EditedFilter(), create: true, originallyExpired: false)
} label: {
Label("Add Filter", systemImage: "plus")
.foregroundColor(.accentColor)
}
} header: {
Text("Active Filters")
}
if !expiredFilters.isEmpty {
Section {
filtersForEach(expiredFilters)
} header: {
Text("Expired Filters")
}
}
}
.navigationTitle(Text("Customize Timelines"))
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .confirmationAction) {
Button("Done") {
dismiss()
}
}
}
.alertWithData("Error Deleting Filter", data: $deletionError, actions: { _ in
Button("OK") {
self.deletionError = nil
}
}, message: { error in
Text(error.localizedDescription)
})
.task {
await mastodonController.loadFilters()
}
}
@ViewBuilder
private func filtersForEach(_ filters: [FilterMO]) -> some View {
if !filters.isEmpty {
ForEach(filters, id: \.id) { filter in
NavigationLink {
EditFilterView(filter: EditedFilter(filter), create: false, originallyExpired: filter.expiresAt != nil && filter.expiresAt! <= Date())
} label: {
FilterRow(filter: filter)
}
.contextMenu {
Button(role: .destructive) {
deleteFilter(filter)
} label: {
Label("Delete Filter", systemImage: "trash")
}
}
}
.onDelete { indices in
for filter in indices.map({ filters[$0] }) {
deleteFilter(filter)
}
}
}
}
private func deleteFilter(_ filter: FilterMO) {
Task {
do {
try await DeleteFilterService(filter: filter, mastodonController: mastodonController).run()
} catch {
self.deletionError = error
}
}
}
}
//struct FiltersView_Previews: PreviewProvider {
// static var previews: some View {
// FiltersView()
// }
//}