Skip to content

Commit 3262ccf

Browse files
committed
add logic for saving favorite animals
1 parent fe00c5e commit 3262ccf

8 files changed

Lines changed: 167 additions & 42 deletions

File tree

AnimalsApp/AnimalsApp.xcodeproj/project.pbxproj.orig

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,12 @@
3535
A463D071285A373800929A3C /* Animals.swift in Sources */ = {isa = PBXBuildFile; fileRef = A463D070285A373700929A3C /* Animals.swift */; };
3636
A463D074285A398900929A3C /* HomeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A463D073285A398900929A3C /* HomeViewModel.swift */; };
3737
A463D078285A5A8000929A3C /* OpenSans-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = A463D077285A5A8000929A3C /* OpenSans-Regular.ttf */; };
38+
<<<<<<< HEAD
39+
A463D07C285B9B6300929A3C /* CoreData.swift in Sources */ = {isa = PBXBuildFile; fileRef = A463D07B285B9B6300929A3C /* CoreData.swift */; };
40+
=======
3841
A463D07A285B8D8E00929A3C /* Colors.swift in Sources */ = {isa = PBXBuildFile; fileRef = A463D079285B8D8D00929A3C /* Colors.swift */; };
42+
A463D07E285CF28200929A3C /* String.swift in Sources */ = {isa = PBXBuildFile; fileRef = A463D07D285CF28200929A3C /* String.swift */; };
43+
>>>>>>> develop
3944
/* End PBXBuildFile section */
4045

4146
/* Begin PBXContainerItemProxy section */
@@ -94,7 +99,12 @@
9499
A463D070285A373700929A3C /* Animals.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Animals.swift; sourceTree = "<group>"; };
95100
A463D073285A398900929A3C /* HomeViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeViewModel.swift; sourceTree = "<group>"; };
96101
A463D077285A5A8000929A3C /* OpenSans-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "OpenSans-Regular.ttf"; sourceTree = "<group>"; };
102+
<<<<<<< HEAD
103+
A463D07B285B9B6300929A3C /* CoreData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreData.swift; sourceTree = "<group>"; };
104+
=======
97105
A463D079285B8D8D00929A3C /* Colors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Colors.swift; sourceTree = "<group>"; };
106+
A463D07D285CF28200929A3C /* String.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = String.swift; sourceTree = "<group>"; };
107+
>>>>>>> develop
98108
/* End PBXFileReference section */
99109

