@@ -103,15 +103,33 @@ final class RepoViewModel: ObservableObject {
103103 }
104104}
105105
106- // MARK: - The SwiftUI View (no NavigationView wrapper )
106+ // MARK: - The SwiftUI View (searchable apps list )
107107public struct AppsView : View {
108108 @StateObject private var vm : RepoViewModel
109109
110+ // Search state
111+ @State private var searchText : String = " "
112+ @FocusState private var searchFieldFocused : Bool
113+
110114 // Public initializer so you can pass a custom repository URL (defaults to user's provided URL)
111115 public init ( repoURL: URL = URL ( string: " https://repository.apptesters.org/ " ) !) {
112116 _vm = StateObject ( wrappedValue: RepoViewModel ( sourceURL: repoURL) )
113117 }
114118
119+ // Filtered apps based on search text
120+ private var filteredApps : [ AltApp ] {
121+ let query = searchText. trimmingCharacters ( in: . whitespacesAndNewlines)
122+ guard !query. isEmpty else { return vm. apps }
123+ let lowered = query. lowercased ( )
124+ return vm. apps. filter { app in
125+ if app. name. lowercased ( ) . contains ( lowered) { return true }
126+ if app. bundleIdentifier. lowercased ( ) . contains ( lowered) { return true }
127+ if let dev = app. developerName, dev. lowercased ( ) . contains ( lowered) { return true }
128+ if let sub = app. subtitle, sub. lowercased ( ) . contains ( lowered) { return true }
129+ return false
130+ }
131+ }
132+
115133 public var body : some View {
116134 Group {
117135 if vm. isLoading && vm. apps. isEmpty {
@@ -135,11 +153,18 @@ public struct AppsView: View {
135153 }
136154 . padding ( )
137155 } else {
138- List ( vm. apps) { app in
156+ // List with searchable modifier
157+ List ( filteredApps) { app in
139158 AppRowView ( app: app)
140159 }
141160 . listStyle ( PlainListStyle ( ) )
142161 . refreshable { vm. refresh ( ) }
162+ . searchable ( text: $searchText, placement: . automatic, prompt: " Search apps or developer " )
163+ . onSubmit ( of: . search) {
164+ // Dismiss keyboard on submit
165+ searchFieldFocused = false
166+ }
167+ . animation ( . default, value: filteredApps)
143168 }
144169 }
145170 . toolbar {
0 commit comments