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

Commit a1cf446

Browse files
authored
Add more app repos
1 parent bd8f107 commit a1cf446

3 files changed

Lines changed: 60 additions & 44 deletions

File tree

Sources/prostore/prostore.swift

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,14 @@ struct MainSidebarView: View {
4545
}
4646
case .apps:
4747
NavigationStack {
48-
AppsView()
48+
AppsView(repoURLs: [
49+
URL(string: "https://repository.apptesters.org/")!,
50+
URL(string: "https://wuxu1.github.io/wuxu-complete.json")!,
51+
URL(string: "https://wuxu1.github.io/wuxu-complete-plus.json")!,
52+
URL(string: "https://raw.githubusercontent.com/RealBlackAstronaut/CelestialRepo/main/CelestialRepo.json")!,
53+
URL(string: "https://ipa.cypwn.xyz/cypwn.json")!,
54+
URL(string: "https://quarksources.github.io/altstore-complete.json")!
55+
])
4956
.navigationTitle("Apps")
5057
.navigationBarTitleDisplayMode(.large)
5158
}

Sources/prostore/views/appsView.swift

Lines changed: 50 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -37,57 +37,66 @@ final class RepoViewModel: ObservableObject {
3737
@Published var isLoading: Bool = false
3838
@Published var errorMessage: String? = nil
3939

40-
private let sourceURL: URL
40+
private let sourceURLs: [URL] // <-- multiple sources
4141

42-
init(sourceURL: URL) {
43-
self.sourceURL = sourceURL
44-
Task { await load() }
42+
init(sourceURLs: [URL]) {
43+
self.sourceURLs = sourceURLs
44+
Task { await loadAllSources() }
4545
}
4646

47-
func load() async {
47+
func loadAllSources() async {
4848
isLoading = true
4949
errorMessage = nil
5050
defer { isLoading = false }
5151

52-
do {
53-
var request = URLRequest(url: sourceURL)
54-
request.setValue("AppTestersListView/1.0 (iOS)", forHTTPHeaderField: "User-Agent")
55-
56-
let (data, response) = try await URLSession.shared.data(for: request)
57-
if let http = response as? HTTPURLResponse, !(200...299).contains(http.statusCode) {
58-
throw NSError(domain: "RepoFetcher", code: http.statusCode, userInfo: [NSLocalizedDescriptionKey: "HTTP \(http.statusCode)"])
59-
}
60-
61-
let decoder = JSONDecoder()
62-
63-
if let source = try? decoder.decode(AltSource.self, from: data), let apps = source.apps {
64-
self.apps = apps
65-
return
66-
}
67-
68-
if let appsArray = try? decoder.decode([AltApp].self, from: data) {
69-
self.apps = appsArray
70-
return
71-
}
72-
73-
if let jsonObject = try JSONSerialization.jsonObject(with: data) as? [String: Any],
74-
let appsFragment = jsonObject["apps"] {
75-
let fragmentData = try JSONSerialization.data(withJSONObject: appsFragment)
76-
let appsArray = try decoder.decode([AltApp].self, from: fragmentData)
77-
self.apps = appsArray
78-
return
52+
var combinedApps: [AltApp] = []
53+
var errors: [String] = []
54+
55+
for url in sourceURLs {
56+
do {
57+
var request = URLRequest(url: url)
58+
request.setValue("AppTestersListView/1.0 (iOS)", forHTTPHeaderField: "User-Agent")
59+
60+
let (data, response) = try await URLSession.shared.data(for: request)
61+
if let http = response as? HTTPURLResponse, !(200...299).contains(http.statusCode) {
62+
throw NSError(domain: "RepoFetcher", code: http.statusCode, userInfo: [NSLocalizedDescriptionKey: "HTTP \(http.statusCode)"])
63+
}
64+
65+
let decoder = JSONDecoder()
66+
67+
if let source = try? decoder.decode(AltSource.self, from: data), let apps = source.apps {
68+
combinedApps.append(contentsOf: apps)
69+
continue
70+
}
71+
72+
if let appsArray = try? decoder.decode([AltApp].self, from: data) {
73+
combinedApps.append(contentsOf: appsArray)
74+
continue
75+
}
76+
77+
if let jsonObject = try JSONSerialization.jsonObject(with: data) as? [String: Any],
78+
let appsFragment = jsonObject["apps"] {
79+
let fragmentData = try JSONSerialization.data(withJSONObject: appsFragment)
80+
let appsArray = try decoder.decode([AltApp].self, from: fragmentData)
81+
combinedApps.append(contentsOf: appsArray)
82+
continue
83+
}
84+
85+
throw NSError(domain: "RepoFetcher", code: -1, userInfo: [NSLocalizedDescriptionKey: "Unexpected JSON format."])
86+
87+
} catch {
88+
errors.append("Failed \(url): \(error.localizedDescription)")
7989
}
80-
81-
throw NSError(domain: "RepoFetcher", code: -1, userInfo: [NSLocalizedDescriptionKey: "Unexpected JSON format."])
82-
83-
} catch {
84-
self.errorMessage = "Failed to load repository: \(error.localizedDescription)"
85-
self.apps = []
90+
}
91+
92+
self.apps = combinedApps
93+
if !errors.isEmpty {
94+
self.errorMessage = errors.joined(separator: "\n")
8695
}
8796
}
8897

8998
func refresh() {
90-
Task { await load() }
99+
Task { await loadAllSources() }
91100
}
92101
}
93102

@@ -98,8 +107,8 @@ public struct AppsView: View {
98107
@FocusState private var searchFieldFocused: Bool
99108
@State private var selectedApp: AltApp? = nil
100109

101-
public init(repoURL: URL = URL(string: "https://repository.apptesters.org/")!) {
102-
_vm = StateObject(wrappedValue: RepoViewModel(sourceURL: repoURL))
110+
public init(repoURLs: [URL] = [URL(string: "https://repository.apptesters.org/")!]) {
111+
_vm = StateObject(wrappedValue: RepoViewModel(sourceURLs: repoURLs))
103112
}
104113

105114
private var filteredApps: [AltApp] {

project.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ targets:
3030
properties:
3131
CFBundleDisplayName: "ProStore"
3232
CFBundleName: "prostore"
33-
CFBundleVersion: "9"
34-
CFBundleShortVersionString: "0.5.0"
33+
CFBundleVersion: "10"
34+
CFBundleShortVersionString: "0.5.1"
3535
UILaunchStoryboardName: "LaunchScreen"
3636
NSPrincipalClass: "UIApplication"
3737
NSAppTransportSecurity:

0 commit comments

Comments
 (0)