Guest User

Untitled

a guest
May 3rd, 2021
139
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Swift 5.13 KB | None | 0 0
  1. struct LyricsMainView: View {
  2.     @State var songName: String = "Adventure of a Lifetime"
  3.     @State var artistName: String = "Coldplay."
  4.     @ObservedObject var viewModel = ViewModel()
  5.     var body: some View {
  6.         HStack {
  7.             Spacer()
  8.            
  9.             Button(action: {
  10.                 viewModel.loadApiSongData(songName: songName, artistName: artistName)
  11.             }, label: {
  12.                 Text("Search Lyrics!")
  13.             })
  14.            
  15.            
  16.            
  17.             .alert(isPresented: $viewModel.noConnectionAlert) {
  18.                 Alert(title: Text("No internet connection"), message: Text("Oops! It seems you arent connected to the internet. Please connect and try again!"), dismissButton: .default(Text("Got it!")))
  19.             }
  20.             Spacer()
  21.         }
  22.         .padding(.top, 20)
  23.         .sheet(item: $viewModel.apiResponse) { item in
  24.             LyricsView(vm: self.viewModel, songName: songName, artistName: artistName, arrLyrics: item.apiValues)
  25.         }
  26.     }
  27. }
  28.  
  29. struct LyricsView: View {
  30.     var vm: ViewModel
  31.     var songName: String
  32.     var artistName: String
  33.     var arrLyrics: String
  34.    
  35.     var body: some View {
  36.         VStack {
  37.             Text(songName)
  38.             Text(artistName)
  39.             Text(arrLyrics)
  40.         }
  41.     }
  42. }
  43.  
  44. struct LyricsView_Previews: PreviewProvider {
  45.     static var previews: some View {
  46.         LyricsView(vm: ViewModel(),
  47.                    songName: "",
  48.                    artistName: "",
  49.                    arrLyrics: ""
  50.         )
  51.     }
  52. }
  53.  
  54. class ViewModel : ObservableObject {
  55.     @Published var searchedSongs = [SongDetails]() {
  56.         didSet {
  57.             print(searchedSongs)
  58.         }
  59.     }
  60.     @Published var apiResponse : APIResponse?
  61.     @Published var noConnectionAlert = false
  62.     var apiError: APIError? {
  63.         didSet {
  64.             noConnectionAlert = true
  65.         }
  66.     }
  67.  
  68.     func loadApiSongData(songName: String, artistName: String) {
  69.         let rawUrl = "https://api.lyrics.ovh/v1/\(artistName)/\(songName)"
  70.         let fixedUrl = rawUrl.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
  71.         print("Old url: \(rawUrl)")
  72.         print("New url: \(fixedUrl!)")
  73.        
  74.         guard let url = URL(string: fixedUrl!) else {
  75.             print("Invalid URL")
  76.             return
  77.         }
  78.        
  79.         let request = URLRequest(url: url)
  80.        
  81.         URLSession.shared.dataTask(with: request) { data, response, error in
  82.             DispatchQueue.main.async {
  83.                 self.responseHandler(data, response, error, songName, artistName)
  84.             }
  85.            
  86.         }.resume()
  87.     }
  88.    
  89.     private func responseHandler(_ data: Data?,
  90.                          _ response: URLResponse?,
  91.                          _ error: Error?,
  92.                          _ songName: String,
  93.                          _ artistName: String) {
  94.         if let error = error {
  95.             if error._code == -1009 {
  96.                 apiError = .offline
  97.             } else {
  98.                 apiError = .sessionError
  99.             }
  100.             return
  101.         }
  102.         guard let response = response as? HTTPURLResponse, let data = data else {
  103.             apiError = .missingDataError
  104.             return
  105.         }
  106.         guard (200..<300).contains(response.statusCode) else {
  107.             switch Status(rawValue: response.statusCode) {
  108.             case .requestTimeout:
  109.                 apiError = .timeoutError
  110.             case .internalServerError:
  111.                 apiError = .internalServerError
  112.             case .notFound:
  113.                 apiError = .notFound
  114.             default:
  115.                 apiError = .requestError
  116.             }
  117.            
  118.             return
  119.         }
  120.         do {
  121.             let decodedResponse = try JSONDecoder().decode(Song.self, from: data)
  122.             if(!songAlreadySearched(songName: songName)) {
  123.                 let song = SongDetails(songName: songName, artistName: artistName, lyrics: decodedResponse.lyrics)
  124.                 searchedSongs.append(song)
  125.             }
  126.             apiResponse = APIResponse(apiValues: decodedResponse.lyrics)
  127.            
  128.         } catch {
  129.             apiError = .parsingError
  130.         }
  131.     }
  132.    
  133.     func songAlreadySearched(songName: String) -> Bool {
  134.         return false
  135.     }
  136. }
  137.  
  138. struct SongDetails: Decodable {
  139.     var songName: String
  140.     var artistName: String
  141.     var lyrics: String
  142. }
  143.  
  144. struct Song: Decodable {
  145.     var lyrics: String
  146. }
  147. struct APIResponse: Identifiable {
  148.     var id: String = UUID().uuidString
  149.    
  150.     var apiValues: String
  151. }
  152.  
  153. enum APIError: Error {
  154.     case sessionError
  155.     case parsingError
  156.     case missingDataError
  157.     case requestError
  158.     case timeoutError
  159.     case offline
  160.     case internalServerError
  161.     case notFound
  162.     case genericError
  163. }
  164. enum Status: Int {
  165.     case multipleChoices = 300
  166.     case badRequest = 400
  167.     case forbidden = 403
  168.     case notFound = 404
  169.     case requestTimeout = 408
  170.     case internalServerError = 500
  171.     case notImplemented = 501
  172.     case badGateway = 502
  173.     case serviceUnavailabe = 503
  174.     case gatewayTimeout = 504
  175. }
  176.  
Advertisement
Add Comment
Please, Sign In to add comment