Skip to content

Commit 5a2d2b7

Browse files
authored
Merge pull request #23 from yale-swe/tracy_dev
Merge tracy_dev
2 parents 93e2e1e + 61389c5 commit 5a2d2b7

File tree

182 files changed

+321
-37
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

182 files changed

+321
-37
lines changed

app/newHere1/newHere.xcodeproj/project.pbxproj

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
7194CFD42B2153D30094BE56 /* PhotoLibraryManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7194CFD32B2153D30094BE56 /* PhotoLibraryManager.swift */; };
3030
7194CFD62B2153DA0094BE56 /* ScreenshotUtility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7194CFD52B2153DA0094BE56 /* ScreenshotUtility.swift */; };
3131
7194CFDC2B2154740094BE56 /* ShareSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7194CFDB2B2154740094BE56 /* ShareSheet.swift */; };
32+
7194CFE42B2367AA0094BE56 /* UserProfileViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7194CFE32B2367AA0094BE56 /* UserProfileViewModel.swift */; };
33+
7194CFE62B2367BE0094BE56 /* EditProfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7194CFE52B2367BE0094BE56 /* EditProfile.swift */; };
3234
71D79DA22B1570E4009A054C /* BubbleAnimation.atlas in Resources */ = {isa = PBXBuildFile; fileRef = 71D79DA12B1570E4009A054C /* BubbleAnimation.atlas */; };
3335
FE32AC982B159A650056B003 /* PostTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE32AC972B159A650056B003 /* PostTest.swift */; };
3436
FE32AC9A2B159A9E0056B003 /* MockMessageState.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE32AC992B159A9E0056B003 /* MockMessageState.swift */; };
@@ -89,6 +91,8 @@
8991
7194CFD32B2153D30094BE56 /* PhotoLibraryManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhotoLibraryManager.swift; sourceTree = "<group>"; };
9092
7194CFD52B2153DA0094BE56 /* ScreenshotUtility.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScreenshotUtility.swift; sourceTree = "<group>"; };
9193
7194CFDB2B2154740094BE56 /* ShareSheet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShareSheet.swift; sourceTree = "<group>"; };
94+
7194CFE32B2367AA0094BE56 /* UserProfileViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserProfileViewModel.swift; sourceTree = "<group>"; };
95+
7194CFE52B2367BE0094BE56 /* EditProfile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EditProfile.swift; sourceTree = "<group>"; };
9296
71D79DA12B1570E4009A054C /* BubbleAnimation.atlas */ = {isa = PBXFileReference; lastKnownFileType = folder.skatlas; path = BubbleAnimation.atlas; sourceTree = "<group>"; };
9397
FE32AC972B159A650056B003 /* PostTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = PostTest.swift; path = newHereTests/PostTest.swift; sourceTree = SOURCE_ROOT; };
9498
FE32AC992B159A9E0056B003 /* MockMessageState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockMessageState.swift; sourceTree = "<group>"; };
@@ -217,6 +221,7 @@
217221
71D79DA52B15758E009A054C /* Profile */ = {
218222
isa = PBXGroup;
219223
children = (
224+
7194CFE52B2367BE0094BE56 /* EditProfile.swift */,
220225
1531A90A2AED964A009F644E /* Profile.swift */,
221226
);
222227
path = Profile;
@@ -293,6 +298,7 @@
293298
71D79DAD2B1578F5009A054C /* Models */ = {
294299
isa = PBXGroup;
295300
children = (
301+
7194CFE32B2367AA0094BE56 /* UserProfileViewModel.swift */,
296302
1531A9122AEDAE2A009F644E /* LocationDataManager.swift */,
297303
);
298304
path = Models;
@@ -478,12 +484,14 @@
478484
1531A90D2AED9663009F644E /* Messages.swift in Sources */,
479485
158392302AFC72D3007A53C7 /* CustomARViewRepresentable.swift in Sources */,
480486
7194CFD42B2153D30094BE56 /* PhotoLibraryManager.swift in Sources */,
487+
7194CFE62B2367BE0094BE56 /* EditProfile.swift in Sources */,
481488
1531A90F2AED9917009F644E /* Post.swift in Sources */,
482489
1531A9152AEDCADB009F644E /* Message.swift in Sources */,
483490
1531A9092AED9618009F644E /* Home.swift in Sources */,
484491
158392332AFC72F3007A53C7 /* LoginView.swift in Sources */,
485492
158392312AFC72D3007A53C7 /* CustomARView.swift in Sources */,
486493
1531A8DE2AED95FD009F644E /* newHereApp.swift in Sources */,
494+
7194CFE42B2367AA0094BE56 /* UserProfileViewModel.swift in Sources */,
487495
);
488496
runOnlyForDeploymentPostprocessing = 0;
489497
};
@@ -668,7 +676,7 @@
668676
CODE_SIGN_STYLE = Automatic;
669677
CURRENT_PROJECT_VERSION = 1;
670678
DEVELOPMENT_ASSET_PATHS = "\"newHere/Preview Content\"";
671-
DEVELOPMENT_TEAM = A7X36A78B2;
679+
DEVELOPMENT_TEAM = W23Y365YR7;
672680
ENABLE_HARDENED_RUNTIME = YES;
673681
ENABLE_PREVIEWS = YES;
674682
GENERATE_INFOPLIST_FILE = YES;
@@ -713,7 +721,7 @@
713721
CODE_SIGN_STYLE = Automatic;
714722
CURRENT_PROJECT_VERSION = 1;
715723
DEVELOPMENT_ASSET_PATHS = "\"newHere/Preview Content\"";
716-
DEVELOPMENT_TEAM = A7X36A78B2;
724+
DEVELOPMENT_TEAM = W23Y365YR7;
717725
ENABLE_HARDENED_RUNTIME = YES;
718726
ENABLE_PREVIEWS = YES;
719727
GENERATE_INFOPLIST_FILE = YES;

