Filter management
This commit is contained in:
parent
b073f31e77
commit
cd59aeab0e
|
@ -142,6 +142,20 @@ extension ContentDatabase {
|
|||
.publisher(in: databaseQueue)
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
func activeFiltersObservation(date: Date) -> AnyPublisher<[Filter], Error> {
|
||||
ValueObservation.tracking(Filter.filter(Column("expiresAt") == nil || Column("expiresAt") > date).fetchAll)
|
||||
.removeDuplicates()
|
||||
.publisher(in: databaseQueue)
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
func expiredFiltersObservation(date: Date) -> AnyPublisher<[Filter], Error> {
|
||||
ValueObservation.tracking(Filter.filter(Column("expiresAt") < date).fetchAll)
|
||||
.removeDuplicates()
|
||||
.publisher(in: databaseQueue)
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
}
|
||||
|
||||
private extension ContentDatabase {
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
"preferences.notification-types.reblog" = "Reblog";
|
||||
"preferences.notification-types.mention" = "Mention";
|
||||
"preferences.notification-types.poll" = "Poll";
|
||||
"filters.active" = "Active";
|
||||
"filters.expired" = "Expired";
|
||||
"filter.add-new" = "Add New Filter";
|
||||
"filter.edit" = "Edit Filter";
|
||||
"filter.keyword-or-phrase" = "Keyword or phrase";
|
||||
|
|
|
@ -78,17 +78,9 @@ private extension FilterEndpoint {
|
|||
"whole_word": wholeWord]
|
||||
|
||||
if let expiresIn = expiresIn {
|
||||
params["expires_in"] = Self.dateFormatter.string(from: expiresIn)
|
||||
params["expires_in"] = Int(expiresIn.timeIntervalSinceNow)
|
||||
}
|
||||
|
||||
return params
|
||||
}
|
||||
|
||||
static let dateFormatter: DateFormatter = {
|
||||
let dateFormatter = DateFormatter()
|
||||
|
||||
dateFormatter.dateFormat = MastodonAPI.dateFormat
|
||||
|
||||
return dateFormatter
|
||||
}()
|
||||
}
|
||||
|
|
|
@ -143,8 +143,12 @@ extension IdentityService {
|
|||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
func filtersObservation() -> AnyPublisher<[Filter], Error> {
|
||||
contentDatabase.filtersObservation()
|
||||
func activeFiltersObservation(date: Date) -> AnyPublisher<[Filter], Error> {
|
||||
contentDatabase.activeFiltersObservation(date: date)
|
||||
}
|
||||
|
||||
func expiredFiltersObservation(date: Date) -> AnyPublisher<[Filter], Error> {
|
||||
contentDatabase.expiredFiltersObservation(date: date)
|
||||
}
|
||||
|
||||
func updatePreferences(_ preferences: Identity.Preferences) -> AnyPublisher<Never, Error> {
|
||||
|
|
|
@ -7,10 +7,12 @@ class EditFilterViewModel: ObservableObject {
|
|||
@Published var filter: Filter
|
||||
@Published var saving = false
|
||||
@Published var alertItem: AlertItem?
|
||||
var date: Date
|
||||
let dateRange: ClosedRange<Date>
|
||||
let saveCompleted: AnyPublisher<Void, Never>
|
||||
|
||||
var date: Date {
|
||||
didSet { filter.expiresAt = date }
|
||||
}
|
||||
|
||||
private let identityService: IdentityService
|
||||
private let saveCompletedInput = PassthroughSubject<Void, Never>()
|
||||
private var cancellables = Set<AnyCancellable>()
|
||||
|
@ -18,8 +20,7 @@ class EditFilterViewModel: ObservableObject {
|
|||
init(filter: Filter, identityService: IdentityService) {
|
||||
self.filter = filter
|
||||
self.identityService = identityService
|
||||
date = Calendar.autoupdatingCurrent.date(byAdding: .minute, value: 30, to: Date()) ?? Date()
|
||||
dateRange = date...(Calendar.autoupdatingCurrent.date(byAdding: .day, value: 7, to: date) ?? Date())
|
||||
date = filter.expiresAt ?? Date()
|
||||
saveCompleted = saveCompletedInput.eraseToAnyPublisher()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,8 @@ import Foundation
|
|||
import Combine
|
||||
|
||||
class FiltersViewModel: ObservableObject {
|
||||
@Published var filters = [Filter]()
|
||||
@Published var activeFilters = [Filter]()
|
||||
@Published var expiredFilters = [Filter]()
|
||||
@Published var alertItem: AlertItem?
|
||||
|
||||
private let identityService: IdentityService
|
||||
|
@ -13,9 +14,15 @@ class FiltersViewModel: ObservableObject {
|
|||
init(identityService: IdentityService) {
|
||||
self.identityService = identityService
|
||||
|
||||
identityService.filtersObservation()
|
||||
let now = Date()
|
||||
|
||||
identityService.activeFiltersObservation(date: now)
|
||||
.assignErrorsToAlertItem(to: \.alertItem, on: self)
|
||||
.assign(to: &$filters)
|
||||
.assign(to: &$activeFilters)
|
||||
|
||||
identityService.expiredFiltersObservation(date: now)
|
||||
.assignErrorsToAlertItem(to: \.alertItem, on: self)
|
||||
.assign(to: &$expiredFilters)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,6 +34,13 @@ extension FiltersViewModel {
|
|||
.store(in: &cancellables)
|
||||
}
|
||||
|
||||
func delete(filter: Filter) {
|
||||
identityService.deleteFilter(id: filter.id)
|
||||
.assignErrorsToAlertItem(to: \.alertItem, on: self)
|
||||
.sink { _ in }
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
|
||||
func editFilterViewModel(filter: Filter) -> EditFilterViewModel {
|
||||
EditFilterViewModel(filter: filter, identityService: identityService)
|
||||
}
|
||||
|
|
|
@ -16,17 +16,11 @@ struct EditFilterView: View {
|
|||
if viewModel.isNew || viewModel.filter.expiresAt == nil {
|
||||
Toggle("filter.never-expires", isOn: .init(
|
||||
get: { viewModel.filter.expiresAt == nil },
|
||||
set: {
|
||||
if $0 {
|
||||
viewModel.filter.expiresAt = nil
|
||||
} else {
|
||||
viewModel.filter.expiresAt = viewModel.date
|
||||
}
|
||||
}))
|
||||
set: { viewModel.filter.expiresAt = $0 ? nil : viewModel.date }))
|
||||
}
|
||||
|
||||
if viewModel.filter.expiresAt != nil {
|
||||
DatePicker(selection: $viewModel.date, in: viewModel.dateRange) {
|
||||
DatePicker(selection: $viewModel.date, in: Date()...) {
|
||||
Text("filter.expire-after")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,8 +13,26 @@ struct FiltersView: View {
|
|||
Label("add", systemImage: "plus.circle")
|
||||
}
|
||||
}
|
||||
Section {
|
||||
ForEach(viewModel.filters) { filter in
|
||||
section(title: "filters.active", filters: viewModel.activeFilters)
|
||||
section(title: "filters.expired", filters: viewModel.expiredFilters)
|
||||
}
|
||||
.navigationTitle("preferences.filters")
|
||||
.toolbar {
|
||||
ToolbarItem(placement: ToolbarItemPlacement.navigationBarTrailing) {
|
||||
EditButton()
|
||||
}
|
||||
}
|
||||
.alertItem($viewModel.alertItem)
|
||||
.onAppear(perform: viewModel.refreshFilters)
|
||||
}
|
||||
}
|
||||
|
||||
private extension FiltersView {
|
||||
@ViewBuilder
|
||||
func section(title: LocalizedStringKey, filters: [Filter]) -> some View {
|
||||
if !filters.isEmpty {
|
||||
Section(header: Text(title)) {
|
||||
ForEach(filters) { filter in
|
||||
NavigationLink(destination: EditFilterView(
|
||||
viewModel: viewModel.editFilterViewModel(filter: filter))) {
|
||||
HStack {
|
||||
|
@ -25,11 +43,13 @@ struct FiltersView: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
.onDelete {
|
||||
guard let index = $0.first else { return }
|
||||
|
||||
viewModel.delete(filter: filters[index])
|
||||
}
|
||||
}
|
||||
}
|
||||
.navigationTitle("preferences.filters")
|
||||
.alertItem($viewModel.alertItem)
|
||||
.onAppear(perform: viewModel.refreshFilters)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue