Advertisement
Guest User

Observable Array problem

a guest
Aug 4th, 2019
687
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Swift 6.83 KB | None | 0 0
  1. // SceneDelegate.swift
  2.  
  3. func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
  4.     // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
  5.     // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
  6.     // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
  7.  
  8.     // Use a UIHostingController as window root view controller
  9.     if let windowScene = scene as? UIWindowScene {
  10.         let window = UIWindow(windowScene: windowScene)
  11.         let store = Store()
  12.         window.rootViewController = UIHostingController(rootView: RepositoryList(store: store))
  13.         self.window = window
  14.         window.makeKeyAndVisible()
  15.     }
  16. }
  17.  
  18. //
  19. //  App.swift
  20.  
  21. import SwiftUI
  22. import Combine
  23.  
  24. struct RepositoryList : View {
  25.     @ObservedObject var store: Store
  26.    
  27.     func move(from source: IndexSet, to destination: Int) {
  28.         store.repositories.swapAt(source.first!, destination)
  29.     }
  30.    
  31.     @State private var isTapped = false
  32.     @State private var bgColor = Color.white
  33.    
  34.     var body: some View {
  35.         NavigationView {
  36.             VStack {
  37.                 List {
  38.                     Section(header: Text("\(String(store.repositories.count)) repositories")) {
  39.                         ForEach(store.repositories) { repository in
  40.                             NavigationLink(destination: RepositoryDetail(store: self.store, repository: repository)) {
  41.                                 RepositoryRow(repository: repository)
  42.                             }.padding(.vertical, 8.0)
  43.                         }.onDelete { index in
  44.                             self.store.repositories.remove(at: index.first!)
  45.                         }.onMove(perform: move)
  46.                     }
  47.                 }
  48.             }
  49.         }.navigationBarTitle("Github user").navigationBarItems(trailing: EditButton())
  50.     }
  51. }
  52.  
  53. struct RepositoryDetail : View {
  54.     @ObservedObject var store: Store
  55.     var repository: Repository
  56.    
  57.     var repoIndex: Int {
  58.         let repoIndex = store.repositories.firstIndex(where: {$0.id == repository.id})!
  59.         print("### IS FAVORITE \(String(store.repositories[repoIndex].isFavorite))")
  60.         return repoIndex
  61.     }
  62.    
  63.     var body: some View {
  64.         VStack(alignment: .leading) {
  65.             Text(String(store.repositories[repoIndex].isFavorite))
  66.             Button(action: { self.store.repositories[self.repoIndex].isFavorite.toggle() }) {
  67.                 if (self.store.repositories[self.repoIndex].isFavorite) {
  68.                     Image(systemName: "star.fill").foregroundColor(Color.yellow)
  69.                 } else {
  70.                     Image(systemName: "star").foregroundColor(Color.gray)
  71.                 }
  72.             }
  73.         }.navigationBarTitle(Text(repository.name), displayMode: .inline)
  74.     }
  75. }
  76.  
  77. class Store: ObservableObject {
  78.     private var cancellable: AnyCancellable? = nil
  79.     @Published var repositories: [Repository] = []
  80.    
  81.     init () {
  82.         var urlComponents = URLComponents(string: "https://api.github.com/users/Hurobaki/repos")!
  83.         var request = URLRequest(url: urlComponents.url!)
  84.         request.addValue("application/json", forHTTPHeaderField: "Content-Type")
  85.        
  86.         cancellable = URLSession.shared.send(request: request)
  87.             .decode(type: [Repository].self, decoder: JSONDecoder())
  88.             .receive(on: DispatchQueue.main)
  89.             .sink(receiveCompletion: { completion in
  90.                 print("### .sink() received the completion", String(describing: completion))
  91.                 switch completion {
  92.                 case .finished:
  93.                     break
  94.                 case .failure(_):
  95.                    print("### ERROR")
  96.                 }
  97.             }, receiveValue: { repositories in
  98.                 self.repositories = repositories
  99.             })
  100.        
  101.     }
  102. }
  103.  
  104. class Repository: Decodable, Identifiable {
  105.     var id: Int = 0
  106.     var name: String = ""
  107.     var desc: String? = nil
  108.    
  109.     var isFavorite = false
  110.    
  111.     private enum CodingKeys: String, CodingKey {
  112.         case id, name
  113.         case desc = "description"
  114.     }
  115. }
  116.  
  117. struct RepositoryRow : View {
  118.    
  119.     var repository: Repository
  120.    
  121.     var body: some View {
  122.         HStack(spacing: 12.0) {
  123.             Image(systemName: "circle")
  124.                 .resizable()
  125.                 .aspectRatio(contentMode: .fit)
  126.                 .frame(width: 80, height: 80)
  127.                 .cornerRadius(20)
  128.            
  129.             VStack(alignment: .leading) {
  130.                 Text(repository.name).font(.headline)
  131.                 Text(repository.desc ?? "No description provided.").lineLimit(2).lineSpacing(4).font(.subheadline).frame(height: 50.0)
  132.             }
  133.         }
  134.     }
  135. }
  136.  
  137. struct LoadingView : UIViewRepresentable {
  138.     typealias UIViewType = UIActivityIndicatorView
  139.    
  140.     func makeUIView(context: UIViewRepresentableContext<LoadingView>) -> LoadingView.UIViewType {
  141.         let view = UIActivityIndicatorView(style: .large)
  142.         view.startAnimating()
  143.         return view
  144.     }
  145.    
  146.     func updateUIView(_ uiView: LoadingView.UIViewType, context: UIViewRepresentableContext<LoadingView>) {
  147.         //Todo
  148.     }
  149. }
  150.  
  151.  
  152. extension URLSession {
  153.    
  154.     enum URLSessionError: Error {
  155.         case invalidResponse
  156.         case serverErrorMessage(statusCode: Int, data: Data)
  157.         case urlError(URLError)
  158.     }
  159.    
  160.     func send(request: URLRequest) -> AnyPublisher<Data, URLSessionError> {
  161.         dataTaskPublisher(for: request)
  162.             .mapError { URLSessionError.urlError($0) }
  163.             .flatMap { data, response -> AnyPublisher<Data, URLSessionError> in
  164.                 guard let response = response as? HTTPURLResponse else {
  165.                     return .fail(.invalidResponse)
  166.                 }
  167.                
  168.                 guard 200..<300 ~= response.statusCode else {
  169.                     return .fail(.serverErrorMessage(statusCode: response.statusCode,
  170.                                                      data: data))
  171.                 }
  172.                
  173.                 return .just(data)
  174.         }.eraseToAnyPublisher()
  175.     }
  176. }
  177.  
  178. extension Publisher {
  179.    
  180.     static func empty() -> AnyPublisher<Output, Failure> {
  181.         return Empty()
  182.             .eraseToAnyPublisher()
  183.     }
  184.    
  185.     static func just(_ output: Output) -> AnyPublisher<Output, Failure> {
  186.         return Just(output)
  187.             .catch { _ in AnyPublisher<Output, Failure>.empty() }
  188.             .eraseToAnyPublisher()
  189.     }
  190.    
  191.     static func fail(_ error: Failure) -> AnyPublisher<Output, Failure> {
  192.         return Fail(error: error)
  193.             .eraseToAnyPublisher()
  194.     }
  195. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement