Skip to content

Commit f44bc4a

Browse files
committed
fixing architecture
1 parent c40cfb8 commit f44bc4a

File tree

7 files changed

+157
-116
lines changed

7 files changed

+157
-116
lines changed

firestore/FirestoreExample.xcodeproj/project.pbxproj

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@
3333
8E4C635725EDD58F001678A1 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 8E4C635625EDD58F001678A1 /* GoogleService-Info.plist */; };
3434
8E4C637825EEF4CA001678A1 /* RestaurantListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8E4C637725EEF4CA001678A1 /* RestaurantListViewModel.swift */; };
3535
8E4C63B225F05E76001678A1 /* StarsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8E4C63B125F05E76001678A1 /* StarsView.swift */; };
36+
8E4C63D825F6D641001678A1 /* Firestore+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8E4C63D725F6D641001678A1 /* Firestore+Extension.swift */; };
37+
8E4C63DE25F6D879001678A1 /* ImageThumbnailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8E4C63DD25F6D879001678A1 /* ImageThumbnailView.swift */; };
38+
8E4C63E425F6D8C8001678A1 /* PriceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8E4C63E325F6D8C8001678A1 /* PriceView.swift */; };
3639
928F7382D38D4F9DB48A15EF /* Pods_FirestoreExample.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 541C1C9953818121C760549F /* Pods_FirestoreExample.framework */; };
3740
DE8564AE23AFBF8000611383 /* FirestoreUITest.m in Sources */ = {isa = PBXBuildFile; fileRef = DE8564AD23AFBF8000611383 /* FirestoreUITest.m */; };
3841
DE8564B423AFBFA700611383 /* FIREGSignInHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = DE8564B123AFBFA700611383 /* FIREGSignInHelper.m */; };
@@ -96,6 +99,9 @@
9699
8E4C635625EDD58F001678A1 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "../../../FolderForGoogleService-Info/GoogleService-Info.plist"; sourceTree = "<group>"; };
97100
8E4C637725EEF4CA001678A1 /* RestaurantListViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RestaurantListViewModel.swift; sourceTree = "<group>"; };
98101
8E4C63B125F05E76001678A1 /* StarsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StarsView.swift; sourceTree = "<group>"; };
102+
8E4C63D725F6D641001678A1 /* Firestore+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Firestore+Extension.swift"; sourceTree = "<group>"; };
103+
8E4C63DD25F6D879001678A1 /* ImageThumbnailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageThumbnailView.swift; sourceTree = "<group>"; };
104+
8E4C63E325F6D8C8001678A1 /* PriceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PriceView.swift; sourceTree = "<group>"; };
99105
B1197C1340BA7906456ECA9D /* Pods_FirestoreSwiftUIExample.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_FirestoreSwiftUIExample.framework; sourceTree = BUILT_PRODUCTS_DIR; };
100106
D3859CC2659F6A304C12A137 /* Pods-FirestoreExample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FirestoreExample.release.xcconfig"; path = "Target Support Files/Pods-FirestoreExample/Pods-FirestoreExample.release.xcconfig"; sourceTree = "<group>"; };
101107
DE8564AC23AFBF8000611383 /* FirestoreExampleUITests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "FirestoreExampleUITests-Bridging-Header.h"; sourceTree = "<group>"; };
@@ -232,6 +238,7 @@
232238
8E4C62D925E9CFE1001678A1 /* Info.plist */,
233239
8E4C635625EDD58F001678A1 /* GoogleService-Info.plist */,
234240
8E4C62D625E9CFE1001678A1 /* Preview Content */,
241+
8E4C63D725F6D641001678A1 /* Firestore+Extension.swift */,
235242
);
236243
path = FirestoreSwiftUIExample;
237244
sourceTree = "<group>";
@@ -250,6 +257,8 @@
250257
8E4C62D225E9CFE0001678A1 /* ContentView.swift */,
251258
8E4C62E625E9D191001678A1 /* RestaurantItemView.swift */,
252259
8E4C63B125F05E76001678A1 /* StarsView.swift */,
260+
8E4C63DD25F6D879001678A1 /* ImageThumbnailView.swift */,
261+
8E4C63E325F6D8C8001678A1 /* PriceView.swift */,
253262
);
254263
path = Views;
255264
sourceTree = "<group>";
@@ -700,7 +709,10 @@
700709
8E4C637825EEF4CA001678A1 /* RestaurantListViewModel.swift in Sources */,
701710
8E4C62D125E9CFE0001678A1 /* FirestoreSwiftUIExampleApp.swift in Sources */,
702711
8E4C63B225F05E76001678A1 /* StarsView.swift in Sources */,
712+
8E4C63E425F6D8C8001678A1 /* PriceView.swift in Sources */,
713+
8E4C63DE25F6D879001678A1 /* ImageThumbnailView.swift in Sources */,
703714
8E4C62E725E9D191001678A1 /* RestaurantItemView.swift in Sources */,
715+
8E4C63D825F6D641001678A1 /* Firestore+Extension.swift in Sources */,
704716
);
705717
runOnlyForDeploymentPostprocessing = 0;
706718
};
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
//
2+
// Firestore+Extension.swift
3+
// FirestoreSwiftUIExample
4+
//
5+
6+
import Firebase
7+
8+
extension Firestore {
9+
func populate() {
10+
let words = ["Bar", "Fire", "Grill", "Drive Thru", "Place", "Best", "Spot", "Prime", "Eatin'"]
11+
12+
let cities = Restaurant.cities
13+
let categories = Restaurant.categories
14+
15+
for _ in 0 ..< 20 {
16+
let randomIndexes = (Int(arc4random_uniform(UInt32(words.count))),
17+
Int(arc4random_uniform(UInt32(words.count))))
18+
let name = words[randomIndexes.0] + " " + words[randomIndexes.1]
19+
let category = categories[Int(arc4random_uniform(UInt32(categories.count)))]
20+
let city = cities[Int(arc4random_uniform(UInt32(cities.count)))]
21+
let price = Int(arc4random_uniform(3)) + 1
22+
let photo = Restaurant.imageURL(forName: name)
23+
24+
// Basic writes
25+
26+
let collection = self.collection("restaurants")
27+
28+
let restaurant = Restaurant(
29+
name: name,
30+
category: category,
31+
city: city,
32+
price: price,
33+
ratingCount: 10,
34+
averageRating: 0,
35+
photo: photo
36+
)
37+
38+
let restaurantRef = collection.document()
39+
do {
40+
try restaurantRef.setData(from: restaurant)
41+
} catch {
42+
fatalError("Encoding Restaurant failed: \(error)")
43+
}
44+
45+
let batch = self.batch()
46+
//TODO: guard let user = Auth.auth().currentUser else { continue }
47+
var average: Float = 0
48+
for _ in 0 ..< 10 {
49+
let rating = Int(arc4random_uniform(5) + 1)
50+
average += Float(rating) / 10
51+
let text = rating > 3 ? "good" : "food was too spicy"
52+
53+
//TODO: userID: user.uid,
54+
//TODO: username: user.displayName ?? "Anonymous",
55+
let review = Review(
56+
rating: rating,
57+
userID: "1234567890",
58+
username: "Anonymous",
59+
text: text,
60+
date: Timestamp()
61+
)
62+
63+
let ratingRef = restaurantRef.collection("ratings").document()
64+
do {
65+
try batch.setData(from: review, forDocument: ratingRef)
66+
} catch {
67+
fatalError("Encoding Rating failed: \(error)")
68+
}
69+
}
70+
batch.updateData(["avgRating": average], forDocument: restaurantRef)
71+
batch.commit(completion: { (error) in
72+
guard let error = error else { return }
73+
print("Error generating reviews: \(error). Check your Firestore permissions.")
74+
})
75+
}
76+
}
77+
78+
}

