Skip to content
This repository was archived by the owner on Mar 7, 2026. It is now read-only.

Commit e91b041

Browse files
authored
Changed validationStates dictionary key from URL to String
1 parent 505554d commit e91b041

3 files changed

Lines changed: 66 additions & 54 deletions

File tree

Sources/prostore/viewModelsAndHelpers/SourcesViewModel.swift

Lines changed: 25 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import Combine
33

44
class SourcesViewModel: ObservableObject {
55
@Published var sources: [Source] = []
6-
@Published var validationStates: [URL: ValidationState] = [:]
6+
@Published var validationStates: [String: ValidationState] = [:] // Use String keys
77
@Published var isAddingNew = false
88
@Published var newSourceURL = ""
99
@Published var editingSource: Source? = nil
@@ -178,34 +178,32 @@ class SourcesViewModel: ObservableObject {
178178
newSourceURL = ""
179179
}
180180

181-
func validateSource(_ source: Source) {
182-
guard let url = source.url else {
183-
// Create a placeholder URL for invalid URL strings to store validation state
184-
if let placeholderURL = URL(string: "invalid://" + source.urlString.addingPercentEncoding(withAllowedCharacters: .alphanumerics)!) {
185-
validationStates[placeholderURL] = .invalid(NSError(domain: "Invalid URL", code: 0, userInfo: nil))
181+
func validateSource(_ source: Source) {
182+
// Always set to loading first
183+
validationStates[source.urlString] = .loading
184+
185+
guard let url = source.url else {
186+
validationStates[source.urlString] = .invalid(NSError(domain: "Invalid URL", code: 0, userInfo: nil))
187+
return
186188
}
187-
return
188-
}
189-
190-
validationStates[url] = .loading
191-
192-
var request = URLRequest(url: url)
193-
request.setValue("AppTestersListView/1.0 (iOS)", forHTTPHeaderField: "User-Agent")
194-
request.timeoutInterval = 10
195-
196-
URLSession.shared.dataTask(with: request) { [weak self] data, response, error in
197-
DispatchQueue.main.async {
198-
if let error = error {
199-
self?.validationStates[url] = .invalid(error)
200-
} else if let httpResponse = response as? HTTPURLResponse, !(200...299).contains(httpResponse.statusCode) {
201-
let error = NSError(domain: "HTTP Error", code: httpResponse.statusCode, userInfo: nil)
202-
self?.validationStates[url] = .invalid(error)
203-
} else {
204-
self?.validationStates[url] = .valid
189+
190+
var request = URLRequest(url: url)
191+
request.setValue("AppTestersListView/1.0 (iOS)", forHTTPHeaderField: "User-Agent")
192+
request.timeoutInterval = 10
193+
194+
URLSession.shared.dataTask(with: request) { [weak self] data, response, error in
195+
DispatchQueue.main.async {
196+
if let error = error {
197+
self?.validationStates[source.urlString] = .invalid(error)
198+
} else if let httpResponse = response as? HTTPURLResponse, !(200...299).contains(httpResponse.statusCode) {
199+
let error = NSError(domain: "HTTP Error", code: httpResponse.statusCode, userInfo: nil)
200+
self?.validationStates[source.urlString] = .invalid(error)
201+
} else {
202+
self?.validationStates[source.urlString] = .valid
203+
}
205204
}
206-
}
207-
}.resume()
208-
}
205+
}.resume()
206+
}
209207

210208
func validateAllSources() {
211209
for source in sources {

Sources/prostore/views/SettingsView.swift

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// SettingsView.swift
22
import SwiftUI
33

4+
// MARK: - Credit model
45
struct Credit: Identifiable {
56
var id = UUID()
67
var name: String
@@ -9,11 +10,13 @@ struct Credit: Identifiable {
910
var avatarURL: URL
1011
}
1112

13+
// MARK: - SettingsView
1214
struct SettingsView: View {
1315
@EnvironmentObject var sourcesViewModel: SourcesViewModel
1416
@State private var showingSourcesManager = false
1517
@State private var showingSetup = false
16-
18+
19+
// MARK: Credits
1720
private let credits: [Credit] = [
1821
Credit(
1922
name: "SuperGamer474",
@@ -41,17 +44,23 @@ struct SettingsView: View {
4144
)
4245
]
4346

47+
// MARK: App metadata
4448
private var appIconURL: URL? {
4549
URL(string: "https://raw.githubusercontent.com/ProStore-iOS/ProStore/main/Sources/prostore/Assets.xcassets/AppIcon.appiconset/Icon-1024.png")
4650
}
4751

4852
private var versionString: String {
49-
Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String ?? "1.0"
53+
Bundle.main.object(
54+
forInfoDictionaryKey: "CFBundleShortVersionString"
55+
) as? String ?? "1.0"
5056
}
5157

58+
// MARK: Body
5259
var body: some View {
5360
NavigationStack {
5461
List {
62+
63+
// MARK: Header
5564
VStack(spacing: 8) {
5665
if let url = appIconURL {
5766
AsyncImage(url: url) { phase in
@@ -60,7 +69,12 @@ struct SettingsView: View {
6069
.resizable()
6170
.scaledToFit()
6271
.frame(width: 120, height: 120)
63-
.clipShape(RoundedRectangle(cornerRadius: 20, style: .continuous))
72+
.clipShape(
73+
RoundedRectangle(
74+
cornerRadius: 20,
75+
style: .continuous
76+
)
77+
)
6478
.shadow(radius: 6)
6579
} else if phase.error != nil {
6680
Image(systemName: "app.fill")
@@ -87,37 +101,42 @@ struct SettingsView: View {
87101
.padding(.vertical, 20)
88102
.listRowInsets(EdgeInsets())
89103

104+
// MARK: Setup
90105
Section {
91106
Button("Show Setup") {
92107
showingSetup = true
93108
}
94109
.buttonStyle(.borderedProminent)
95110
}
96111

112+
// MARK: Sources
97113
Section(header: Text("Sources")) {
98114
NavigationLink {
99115
SourcesManagerView()
100116
} label: {
101117
Label("Sources Manager", systemImage: "link")
102118
}
103-
119+
104120
DisclosureGroup("Current Sources") {
105121
ForEach(sourcesViewModel.sources.prefix(3)) { source in
106122
HStack {
107123
Text(source.urlString)
108124
.font(.caption)
109125
.foregroundColor(.secondary)
110126
.lineLimit(1)
127+
111128
Spacer()
112-
if let url = source.url,
113-
let validationState = sourcesViewModel.validationStates[url] {
129+
130+
// ✅ UPDATED: String-keyed validation lookup
131+
if let validationState =
132+
sourcesViewModel.validationStates[source.urlString] {
114133
Image(systemName: validationState.icon)
115134
.font(.caption2)
116135
.foregroundColor(validationState.color)
117136
}
118137
}
119138
}
120-
139+
121140
if sourcesViewModel.sources.count > 3 {
122141
Text("+ \(sourcesViewModel.sources.count - 3) more")
123142
.font(.caption)
@@ -126,28 +145,32 @@ struct SettingsView: View {
126145
}
127146
}
128147

148+
// MARK: Credits
129149
Section(header: Text("Credits")) {
130-
ForEach(credits) { c in
131-
CreditRow(credit: c)
150+
ForEach(credits) { credit in
151+
CreditRow(credit: credit)
132152
}
133153
}
134154
}
135-
.listStyle(InsetGroupedListStyle())
155+
.listStyle(.insetGrouped)
136156
.navigationTitle("Settings")
137157
.navigationBarTitleDisplayMode(.large)
138158
.onAppear {
139159
sourcesViewModel.validateAllSources()
140160
}
141161
}
142162
.sheet(isPresented: $showingSetup) {
143-
SetupView(onComplete: { showingSetup = false })
163+
SetupView {
164+
showingSetup = false
165+
}
144166
}
145167
}
146168
}
147169

170+
// MARK: - CreditRow
148171
struct CreditRow: View {
149172
let credit: Credit
150-
@Environment(\.openURL) var openURL
173+
@Environment(\.openURL) private var openURL
151174

152175
var body: some View {
153176
HStack(spacing: 12) {
@@ -166,7 +189,10 @@ struct CreditRow: View {
166189
}
167190
.frame(width: 44, height: 44)
168191
.clipShape(Circle())
169-
.overlay(Circle().stroke(Color(UIColor.separator), lineWidth: 0.5))
192+
.overlay(
193+
Circle()
194+
.stroke(Color(UIColor.separator), lineWidth: 0.5)
195+
)
170196

171197
VStack(alignment: .leading, spacing: 2) {
172198
Text(credit.name)
@@ -185,7 +211,7 @@ struct CreditRow: View {
185211
.imageScale(.large)
186212
.foregroundColor(.primary)
187213
}
188-
.buttonStyle(BorderlessButtonStyle())
214+
.buttonStyle(.borderless)
189215
}
190216
.padding(.vertical, 8)
191217
}

Sources/prostore/views/SourcesManagerView.swift

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -143,18 +143,6 @@ struct SourceRow: View {
143143
let source: SourcesViewModel.Source
144144
@EnvironmentObject var sourcesViewModel: SourcesViewModel
145145

146-
var validationState: SourcesViewModel.ValidationState? {
147-
// Try to get validation state from the actual URL
148-
if let url = source.url {
149-
return sourcesViewModel.validationStates[url]
150-
}
151-
// If URL is invalid, look for placeholder validation state
152-
if let placeholderURL = URL(string: "invalid://" + source.urlString.addingPercentEncoding(withAllowedCharacters: .alphanumerics)!) {
153-
return sourcesViewModel.validationStates[placeholderURL]
154-
}
155-
return nil
156-
}
157-
158146
var body: some View {
159147
HStack {
160148
VStack(alignment: .leading, spacing: 4) {
@@ -164,7 +152,7 @@ struct SourceRow: View {
164152
.lineLimit(2)
165153
.minimumScaleFactor(0.8)
166154

167-
if let validationState = validationState {
155+
if let validationState = sourcesViewModel.validationStates[source.urlString] {
168156
HStack {
169157
Image(systemName: validationState.icon)
170158
.font(.caption)

0 commit comments

Comments
 (0)