Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Bucket
uuid = "273B8391-36D9-4E32-9A15-1C54AC963890"
type = "1"
version = "2.0">
</Bucket>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>SchemeUserState</key>
<dict>
<key>Assignment.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>0</integer>
</dict>
</dict>
</dict>
</plist>
43 changes: 32 additions & 11 deletions Assignment/api/ApiService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,48 @@

import Foundation

class ApiService : NSObject {
class ApiService {
private let baseUrl = ""

private let sourcesURL = URL(string: "https://api.restful-api.dev/objects")!

func fetchDeviceDetails(completion : @escaping ([DeviceData]) -> ()){
URLSession.shared.dataTask(with: sourcesURL) { (data, urlResponse, error) in
func fetchDeviceDetails(completion : @escaping (Result<[DeviceData], Error>) -> Void) {
URLSession.shared.dataTask(with: sourcesURL) { data, response, error in
if let error = error {
print("Network error: \(error.localizedDescription)")
completion([]) // Return an empty array on network failure
DispatchQueue.main.async{
completion(.failure(error))
}
// Return an empty array on network failure
return
}

if let data = data {
let jsonDecoder = JSONDecoder()
let empData = try! jsonDecoder.decode([DeviceData].self, from: data)
if (empData.isEmpty) {
completion([])
// Error

guard let data = data else {
DispatchQueue.main.async{
completion(.success([]))

}
return
}
do {
let devices = try JSONDecoder().decode([DeviceData].self, from: data)
DispatchQueue.main.async{
completion(.success(devices))
}
} catch{
print("decode error")
DispatchQueue.main.async{
completion(.failure(error))
// let jsonDecoder = JSONDecoder()
// let empData = try! jsonDecoder.decode([DeviceData].self, from: data)
// if (empData.isEmpty) {
// completion([])
// // Error
// }}
}
}
}.resume()
} .resume()

}
}
65 changes: 51 additions & 14 deletions Assignment/ui/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,15 @@

import UIKit

class ContentViewController: UIViewController {
class ContentViewController: UIViewController{



private let viewModel = ContentViewModel()
private var devices: [DeviceData] = []
private var filteredDevices: [DeviceData] = []
private var tableView: UITableView!
private let searchController = UISearchController(searchResultsController: nil)
private var activityIndicator: UIActivityIndicatorView!

override func viewDidLoad() {
Expand All @@ -38,46 +42,79 @@ class ContentViewController: UIViewController {
activityIndicator.center = self.view.center
activityIndicator.hidesWhenStopped = true
view.addSubview(activityIndicator)

//api data fetch
setupSearchBar()
fetchData()

navigationItem.title = "Computers"
view.backgroundColor = .white

}

func fetchData() {
activityIndicator.startAnimating()

DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
if let data = self.viewModel.data {
self.devices = data
self.tableView.reloadData()
}
self.activityIndicator.stopAnimating()
//
// DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
// if let data = self.viewModel.data {
// self.devices = data
// print(data)
//
// self.tableView.reloadData()
// }
viewModel.fetchDevices{ [weak self] devices in
guard let self = self else { return}
self.devices = devices
self.tableView.reloadData()
self.activityIndicator.stopAnimating()
self.tableView.isHidden = false
}
}
private var isFiltering:Bool{
searchController.isActive &&
!(searchController.searchBar.text?.isEmpty ?? true)
}
private func setupSearchBar(){
searchController.searchResultsUpdater = self
searchController.obscuresBackgroundDuringPresentation = false
searchController.searchBar.placeholder = "Search Devices"
navigationItem.searchController = searchController
navigationItem.hidesSearchBarWhenScrolling = false
definesPresentationContext = true
}
}

extension ContentViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return devices.count
return isFiltering ? filteredDevices.count: devices.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "DeviceCell", for: indexPath)
let device = devices[indexPath.row]
let device = isFiltering ? filteredDevices[indexPath.row]
:devices[indexPath.row]
cell.textLabel?.text = device.name
return cell
}

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let selectedDevice = devices[indexPath.row]
_ = DetailViewController(device: selectedDevice)
let device = isFiltering ? filteredDevices[indexPath.row]
:devices[indexPath.row]
let detailVC = DetailViewController(device: device)
navigationController?.pushViewController(detailVC, animated: true)

}
}


extension ContentViewController: UISearchResultsUpdating{
func updateSearchResults(for searchController: UISearchController) {
let searchText = searchController.searchBar.text ?? ""
filteredDevices = devices.filter{
$0.name.lowercased().contains(searchText.lowercased())
}
tableView.reloadData()

}
}



31 changes: 20 additions & 11 deletions Assignment/vm/ContentViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,28 @@
import Foundation


class ContentViewModel : ObservableObject {
class ContentViewModel {

private let apiService = ApiService()
@Published var navigateDetail: DeviceData? = nil
var data: [DeviceData]? = []
// @Published var navigateDetail: DeviceData? = nil
// var data: [DeviceData]? = []
private var devices: [DeviceData] = []

func fetchAPI() {
apiService.fetchDeviceDetails(completion: { item in
self.data = item
})
}

func navigateToDetail(navigateDetail: DeviceData) {
self.navigateDetail = navigateDetail
func fetchDevices(completion:@escaping ([DeviceData]) -> Void){
apiService.fetchDeviceDetails{ result in
switch result {
case.success(let devices):
completion(devices)
case .failure(let error):
print("error",error.localizedDescription)
completion([])
}
}
}
}
}

// func navigateToDetail(navigateDetail: DeviceData) {
// self.navigateDetail = navigateDetail
// }