I am trying to make an app that will allow you to view the repo list of the user by providing their login name and I get quite a major bug I can't figure our how to get rid of.
How to make the bug appear?
- Advance from the initial view to the ListView by typing the correct user login (e.g. jacobtoye) name in the TextField
- Remove the content of TextField in the ListView and press "View repos"
- At least I don't get an error alert then, but an eternal ProgressView()
How to make an empty query pushed from the ListView show an "invalid username error" alert rather than Eternal ProgressView()?
The code:
CONTENTVIEW FILE:
import SwiftUI
struct ContentView: View {
@StateObject var viewModel = ContentViewModel()
var body: some View {
if viewModel.repos.isEmpty {
//Initial View code here
NavigationView{
VStack(alignment: .leading){
HStack{
TextField("Enter GitHub username", text: $viewModel.userName)
Button("View repos") {
viewModel.fetchRepos()
}
.alert("This user doesn't own any repositories", isPresented: $viewModel.showingSecondAlert){
Button("Try again", action: viewModel.flushRepos)
}
.padding()
}
.alert("Invalid GitHub username", isPresented: $viewModel.showingMainAlert){
Button("Try again", action: viewModel.flushRepos)
}
.navigationTitle("GH Repo Language")
Spacer()
}
}
}
else if viewModel.reposAreLoading {
ProgressView()
} else {
//ListView code here
NavigationView{
VStack{
HStack{
TextField("Enter GitHub username", text: $viewModel.userName)
Button("View repos") {
viewModel.fetchRepos()
}
.alert("This user doesn't own any repositories", isPresented: $viewModel.showingSecondAlert){
Button("Try again", action: viewModel.flushRepos)
}
.padding()
}
.alert("Invalid GitHub username", isPresented: $viewModel.showingMainAlert){
Button("Try again", action: viewModel.flushRepos)
}
List {
ForEach(viewModel.repos) { repo in
VStack {
Text("\(repo.fullName)")
}
}
}
}
}
.navigationTitle("\(viewModel.repos.first?.owner.login ?? "no name")'s repos")
}
}
}
CONTENTVIEW MODEL:
import Foundation
final class ContentViewModel: ObservableObject {
@Published var repos = [Repository]()
@Published var reposAreLoading = false
@Published var userName = ""
@Published var showingMainAlert = false
@Published var showingSecondAlert = false
func fetchRepos() {
reposAreLoading = true
guard let url = URL(string: "https://api.github.com/users/\(userName)/repos") else { return }
URLSession.shared.dataTask(with: url) {(data, _, _) in
guard let data = data else { return }
DispatchQueue.main.async {
do {
self.repos = try JSONDecoder().decode([Repository].self, from: data)
self.reposAreLoading = false
if self.repos.isEmpty {
self.showingSecondAlert = true
}
} catch {
self.showingMainAlert = true
}
}
}.resume()
}
func flushRepos() {
self.repos = [Repository]()
}
}
JSON STRUCTS:
import Foundation
struct Repository: Decodable, Identifiable {
let id: Int
let name: String
let fullName: String
let owner: Owner
enum CodingKeys: String, CodingKey {
case id, owner
case name
case fullName = "full_name"
}
}
struct Owner : Decodable, Identifiable {
let id: Int
let login: String
let reposUrl : String
enum CodingKeys: String, CodingKey, CaseIterable {
case id
case login
case reposUrl = "repos_url"
}
}
For me it seems that somehow Xcode gets stuck in realising the fetchRepos() function after pushing an empty query from the ListView, but I don't know how to find out what to fix. Please help.