app/newHere1/newHere/Assets.xcassets/AccentColor.colorset/Contents.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
11
{
22
"colors" : [
33
{
4+
"color" : {
5+
"color-space" : "srgb",
6+
"components" : {
7+
"alpha" : "1.000",
8+
"blue" : "1.000",
9+
"green" : "1.000",
10+
"red" : "1.000"
11+
}
12+
},
413
"idiom" : "universal"
514
}
615
],
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"colors" : [
3+
{
4+
"idiom" : "universal"
5+
},
6+
{
7+
"appearances" : [
8+
{
9+
"appearance" : "luminosity",
10+
"value" : "dark"
11+
}
12+
],
13+
"color" : {
14+
"color-space" : "srgb",
15+
"components" : {
16+
"alpha" : "1.000",
17+
"blue" : "1.000",
18+
"green" : "1.000",
19+
"red" : "1.000"
20+
}
21+
},
22+
"idiom" : "universal"
23+
}
24+
],
25+
"info" : {
26+
"author" : "xcode",
27+
"version" : 1
28+
}
29+
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//
2+
// UserProfileViewModel.swift
3+
// newHere
4+
//
5+
// Created by YIMING GUAN on 2023/12/7.
6+
//
7+
8+
import Foundation
9+
import SwiftUI
10+
11+
class UserProfileViewModel: ObservableObject {
12+
@Published var username: String = userName
13+
@Published var email: String = userEmail
14+
@Published var profileImage: UIImage? = nil
15+
// Add other profile properties here
16+
17+
// Implement methods to update these properties, for example, from an API
18+
}

app/newHere1/newHere/Utils/api_call.swift

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,13 @@ struct MessageResponse: Codable {
4848
let location: GeoJSONPoint
4949
}
5050

51+
//// Structure for updating user profile
52+
struct UpdateProfileRequest: Codable {
53+
let userName: String?
54+
let email: String?
55+
let avatar: String? // Assuming avatar is a string (URL or base64 encoded image)
56+
}
57+
5158
//// Structure for response of adding a friend
5259
struct AddFriendResponse: Codable {
5360
let message: String
@@ -74,6 +81,46 @@ struct UserMessage: Codable {
7481
let replies: [String]
7582
}
7683

84+
//// api call to update user profile
85+
func updateUserProfile(userId: String, userName: String?, email: String?, avatar: String?, completion: @escaping (Result<Bool, Error>) -> Void) {
86+
let urlString = "https://here-swe.vercel.app/user/\(userId)/update-profile" // Adjust URL as needed
87+
88+
guard let url = URL(string: urlString) else {
89+
completion(.failure(URLError(.badURL)))
90+
return
91+
}
92+
93+
var request = URLRequest(url: url)
94+
request.httpMethod = "PUT"
95+
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
96+
request.addValue(apiKey, forHTTPHeaderField: "X-API-Key")
97+
98+
let requestBody = UpdateProfileRequest(userName: userName, email: email, avatar: avatar)
99+
do {
100+
request.httpBody = try JSONEncoder().encode(requestBody)
101+
} catch {
102+
completion(.failure(error))
103+
return
104+
}
105+
106+
let task = URLSession.shared.dataTask(with: request) { data, response, error in
107+
if let error = error {
108+
completion(.failure(error))
109+
return
110+
}
111+
112+
guard let httpResponse = response as? HTTPURLResponse, (200...299).contains(httpResponse.statusCode) else {
113+
completion(.failure(URLError(.badServerResponse)))
114+
return
115+
}
116+
117+
completion(.success(true))
118+
}
119+
120+
task.resume()
121+
}
122+
123+
77124
//// Function to fetch user messages
78125
func getUserMessages(userId: String, completion: @escaping (Result<[MessageResponse], Error>) -> Void) {
79126
// API URL
@@ -474,6 +521,8 @@ func updateMetrics(completion: @escaping (Result<Bool, Error>) -> Void) {
474521

475522
task.resume()
476523
}
524+
525+
477526
//getAllUserFriends(userId: <#T##String#>, completion: <#T##(Result<[String : String], Error>) -> Void#>) { friendsList in
478527
// guard let friendsList = friendsList else {
479528
// print("Failed to fetch friends list.")

app/newHere1/newHere/Views/ARView/CustomARViewRepresentable.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ struct CustomARViewRepresentable: UIViewRepresentable {
188188
textureAtlas.textureNames.forEach { print($0) } // Print each texture name
189189

190190
for i in 0..<numImages {
191-
let textureName = "bubble-final\(String(format: "%04d", i))"
191+
let textureName = "bubble-final\(String(format: "%03d", i))"
192192
let texture = textureAtlas.textureNamed(textureName)
193193
frames.append(texture)
194194
}

app/newHere1/newHere/Views/Home/Home.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ struct HomePageView: View {
6565
HStack(alignment: .bottom, spacing: 28.0) {
6666
Button(action: {updateARState.updateTrue = true})
6767
{
68-
Image(systemName: "map")
68+
Image(systemName: "arrow.clockwise")
6969
.foregroundColor(.white)
7070
}
7171

app/newHere1/newHere/Views/Login/LoginView.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ let logApiKey = "qe5YT6jOgiA422_UcdbmVxxG1Z6G48aHV7fSV4TbAPs"
66

77
let userId = UserDefaults.standard.string(forKey: "UserId") ?? ""
88
let userName = UserDefaults.standard.string(forKey: "UserName") ?? ""
9-
9+
let userEmail = UserDefaults.standard.string(forKey: "UserEmail") ?? ""
1010

1111
/**
1212
* LoginView
@@ -159,6 +159,11 @@ struct LoginView: View {
159159
// Store the extracted username in UserDefaults.
160160
UserDefaults.standard.set(userName, forKey: "UserName")
161161
}
162+
if let email = json["email"] as? String {
163+
print("Email:\(email)")
164+
// Store the extracted username in UserDefaults.
165+
UserDefaults.standard.set(email, forKey: "UserEmail")
166+
}
162167
}
163168
} catch {
164169
// If JSON parsing fails, print an error message.
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
//
2+
// EditProfile.swift
3+
// newHere
4+
//
5+
// Created by TRACY LI on 2023/12/7.
6+
//
7+
8+
import SwiftUI
9+
10+
struct EditProfile: View {
11+
@Binding var isPresented: Bool
12+
@ObservedObject var viewModel: UserProfileViewModel
13+
@State private var image: Image? = Image(systemName: "person.crop.circle.fill")
14+
@State private var isShowingImagePicker = false
15+
@State private var inputImage: UIImage?
16+
@State private var username: String = ""
17+
@State private var email: String = ""
18+
19+
var body: some View {
20+
VStack {
21+
// Top bar with close button
22+
HStack {
23+
Spacer()
24+
Button(action: {
25+
isPresented.toggle()
26+
}) {
27+
Image(systemName: "xmark.circle")
28+
.font(.system(size: 28))
29+
.foregroundColor(.white)
30+
.shadow(radius: 2.0)
31+
}
32+
.padding(.trailing, 20)
33+
}
34+
.padding(.vertical, 8)
35+
36+
// Edit Profile: Avatar photo, Name, Bio
37+
VStack(alignment: .leading) {
38+
// User Avatar
39+
Button(action: {
40+
self.isShowingImagePicker = true
41+
}) {
42+
VStack {
43+
image?
44+
.resizable()
45+
.scaledToFill()
46+
.clipShape(Circle())
47+
.frame(width: 100, height: 100)
48+
.shadow(radius: 3)
49+
.foregroundColor(Color.white)
50+
51+
Text("Edit Profile Picture")
52+
.foregroundColor(.white)
53+
}
54+
}
55+
.sheet(isPresented: $isShowingImagePicker, onDismiss: loadImage) {
56+
ImagePicker(image: self.$inputImage)
57+
}
58+
59+
// Username Input
60+
Text("Username:")
61+
.foregroundColor(.white)
62+
TextField("Enter new username", text: $username)
63+
.textFieldStyle(RoundedBorderTextFieldStyle())
64+
// Bio Input
65+
Text("Email:")
66+
.foregroundColor(.white)
67+
TextField("Enter new email", text: $email)
68+
.textFieldStyle(RoundedBorderTextFieldStyle())
69+
}
70+
.padding()
71+
72+
// Save Button
73+
Button(action: {
74+
// Action to save the profile details
75+
saveProfile(userId: userId)
76+
}) {
77+
Text("Save")
78+
.foregroundColor(.white)
79+
.padding()
80+
.frame(maxWidth: .infinity)
81+
.background(Color.white.opacity(0.5))
82+
.cornerRadius(10)
83+
}
84+
.padding()
85+
86+
Spacer()
87+
}
88+
.frame(width: 350, height: 600)
89+
.padding(.top, 10)
90+
.padding(.bottom, 10)
91+
}
92+
93+
func loadImage() {
94+
guard let inputImage = inputImage else { return }
95+
image = Image(uiImage: inputImage)
96+
viewModel.profileImage = inputImage
97+
}
98+
func saveProfile(userId: String) {
99+
let userId = userId // Replace with actual user ID
100+
101+
let userNameToUpdate: String? = username.isEmpty ? nil : username
102+
let emailToUpdate: String? = email.isEmpty ? nil : email
103+
let avatarToUpdate: String? = nil // Replace with actual logic to handle avatar updates
104+
105+
updateUserProfile(userId: userId, userName: userNameToUpdate, email: emailToUpdate, avatar: avatarToUpdate) { result in
106+
DispatchQueue.main.async {
107+
switch result {
108+
case .success:
109+
print("Profile updated successfully.")
110+
// Handle successful update (e.g., show confirmation message)
111+
self.viewModel.username = self.username
112+
self.viewModel.email = self.email
113+
case .failure(let error):
114+
print("Error updating profile: \(error.localizedDescription)")
115+
// Handle error (e.g., show error message)
116+
}
117+
}
118+
}
119+
}
120+
}
121+
122+
struct ImagePicker: UIViewControllerRepresentable {
123+
@Environment(\.presentationMode) var presentationMode
124+
@Binding var image: UIImage?
125+
126+
func makeUIViewController(context: Context) -> UIImagePickerController {
127+
let picker = UIImagePickerController()
128+
picker.delegate = context.coordinator
129+
return picker
130+
}
131+
132+
func updateUIViewController(_ uiViewController: UIImagePickerController, context: Context) {}
133+
134+
func makeCoordinator() -> Coordinator {
135+
Coordinator(self)
136+
}
137+
138+
class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
139+
let parent: ImagePicker
140+
141+
init(_ parent: ImagePicker) {
142+
self.parent = parent
143+
}
144+
145+
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
146+
if let uiImage = info[.originalImage] as? UIImage {
147+
parent.image = uiImage
148+
}
149+
150+
parent.presentationMode.wrappedValue.dismiss()
151+
}
152+
}
153+
}
154+
155+

0 commit comments

Comments
 (0)