// // PetListViewController.swift // VenusKitto // // Created by Neoa on 2025/8/25. // import Foundation import UIKit struct Pet: Codable { let id: String let name: String let avatar: String let breedName: String let age: String } struct PetListResponse: Codable { let code: String let msg: String? let data: [Pet] } class PetListViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { private var pets: [Pet] = [] var onPetSelected: ((Pet) -> Void)? func reloadPetList() { tableView.reloadData() } private let tableView = UITableView() private var selectedPet: Pet? override func viewDidLoad() { super.viewDidLoad() // Set up table view tableView.delegate = self tableView.dataSource = self tableView.register(PetTableViewCell.self, forCellReuseIdentifier: "PetCell") view.addSubview(tableView) tableView.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ tableView.topAnchor.constraint(equalTo: view.topAnchor), tableView.leftAnchor.constraint(equalTo: view.leftAnchor), tableView.rightAnchor.constraint(equalTo: view.rightAnchor), tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor) ]) fetchPetList() // Request pet list } // Table view data source func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return pets.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let pet = pets[indexPath.row] let cell = tableView.dequeueReusableCell(withIdentifier: "PetCell", for: indexPath) as! PetTableViewCell cell.configure(with: pet) return cell } // Table view delegate func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let selectedPet = pets[indexPath.row] onPetSelected?(selectedPet) self.dismiss(animated: true) // Handle switching pet or showing more details } func fetchPetList() { // Get userId from UserDefaults guard let userId = UserDefaults.standard.string(forKey: "userId"), !userId.isEmpty else { print("⚠️ fetchPetList: userId missing or empty in UserDefaults") return } // Build URL with query parameter var components = URLComponents(string: "\(baseURL)/petRecordPet/queryPetList") components?.queryItems = [URLQueryItem(name: "userId", value: userId)] guard let url = components?.url else { print("⚠️ fetchPetList: Failed to build URL with userId param") return } print("🐾 fetchPetList URL: \(url.absoluteString)") var request = URLRequest(url: url) request.httpMethod = "GET" request.setValue("application/json", forHTTPHeaderField: "Content-Type") if let token = UserDefaults.standard.string(forKey: "userToken") { request.setValue(token, forHTTPHeaderField: "Authorization") } let task = URLSession.shared.dataTask(with: request) { [weak self] data, response, error in if let httpResp = response as? HTTPURLResponse { print("🐾 fetchPetList HTTP status: \(httpResp.statusCode)") } if let error = error { print("Error: \(error)") return } guard let data = data else { return } do { let decoder = JSONDecoder() let responseObject = try decoder.decode(PetListResponse.self, from: data) if responseObject.code == "200" { self?.pets = responseObject.data DispatchQueue.main.async { self?.reloadPetList() } } else { print("Error: \(responseObject.msg ?? "Unknown error")") } } catch { print("Error decoding response: \(error)") } } task.resume() } } class PetTableViewCell: UITableViewCell { private let avatarImageView = UIImageView() private let nameLabel = UILabel() override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) avatarImageView.contentMode = .scaleAspectFill avatarImageView.layer.cornerRadius = 24 avatarImageView.clipsToBounds = true contentView.addSubview(avatarImageView) nameLabel.font = .systemFont(ofSize: 16) contentView.addSubview(nameLabel) avatarImageView.translatesAutoresizingMaskIntoConstraints = false nameLabel.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ avatarImageView.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 16), avatarImageView.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), avatarImageView.widthAnchor.constraint(equalToConstant: 48), avatarImageView.heightAnchor.constraint(equalToConstant: 48), nameLabel.leftAnchor.constraint(equalTo: avatarImageView.rightAnchor, constant: 16), nameLabel.centerYAnchor.constraint(equalTo: contentView.centerYAnchor) ]) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } func configure(with pet: Pet) { nameLabel.text = pet.name if let url = URL(string: pet.avatar) { loadImage(from: url) } } private func loadImage(from url: URL) { // Create a data task to load the image URLSession.shared.dataTask(with: url) { [weak self] data, response, error in // Check for errors if let error = error { print("Error loading image: \(error)") return } // Check if data is valid guard let data = data else { print("No data returned") return } // Update the image on the main thread DispatchQueue.main.async { if let image = UIImage(data: data) { self?.avatarImageView.image = image } } }.resume() // Start the download } }