Filter management

This commit is contained in:
Justin Mazzocchi 2020-08-29 17:32:34 -07:00
parent b073f31e77
commit cd59aeab0e
No known key found for this signature in database
GPG key ID: E223E6937AAFB01C
8 changed files with 72 additions and 31 deletions

View file

@ -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 {

View file

@ -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";

View file

@ -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
}()
}

View file

@ -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> {

View file

@ -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()
}
}

View file

@ -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)
}

View file

@ -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")
}
}

View file

@ -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)
}
}