100110
/* Begin PBXFrameworksBuildPhase section */
@@ -173,7 +183,6 @@
173183
A463D0222858EBBD00929A3C /* Assets.xcassets */,
174184
A463D0242858EBBD00929A3C /* LaunchScreen.storyboard */,
175185
A463D0272858EBBD00929A3C /* Info.plist */,
176-
A463D01F2858EBBB00929A3C /* AnimalsApp.xcdatamodeld */,
177186
);
178187
path = AnimalsApp;
179188
sourceTree = "<group>";
@@ -249,6 +258,7 @@
249258
children = (
250259
A463D06128590D0300929A3C /* Images.swift */,
251260
A463D079285B8D8D00929A3C /* Colors.swift */,
261+
A463D07D285CF28200929A3C /* String.swift */,
252262
);
253263
path = DesignSystem;
254264
sourceTree = "<group>";
@@ -257,6 +267,7 @@
257267
isa = PBXGroup;
258268
children = (
259269
A463D068285A1A5A00929A3C /* WebServices.swift */,
270+
A463D07B285B9B6300929A3C /* CoreData.swift */,
260271
);
261272
path = Services;
262273
sourceTree = "<group>";
@@ -273,6 +284,7 @@
273284
A463D06F285A371F00929A3C /* Models */ = {
274285
isa = PBXGroup;
275286
children = (
287+
A463D01F2858EBBB00929A3C /* AnimalsApp.xcdatamodeld */,
276288
A463D070285A373700929A3C /* Animals.swift */,
277289
);
278290
path = Models;
@@ -560,20 +572,19 @@
560572
buildActionMask = 2147483647;
561573
files = (
562574
A463D06228590D0300929A3C /* Images.swift in Sources */,
575+
A463D07C285B9B6300929A3C /* CoreData.swift in Sources */,
563576
A463D065285953F900929A3C /* AnimalTableViewCell.swift in Sources */,
564577
A463D0212858EBBB00929A3C /* AnimalsApp.xcdatamodeld in Sources */,
565578
A463D0572858F62600929A3C /* RegisterViewController.swift in Sources */,
566579
A463D0172858EBBB00929A3C /* AppDelegate.swift in Sources */,
567580
A463D071285A373800929A3C /* Animals.swift in Sources */,
568581
A463D04B2858F39000929A3C /* MainTabBarController.swift in Sources */,
569582
A463D074285A398900929A3C /* HomeViewModel.swift in Sources */,
570-
<<<<<<< HEAD
571583
A463D07A285B8D8E00929A3C /* Colors.swift in Sources */,
572-
=======
573584
5CA996F8285A98FB00FF5D79 /* RegisterViewModel.swift in Sources */,
574-
>>>>>>> develop
575585
A463D05D2858F64B00929A3C /* FavoritesViewController.swift in Sources */,
576586
A463D06D285A22D200929A3C /* DetailViewController.swift in Sources */,
587+
A463D07E285CF28200929A3C /* String.swift in Sources */,
577588
A463D069285A1A5A00929A3C /* WebServices.swift in Sources */,
578589
A463D0532858F60C00929A3C /* HomeViewController.swift in Sources */,
579590
);
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
//
2+
// Items.swift
3+
// AnimalsApp
4+
//
5+
// Created by Laura Pinheiro Marson on 15/06/22.
6+
//
7+
8+
import Foundation
9+
10+
struct Animals: Codable {
11+
var items: [Animal]
12+
}
13+
14+
struct Animal: Codable {
15+
var id: String?
16+
var name: String?
17+
var description: String?
18+
var age: Int?
19+
var species: String?
20+
var image: String?
21+
var createdAt: String?
22+
var updatedAt: String?
23+
var isFavorite: Bool? = false
24+
<<<<<<< HEAD
25+
var imageData: Data?
26+
=======
27+
28+
enum CodingKeys: String, CodingKey {
29+
case id
30+
case name
31+
case description
32+
case age
33+
case species
34+
case image
35+
case createdAt = "created_at"
36+
case updatedAt = "updated_at"
37+
}
38+
>>>>>>> develop
39+
}
40+
41+
extension Animal {
42+
43+
var imageURL: URL {
44+
guard let imageURL = URL(string: self.image ?? "") else {
45+
return URL(fileURLWithPath: "")
46+
}
47+
return imageURL
48+
}
49+
}

AnimalsApp/AnimalsApp/Services/CoreData.swift

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,15 @@
88
import UIKit
99
import CoreData
1010

11-
class CoreData {
11+
protocol CoreDataContract: AnyObject {
12+
func loadFavoriteAnimals(completion: @escaping () -> ())
13+
func isFavorite(id: String) -> Bool
14+
func addFavorite(_ animal: Animal)
15+
func removeFavorite(id: String)
16+
func saveChanges()
17+
}
18+
19+
class CoreData: CoreDataContract {
1220
var managedContext: NSManagedObjectContext?
1321
var favoriteAnimals = [FavoriteAnimal]()
1422

@@ -58,17 +66,18 @@ class CoreData {
5866
func removeFavorite(id: String) {
5967

6068
guard let managedContext = managedContext else { return }
61-
62-
var removeAnimal = FavoriteAnimal()
63-
64-
for (index, animal) in favoriteAnimals.enumerated() {
69+
70+
var count = 0
71+
72+
for animal in favoriteAnimals {
6573
if animal.id == id {
66-
removeAnimal = animal
67-
favoriteAnimals.remove(at: index)
74+
let removeAnimal = animal
75+
favoriteAnimals.remove(at: count)
76+
managedContext.delete(removeAnimal)
6877
}
78+
count += 1
6979
}
70-
71-
managedContext.delete(removeAnimal)
80+
7281
}
7382

7483
func saveChanges() {

AnimalsApp/AnimalsApp/View Models/HomeViewModel.swift

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@ import Foundation
99

1010
class HomeViewModel {
1111
private var webServices: WebServicesContract
12+
private var coreData: CoreDataContract
1213
var animals = [Animal]()
1314

14-
init(webServices: WebServicesContract = WebServices()) {
15+
init(webServices: WebServicesContract = WebServices(), coreData: CoreDataContract = CoreData()) {
1516
self.webServices = webServices
17+
self.coreData = coreData
1618
}
1719

1820
func numberOfRows() -> Int {
@@ -28,6 +30,7 @@ class HomeViewModel {
2830
switch result {
2931
case .success(let animals):
3032
self?.handleAnimalResponse(with: animals)
33+
self?.setFavorite()
3134
case .failure(let error):
3235
//obs criar alerta
3336
print(error.localizedDescription)
@@ -45,4 +48,33 @@ class HomeViewModel {
4548
return false
4649
}
4750
}
51+
52+
//MARK: Core Data Methods
53+
54+
private func setFavorite() {
55+
for (index, animal) in animals.enumerated() {
56+
guard let id = animal.id else { return }
57+
animals[index].isFavorite = coreData.isFavorite(id: id)
58+
}
59+
}
60+
61+
func addOrRemoveFavorite(at index: Int, with image: Data) {
62+
animals[index].imageData = image
63+
64+
guard let isFavorite = animals[index].isFavorite,
65+
let id = animals[index].id else { return }
66+
isFavorite ? coreData.removeFavorite(id: id) : coreData.addFavorite(animals[index])
67+
68+
animals[index].isFavorite = !isFavorite
69+
}
70+
71+
func loadFavorites(completion: @escaping () -> ()) {
72+
coreData.loadFavoriteAnimals {
73+
completion()
74+
}
75+
}
76+
77+
func saveChangesInCoreData() {
78+
coreData.saveChanges()
79+
}
4880
}

AnimalsApp/AnimalsApp/Views/Components/AnimalTableViewCell.swift

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,26 +8,20 @@
88
import UIKit
99
import SDWebImage
1010

11+
protocol ActionDelegateProtocol: AnyObject {
12+
func favoriteButtonTapped(at index: Int, with image: Data)
13+
}
14+
1115
class AnimalTableViewCell: UITableViewCell {
16+
weak var delegate: ActionDelegateProtocol?
17+
var animal: Animal?
18+
var index: Int?
1219

1320
@IBOutlet weak var animalImage: UIImageView!
1421
@IBOutlet weak var nameLabel: UILabel!
1522
@IBOutlet weak var descriptionLabel: UILabel!
1623
@IBOutlet weak var favoriteButton: UIButton!
1724

18-
var animal: Animal?
19-
20-
// var isFavorite: Bool? {
21-
// didSet {
22-
// guard let isFavorite = isFavorite else { return }
23-
// if isFavorite {
24-
// favoriteButton.imageView?.image = .favorite
25-
// } else {
26-
// favoriteButton.imageView?.image = .notFavorite
27-
// }
28-
// }
29-
// }
30-
3125
override func awakeFromNib() {
3226
super.awakeFromNib()
3327
// Initialization code
@@ -55,21 +49,23 @@ class AnimalTableViewCell: UITableViewCell {
5549

5650
animalImage.sd_setImage(with: imageURL, placeholderImage: placeholderImage)
5751

58-
if animal.isFavorite ?? false {
59-
favoriteButton.setImage(.favorite, for: .normal)
60-
} else {
61-
favoriteButton.setImage(.notFavorite, for: .normal)
62-
}
52+
animal.isFavorite ?? false ? favoriteButton.setImage(.favorite, for: .normal) : favoriteButton.setImage(.notFavorite, for: .normal)
6353
}
6454

6555
@IBAction func favoritePressed(_ sender: UIButton) {
6656
guard let animal = animal else { return }
6757

6858
if animal.isFavorite ?? false {
6959
sender.setImage(.notFavorite, for: .normal)
60+
self.animal?.isFavorite = false
7061
} else {
7162
sender.setImage(.favorite, for: .normal)
63+
self.animal?.isFavorite = true
64+
}
65+
66+
if let index = index, let image = SDImageCache.shared.imageFromDiskCache(forKey: animal.imageURL.absoluteString) {
67+
let imageData = image.jpegData(compressionQuality: 0.9)
68+
delegate?.favoriteButtonTapped(at: index, with: imageData ?? Data())
7269
}
7370
}
74-
7571
}

AnimalsApp/AnimalsApp/Views/Components/AnimalTableViewCell.xib

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@
3636
<constraint firstAttribute="height" constant="40" id="7rZ-bg-lFP"/>
3737
<constraint firstAttribute="width" constant="40" id="i65-df-ED5"/>
3838
</constraints>
39-
<state key="normal" image="addFavorite"/>
4039
<connections>
4140
<action selector="favoritePressed:" destination="KGk-i7-Jjw" eventType="touchUpInside" id="X9N-Mv-iRU"/>
4241
</connections>
@@ -81,13 +80,12 @@
8180
</tableViewCell>
8281
</objects>
8382
<resources>
84-
<image name="addFavorite" width="22.5" height="21.5"/>
8583
<image name="imagePlaceholder" width="300" height="300"/>
8684
<namedColor name="blueTextColor">
8785
<color red="0.082000002264976501" green="0.54500001668930054" blue="0.74900001287460327" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
8886
</namedColor>
8987
<namedColor name="grayTextColor">
90-
<color red="0.40000000596046448" green="0.40000000596046448" blue="0.40000000596046448" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
88+
<color red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
9189
</namedColor>
9290
</resources>
9391
</document>

AnimalsApp/AnimalsApp/Views/HomeViewController/HomeViewController.swift

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,28 @@ class HomeViewController: UIViewController {
2727
tableView.register(UINib(nibName: "AnimalTableViewCell", bundle: nil), forCellReuseIdentifier: "Animal")
2828

2929
setNavigationItems()
30+
homeVM.loadFavorites { [weak self] in
31+
self?.populateTableView()
32+
}
3033

3134
let refreshControl = UIRefreshControl()
3235
refreshControl.addTarget(self, action: #selector(reloadAnimals), for: .valueChanged)
3336
tableView.refreshControl = refreshControl
37+
38+
let notificationCenter = NotificationCenter.default
39+
notificationCenter.addObserver(self, selector: #selector(saveChanges), name: UIApplication.willResignActiveNotification, object: nil)
3440
}
3541

3642
override func viewWillAppear(_ animated: Bool) {
43+
super.viewWillAppear(animated)
3744
populateTableView()
3845
}
3946

47+
override func viewDidDisappear(_ animated: Bool) {
48+
super.viewDidDisappear(animated)
49+
homeVM.saveChangesInCoreData()
50+
}
51+
4052
// MARK: Methods
4153
private func setNavigationItems() {
4254
title = "Home"
@@ -66,6 +78,11 @@ class HomeViewController: UIViewController {
6678
populateTableView()
6779
refreshControl.endRefreshing()
6880
}
81+
82+
@objc
83+
private func saveChanges() {
84+
homeVM.saveChangesInCoreData()
85+
}
6986
}
7087

7188
// MARK: TableView Data Source
@@ -81,6 +98,8 @@ extension HomeViewController: UITableViewDataSource {
8198
}
8299

83100
cell.animal = homeVM.modelAt(indexPath.row)
101+
cell.index = indexPath.row
102+
cell.delegate = self
84103
cell.configure()
85104

86105
return cell
@@ -102,3 +121,10 @@ extension HomeViewController: UITableViewDelegate {
102121
}
103122

104123
}
124+
125+
// MARK: Action Delegate Protocol
126+
extension HomeViewController: ActionDelegateProtocol {
127+
func favoriteButtonTapped(at index: Int, with image: Data) {
128+
homeVM.addOrRemoveFavorite(at: index, with: image)
129+
}
130+
}

0 commit comments

Comments
 (0)