fancy new browser
1import SwiftUI
2import MereCore
3
4public struct AdBlockSettingsView: View {
5
6 @ObservedObject var adBlock: AdBlockController
7
8 public init(adBlock: AdBlockController) {
9 self.adBlock = adBlock
10 }
11
12 public var body: some View {
13 VStack(alignment: .leading, spacing: 16) {
14
15 // Master toggle
16 HStack {
17 VStack(alignment: .leading, spacing: 2) {
18 Text("Ad & Tracker Blocking")
19 .font(.headline)
20 Text("\(adBlock.totalRuleCount.formatted()) rules · \(adBlock.totalBlockedCount.formatted()) blocked")
21 .font(.caption)
22 .foregroundStyle(.secondary)
23 }
24 Spacer()
25 Toggle("", isOn: Binding(
26 get: { adBlock.isEnabled },
27 set: { adBlock.setEnabled($0) }
28 ))
29 .labelsHidden()
30 }
31
32 Divider()
33
34 // Loaded lists
35 if adBlock.loadedLists.isEmpty {
36 Text("No lists loaded")
37 .foregroundStyle(.secondary)
38 .font(.subheadline)
39 } else {
40 ForEach(Array(adBlock.loadedLists.keys.sorted()), id: \.self) { name in
41 HStack {
42 VStack(alignment: .leading, spacing: 2) {
43 Text(name).font(.subheadline)
44 if let count = adBlock.loadedLists[name] {
45 Text("\(count.formatted()) rules")
46 .font(.caption)
47 .foregroundStyle(.secondary)
48 }
49 }
50 Spacer()
51 Button {
52 Task { await adBlock.remove(listNamed: name) }
53 } label: {
54 Image(systemName: "trash")
55 .foregroundStyle(.red)
56 }
57 .buttonStyle(.plain)
58 }
59 }
60 }
61
62 Divider()
63
64 // Load default lists
65 HStack {
66 Button("Load EasyList + EasyPrivacy") {
67 Task { await adBlock.loadDefaults() }
68 }
69 .disabled(adBlock.isLoading)
70
71 if adBlock.isLoading {
72 ProgressView().scaleEffect(0.7)
73 }
74 }
75
76 if let error = adBlock.error {
77 Text(error)
78 .font(.caption)
79 .foregroundStyle(.red)
80 }
81 }
82 .padding()
83 .frame(width: 320)
84 }
85}