firestore/FirestoreSwiftUIExample/ViewModels/RestaurantListViewModel.swift

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import Firebase
88

99
class RestaurantListViewModel: ObservableObject {
1010

11-
@Published var restaurants: [Restaurant] = []
11+
@Published var restaurants = [Restaurant]()
1212
private var db = Firestore.firestore()
1313

1414
func fetchData() {
@@ -19,8 +19,17 @@ class RestaurantListViewModel: ObservableObject {
1919
}
2020

2121
self.restaurants = querySnapshot?.documents.compactMap { document in
22-
try? document.data(as: Restaurant.self)
22+
do {
23+
return try document.data(as: Restaurant.self)
24+
} catch let error {
25+
print(error)
26+
return nil
27+
}
2328
} ?? []
2429
}
2530
}
31+
32+
func populate() {
33+
db.populate()
34+
}
2635
}

firestore/FirestoreSwiftUIExample/Views/ContentView.swift

Lines changed: 1 addition & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import SwiftUI
77
import Firebase
88

99
struct ContentView: View {
10-
let db = Firestore.firestore()
1110
@ObservedObject var restaurantListViewModel = RestaurantListViewModel()
1211

1312
var body: some View {
@@ -24,7 +23,7 @@ struct ContentView: View {
2423
.toolbar {
2524
ToolbarItem(placement: .navigationBarLeading) {
2625
Button("Populate") {
27-
populate()
26+
restaurantListViewModel.populate()
2827
}
2928
}
3029

@@ -36,75 +35,6 @@ struct ContentView: View {
3635
}
3736
}
3837
}
39-
40-
func populate() {
41-
let words = ["Bar", "Fire", "Grill", "Drive Thru", "Place", "Best", "Spot", "Prime", "Eatin'"]
42-
43-
let cities = Restaurant.cities
44-
let categories = Restaurant.categories
45-
46-
for _ in 0 ..< 20 {
47-
let randomIndexes = (Int(arc4random_uniform(UInt32(words.count))),
48-
Int(arc4random_uniform(UInt32(words.count))))
49-
let name = words[randomIndexes.0] + " " + words[randomIndexes.1]
50-
let category = categories[Int(arc4random_uniform(UInt32(categories.count)))]
51-
let city = cities[Int(arc4random_uniform(UInt32(cities.count)))]
52-
let price = Int(arc4random_uniform(3)) + 1
53-
let photo = Restaurant.imageURL(forName: name)
54-
55-
// Basic writes
56-
57-
let collection = db.collection("restaurants")
58-
59-
let restaurant = Restaurant(
60-
name: name,
61-
category: category,
62-
city: city,
63-
price: price,
64-
ratingCount: 10,
65-
averageRating: 0,
66-
photo: photo
67-
)
68-
69-
let restaurantRef = collection.document()
70-
do {
71-
try restaurantRef.setData(from: restaurant)
72-
} catch {
73-
fatalError("Encoding Restaurant failed: \(error)")
74-
}
75-
76-
let batch = db.batch()
77-
//TODO: guard let user = Auth.auth().currentUser else { continue }
78-
var average: Float = 0
79-
for _ in 0 ..< 10 {
80-
let rating = Int(arc4random_uniform(5) + 1)
81-
average += Float(rating) / 10
82-
let text = rating > 3 ? "good" : "food was too spicy"
83-
84-
//TODO: userID: user.uid,
85-
//TODO: username: user.displayName ?? "Anonymous",
86-
let review = Review(
87-
rating: rating,
88-
userID: "1234567890",
89-
username: "Anonymous",
90-
text: text,
91-
date: Timestamp()
92-
)
93-
94-
let ratingRef = restaurantRef.collection("ratings").document()
95-
do {
96-
try batch.setData(from: review, forDocument: ratingRef)
97-
} catch {
98-
fatalError("Encoding Rating failed: \(error)")
99-
}
100-
}
101-
batch.updateData(["avgRating": average], forDocument: restaurantRef)
102-
batch.commit(completion: { (error) in
103-
guard let error = error else { return }
104-
print("Error generating reviews: \(error). Check your Firestore permissions.")
105-
})
106-
}
107-
}
10838
}
10939

11040
struct RestaurantDetailView: View {
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//
2+
// ImageThumbnailView.swift
3+
// FirestoreSwiftUIExample
4+
//
5+
6+
import SwiftUI
7+
import SDWebImageSwiftUI
8+
9+
struct ImageThumbnailView: View {
10+
var imageURL: URL
11+
12+
var body: some View {
13+
WebImage(url: imageURL)
14+
.resizable()
15+
.placeholder(Image(systemName: "photo"))
16+
.aspectRatio(1, contentMode: .fill)
17+
.frame(width: 100, height: 100, alignment: .leading)
18+
}
19+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//
2+
// PriceView.swift
3+
// FirestoreSwiftUIExample
4+
//
5+
6+
import SwiftUI
7+
8+
struct PriceView: View {
9+
var price: Int
10+
11+
var body: some View {
12+
Text(priceString(from: price))
13+
.font(.footnote)
14+
.foregroundColor(Color.gray)
15+
.multilineTextAlignment(.trailing)
16+
}
17+
18+
func priceString(from price: Int) -> String {
19+
let priceText: String
20+
switch price {
21+
case 1:
22+
priceText = "$"
23+
case 2:
24+
priceText = "$$"
25+
case 3:
26+
priceText = "$$$"
27+
case _:
28+
fatalError("price must be between one and three")
29+
}
30+
31+
return priceText
32+
}
33+
}

firestore/FirestoreSwiftUIExample/Views/RestaurantItemView.swift

Lines changed: 3 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,19 @@
44
//
55

66
import SwiftUI
7-
import SDWebImageSwiftUI
87

98
struct RestaurantItemView: View {
109
var restaurant: Restaurant
1110

1211
var body: some View {
1312
HStack {
14-
ImageThumbnail(imageURL: restaurant.photo)
13+
ImageThumbnailView(imageURL: restaurant.photo)
1514
VStack(alignment: .leading) {
1615
HStack {
1716
Text(restaurant.name)
1817
.frame(alignment: .leading)
1918
Spacer()
20-
Price(price: restaurant.price)
19+
PriceView(price: restaurant.price)
2120
}
2221
StarsView(rating: Int(restaurant.averageRating.rounded()))
2322
Spacer()
@@ -36,46 +35,7 @@ struct RestaurantItemView: View {
3635

3736
struct RestaurantItemView_Previews: PreviewProvider {
3837
static var previews: some View {
39-
let data = Restaurant(id: .init(), name: "Pizza Place", category: "Pizza", city: "Austin", price: 2, ratingCount: 1, averageRating: 4, photo: Restaurant.imageURL(forName: "Place Place"))
38+
let data = Restaurant(id: .init(), name: "Pizza Place", category: "Pizza", city: "Austin", price: 2, ratingCount: 1, averageRating: 4, photo: Restaurant.imageURL(forName: "Pizza Place"))
4039
RestaurantItemView(restaurant: data)
4140
}
4241
}
43-
44-
struct ImageThumbnail: View {
45-
var imageURL: URL
46-
47-
var body: some View {
48-
WebImage(url: imageURL)
49-
.resizable()
50-
.placeholder(Image(systemName: "photo"))
51-
.aspectRatio(1, contentMode: .fill)
52-
.frame(width: 100, height: 100, alignment: .leading)
53-
}
54-
}
55-
56-
struct Price: View {
57-
var price: Int
58-
59-
var body: some View {
60-
Text(priceString(from: price))
61-
.font(.footnote)
62-
.foregroundColor(Color.gray)
63-
.multilineTextAlignment(.trailing)
64-
}
65-
66-
func priceString(from price: Int) -> String {
67-
let priceText: String
68-
switch price {
69-
case 1:
70-
priceText = "$"
71-
case 2:
72-
priceText = "$$"
73-
case 3:
74-
priceText = "$$$"
75-
case _:
76-
fatalError("price must be between one and three")
77-
}
78-
79-
return priceText
80-
}
81-
}

0 commit comments

Comments
 (0)