diff --git a/.DS_Store b/.DS_Store index 015d35c..181327f 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/app/.DS_Store b/app/.DS_Store index e0f8154..8acde58 100644 Binary files a/app/.DS_Store and b/app/.DS_Store differ diff --git a/app/newHere1/.DS_Store b/app/newHere1/.DS_Store index 4cecc7e..85f9a7d 100644 Binary files a/app/newHere1/.DS_Store and b/app/newHere1/.DS_Store differ diff --git a/app/newHere1/newHere.xcodeproj/project.pbxproj b/app/newHere1/newHere.xcodeproj/project.pbxproj index 469b85d..0da8fb1 100644 --- a/app/newHere1/newHere.xcodeproj/project.pbxproj +++ b/app/newHere1/newHere.xcodeproj/project.pbxproj @@ -26,6 +26,9 @@ 158392332AFC72F3007A53C7 /* LoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 158392322AFC72F3007A53C7 /* LoginView.swift */; }; 158392352AFC730B007A53C7 /* Registration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 158392342AFC730B007A53C7 /* Registration.swift */; }; 15F1CC9C2B05C36A00A34A19 /* LoginViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15F1CC9B2B05C36A00A34A19 /* LoginViewTests.swift */; }; + 7194CFD42B2153D30094BE56 /* PhotoLibraryManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7194CFD32B2153D30094BE56 /* PhotoLibraryManager.swift */; }; + 7194CFD62B2153DA0094BE56 /* ScreenshotUtility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7194CFD52B2153DA0094BE56 /* ScreenshotUtility.swift */; }; + 7194CFDC2B2154740094BE56 /* ShareSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7194CFDB2B2154740094BE56 /* ShareSheet.swift */; }; 71D79DA22B1570E4009A054C /* BubbleAnimation.atlas in Resources */ = {isa = PBXBuildFile; fileRef = 71D79DA12B1570E4009A054C /* BubbleAnimation.atlas */; }; FE32AC982B159A650056B003 /* PostTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE32AC972B159A650056B003 /* PostTest.swift */; }; FE32AC9A2B159A9E0056B003 /* MockMessageState.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE32AC992B159A9E0056B003 /* MockMessageState.swift */; }; @@ -83,6 +86,9 @@ 158392322AFC72F3007A53C7 /* LoginView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginView.swift; sourceTree = ""; }; 158392342AFC730B007A53C7 /* Registration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Registration.swift; sourceTree = ""; }; 15F1CC9B2B05C36A00A34A19 /* LoginViewTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginViewTests.swift; sourceTree = ""; }; + 7194CFD32B2153D30094BE56 /* PhotoLibraryManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhotoLibraryManager.swift; sourceTree = ""; }; + 7194CFD52B2153DA0094BE56 /* ScreenshotUtility.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScreenshotUtility.swift; sourceTree = ""; }; + 7194CFDB2B2154740094BE56 /* ShareSheet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShareSheet.swift; sourceTree = ""; }; 71D79DA12B1570E4009A054C /* BubbleAnimation.atlas */ = {isa = PBXFileReference; lastKnownFileType = folder.skatlas; path = BubbleAnimation.atlas; sourceTree = ""; }; FE32AC972B159A650056B003 /* PostTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = PostTest.swift; path = newHereTests/PostTest.swift; sourceTree = SOURCE_ROOT; }; FE32AC992B159A9E0056B003 /* MockMessageState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockMessageState.swift; sourceTree = ""; }; @@ -191,6 +197,14 @@ path = newHereUITests; sourceTree = ""; }; + 7194CFDA2B21546C0094BE56 /* ShareSheet */ = { + isa = PBXGroup; + children = ( + 7194CFDB2B2154740094BE56 /* ShareSheet.swift */, + ); + path = ShareSheet; + sourceTree = ""; + }; 71D79DA42B15757E009A054C /* Home */ = { isa = PBXGroup; children = ( @@ -226,6 +240,7 @@ 71D79DA82B15767C009A054C /* Views */ = { isa = PBXGroup; children = ( + 7194CFDA2B21546C0094BE56 /* ShareSheet */, 71D79DAE2B15793E009A054C /* FriendsView */, 71D79DAC2B157721009A054C /* ARView */, 1531A8DF2AED95FD009F644E /* ContentView.swift */, @@ -258,6 +273,8 @@ 71D79DAB2B1576DA009A054C /* Utils */ = { isa = PBXGroup; children = ( + 7194CFD32B2153D30094BE56 /* PhotoLibraryManager.swift */, + 7194CFD52B2153DA0094BE56 /* ScreenshotUtility.swift */, 1583922C2AFC72CF007A53C7 /* api_call.swift */, ); path = Utils; @@ -454,10 +471,13 @@ 1531A8E02AED95FD009F644E /* ContentView.swift in Sources */, 158392352AFC730B007A53C7 /* Registration.swift in Sources */, 1531A90B2AED964A009F644E /* Profile.swift in Sources */, + 7194CFDC2B2154740094BE56 /* ShareSheet.swift in Sources */, + 7194CFD62B2153DA0094BE56 /* ScreenshotUtility.swift in Sources */, 15582E392AFB2659003910A2 /* Friends.swift in Sources */, 1583922D2AFC72CF007A53C7 /* api_call.swift in Sources */, 1531A90D2AED9663009F644E /* Messages.swift in Sources */, 158392302AFC72D3007A53C7 /* CustomARViewRepresentable.swift in Sources */, + 7194CFD42B2153D30094BE56 /* PhotoLibraryManager.swift in Sources */, 1531A90F2AED9917009F644E /* Post.swift in Sources */, 1531A9152AEDCADB009F644E /* Message.swift in Sources */, 1531A9092AED9618009F644E /* Home.swift in Sources */, @@ -648,7 +668,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"newHere/Preview Content\""; - DEVELOPMENT_TEAM = A7X36A78B2; + DEVELOPMENT_TEAM = W23Y365YR7; ENABLE_HARDENED_RUNTIME = YES; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; @@ -675,7 +695,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SDKROOT = auto; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTS_MACCATALYST = NO; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; @@ -689,10 +709,11 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = newHere/newHere.entitlements; - CODE_SIGN_STYLE = Manual; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"newHere/Preview Content\""; - DEVELOPMENT_TEAM = ""; + DEVELOPMENT_TEAM = W23Y365YR7; ENABLE_HARDENED_RUNTIME = YES; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; @@ -719,7 +740,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SDKROOT = auto; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTS_MACCATALYST = NO; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; @@ -746,7 +767,8 @@ PRODUCT_BUNDLE_IDENTIFIER = com.eric.newHereTests; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = auto; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; SWIFT_EMIT_LOC_STRINGS = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -771,7 +793,8 @@ PRODUCT_BUNDLE_IDENTIFIER = com.eric.newHereTests; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = auto; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; SWIFT_EMIT_LOC_STRINGS = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -795,7 +818,8 @@ PRODUCT_BUNDLE_IDENTIFIER = com.eric.newHereUITests; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = auto; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; SWIFT_EMIT_LOC_STRINGS = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -817,7 +841,8 @@ PRODUCT_BUNDLE_IDENTIFIER = com.eric.newHereUITests; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = auto; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; SWIFT_EMIT_LOC_STRINGS = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -839,6 +864,9 @@ PRODUCT_BUNDLE_IDENTIFIER = "here.newHereTests-v2"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_EMIT_LOC_STRINGS = NO; SWIFT_VERSION = 5.0; @@ -861,6 +889,9 @@ PRODUCT_BUNDLE_IDENTIFIER = "here.newHereTests-v2"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; SWIFT_EMIT_LOC_STRINGS = NO; SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_VERSION = 5.0; diff --git a/app/newHere1/newHere/Utils/PhotoLibraryManager.swift b/app/newHere1/newHere/Utils/PhotoLibraryManager.swift new file mode 100644 index 0000000..72cf22e --- /dev/null +++ b/app/newHere1/newHere/Utils/PhotoLibraryManager.swift @@ -0,0 +1,47 @@ +// +// PhotoLibraryManager.swift +// newHere +// +// Created by TRACY LI on 2023/12/2. +// + +import UIKit +import Photos + +class ImageSaver: NSObject { + var completion: ((Bool, Error?) -> Void)? + + func saveImageToAlbum(image: UIImage, completion: @escaping (Bool, Error?) -> Void) { + self.completion = completion + UIImageWriteToSavedPhotosAlbum(image, self, #selector(image(_:didFinishSavingWithError:contextInfo:)), nil) + } + + @objc private func image(_ image: UIImage, didFinishSavingWithError error: Error?, contextInfo: UnsafeRawPointer) { + if let error = error { + completion?(false, error) + } else { + completion?(true, nil) + } + } +} + +struct PhotoLibraryManager { + static func checkPhotoLibraryPermission(completion: @escaping (Bool) -> Void) { + let status = PHPhotoLibrary.authorizationStatus() + switch status { + case .authorized: + completion(true) + case .denied, .restricted: + completion(false) + case .notDetermined: + PHPhotoLibrary.requestAuthorization { newStatus in + DispatchQueue.main.async { + completion(newStatus == .authorized) + } + } + @unknown default: + fatalError("Unknown photo library authorization status") + } + } +} + diff --git a/app/newHere1/newHere/Utils/ScreenshotUtility.swift b/app/newHere1/newHere/Utils/ScreenshotUtility.swift new file mode 100644 index 0000000..9a3b9cc --- /dev/null +++ b/app/newHere1/newHere/Utils/ScreenshotUtility.swift @@ -0,0 +1,16 @@ +// +// ScreenshotUtility.swift +// newHere +// +// Created by TRACY LI on 2023/12/2. +// + +import UIKit + +func captureScreenshot(of view: UIView) -> UIImage? { + let renderer = UIGraphicsImageRenderer(size: view.bounds.size) + return renderer.image { ctx in + view.drawHierarchy(in: view.bounds, afterScreenUpdates: true) + } +} + diff --git a/app/newHere1/newHere/Utils/api_call.swift b/app/newHere1/newHere/Utils/api_call.swift index 5ce8a2c..ef89411 100644 --- a/app/newHere1/newHere/Utils/api_call.swift +++ b/app/newHere1/newHere/Utils/api_call.swift @@ -424,7 +424,56 @@ func getFilteredMessages(userId: String, location: CLLocation, friendList: [Stri } } +func updateMetrics(completion: @escaping (Result) -> Void) { + let urlString = "https://here-swe.vercel.app/metrics/increment-clicks" + + // URL validation + guard let url = URL(string: urlString) else { + completion(.failure(URLError(.badURL))) + return + } + + // Setup request + var request = URLRequest(url: url) + request.httpMethod = "POST" + request.addValue("application/json", forHTTPHeaderField: "Content-Type") + request.addValue(apiKey, forHTTPHeaderField: "X-API-Key") + + // Prepare request body + let requestBody = ["metricsName": "metric-screenshot-icon3"] + do { + request.httpBody = try JSONSerialization.data(withJSONObject: requestBody, options: []) + } catch { + completion(.failure(error)) + return + } + + // Send request + let task = URLSession.shared.dataTask(with: request) { data, response, error in + // Check for errors + if let error = error { + completion(.failure(error)) + return + } + + // Check for valid HTTP response + guard let httpResponse = response as? HTTPURLResponse else { + completion(.failure(URLError(.badServerResponse))) + return + } + // Check for successful status code + guard (200...299).contains(httpResponse.statusCode) else { + completion(.failure(URLError(.badServerResponse))) + return + } + + // Success + completion(.success(true)) + } + + task.resume() +} //getAllUserFriends(userId: <#T##String#>, completion: <#T##(Result<[String : String], Error>) -> Void#>) { friendsList in // guard let friendsList = friendsList else { // print("Failed to fetch friends list.") diff --git a/app/newHere1/newHere/Views/FriendsView/Friends.swift b/app/newHere1/newHere/Views/FriendsView/Friends.swift index 79d16ed..4df4d5c 100644 --- a/app/newHere1/newHere/Views/FriendsView/Friends.swift +++ b/app/newHere1/newHere/Views/FriendsView/Friends.swift @@ -38,15 +38,13 @@ struct Friends: View { Button(action: { isPresented.toggle() // Close the popup }) { - Text("Close") - .font(.headline) - .padding() - .background(Color.blue) - .foregroundColor(.white) - .cornerRadius(10) + Image(systemName: "xmark.circle") + .font(.system(size: 28)) + .foregroundColor(Color.white) + .shadow(radius: 2.0) } .padding(.trailing, 20) // Adjust the position of the close button - } + }.padding(.vertical, 8) // search bar and add friend button HStack { @@ -93,7 +91,7 @@ struct Friends: View { Text("Add Friend") .padding(.horizontal, 16) .padding(.vertical, 8) - .background(Color.blue) + .background(Color.white.opacity(0.5)) .foregroundColor(.white) .cornerRadius(8) } @@ -134,17 +132,22 @@ struct Friends: View { } }){ Image(systemName: "minus.circle") + .font(.system(size: 28)) + .foregroundColor(Color.gray) } } - } + }.background(Color.gray) } } + .frame(width: 350, height: 600) + .padding(.top, 10) + .padding(.bottom, 10) .onAppear { // Fetch Friends List on Appear getAllUserFriends(userId: userId) { result in switch result { case .success(let response): - print("Friends fetched successfully: \(response)") + print("Friends fetched successfully: \(response)") self.friendsList = response.values.map { $0 } case .failure(let error): @@ -158,3 +161,4 @@ struct Friends: View { // Make sure `getAllUserFriends` has a signature similar to this: // func getAllUserFriends(userId: String, completion: @escaping (Result<[String], Error>) -> Void) + diff --git a/app/newHere1/newHere/Views/Home/Home.swift b/app/newHere1/newHere/Views/Home/Home.swift index 1514539..bf16cdc 100644 --- a/app/newHere1/newHere/Views/Home/Home.swift +++ b/app/newHere1/newHere/Views/Home/Home.swift @@ -1,5 +1,6 @@ import SwiftUI import ARKit +import UIKit /** * MessageState @@ -37,6 +38,9 @@ struct HomePageView: View { @State private var isShowingPosts = false @StateObject var messageState = MessageState() @StateObject var fetchedMessagesState = FetchedMessagesState() + @State private var shareSheetPresented = false + @State private var screenshot: UIImage? + @State private var showCaptureAlert = false @EnvironmentObject var locationDataManager: LocationDataManager @@ -79,13 +83,44 @@ struct HomePageView: View { .foregroundColor(.white) } - Button{ - - }label: - { - Image(systemName: "square.and.arrow.up") + Button(action: { + updateMetrics { result in + switch result { + case .success(_): + print("Metrics incremented successfully") + case .failure(let error): + print("Error incrementing metrics: \(error.localizedDescription)") +// self.errorMessage = error.localizedDescription + } + } + + if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene, + let window = windowScene.windows.first(where: { $0.isKeyWindow }) { + screenshot = captureScreenshot(of: window) + showCaptureAlert = true + } + }) { + Image(systemName: "photo.on.rectangle.angled") .foregroundColor(.white) } + .sheet(isPresented: $shareSheetPresented, onDismiss: { + screenshot = nil + }) { + if let screenshot = screenshot { + ShareSheet(items: [screenshot]) + } + } + .alert(isPresented: $showCaptureAlert) { + Alert( + title: Text("Screen captured!"), + message: Text("Wanna share it?"), + primaryButton: .default(Text("Share")) { + shareSheetPresented = true + }, + secondaryButton: .cancel() + ) + } + Button{isShowingProfile.toggle() diff --git a/app/newHere1/newHere/Views/Login/LoginView.swift b/app/newHere1/newHere/Views/Login/LoginView.swift index ff81007..77de485 100644 --- a/app/newHere1/newHere/Views/Login/LoginView.swift +++ b/app/newHere1/newHere/Views/Login/LoginView.swift @@ -47,7 +47,8 @@ struct LoginView: View { NavigationView { VStack { - Text("Login") + Spacer() + Text("Here!") .font(.largeTitle) .padding(.bottom, 50) @@ -57,6 +58,8 @@ struct LoginView: View { .background(Color(.systemGray6)) .cornerRadius(5.0) .padding(.bottom, 20) + .padding(.leading, 20) + .padding(.trailing, 20) // Password input field SecureField("Password", text: $password) @@ -64,6 +67,8 @@ struct LoginView: View { .background(Color(.systemGray6)) .cornerRadius(5.0) .padding(.bottom, 20) + .padding(.leading, 20) + .padding(.trailing, 20) // Login button Button(action: LogInUser) { @@ -72,7 +77,7 @@ struct LoginView: View { .frame(height: 50) .foregroundColor(.white) .font(.system(size: 18, weight: .bold)) - .background(Color.blue) + .background(Color.gray) .cornerRadius(5.0) } .padding(.horizontal) @@ -80,6 +85,7 @@ struct LoginView: View { // Navigation link to registration view NavigationLink(destination: RegistrationView(isRegistered: $isRegistered)) { Text("Don't have an account? Signup") + .foregroundColor(Color.gray) } .padding() @@ -89,7 +95,7 @@ struct LoginView: View { .alert(isPresented: $showingAlert) { Alert(title: Text("Login Status"), message: Text(alertMessage), dismissButton: .default(Text("OK"))) } - }.navigationBarBackButtonHidden(true) + } } /// Function to handle user login diff --git a/app/newHere1/newHere/Views/Profile/Profile.swift b/app/newHere1/newHere/Views/Profile/Profile.swift index c9cc82a..0976366 100644 --- a/app/newHere1/newHere/Views/Profile/Profile.swift +++ b/app/newHere1/newHere/Views/Profile/Profile.swift @@ -37,26 +37,56 @@ struct ProfilePopup: View { } ProfileHeader() // User profile header Divider() - ProfileStats() // User profile statistics - Divider() - Button(action: { - isShowingFriends.toggle() - }) { - Text("Show Friends") - .font(.headline) - .padding(EdgeInsets(top: 6, leading: 12, bottom: 6, trailing: 12)) - .border(Color.gray, width: 1) - .foregroundColor(Color.gray) - .cornerRadius(5) + + HStack { + VStack { + Text("Notes") + .font(.caption) + .foregroundColor(.gray.opacity(0.8)) + + Text("10") + .font(.headline) + } + .padding() + .background(Color.white.opacity(0.8)) + .cornerRadius(8) + .shadow(radius: 3) + + VStack { + Text("Friends") + .font(.caption) + .foregroundColor(.gray.opacity(0.8)) + + Text("100") + .font(.headline) + } + .padding() + .background(Color.white.opacity(0.8)) + .cornerRadius(8) + .shadow(radius: 3) + .onTapGesture { + isShowingFriends.toggle() // Toggle the state to show friends + } } + .padding() + + Divider() PostGrid() // Grid to show posts } .padding(.top, 10) .padding(.bottom, 10) - .sheet(isPresented: $isShowingFriends) { - // Friends.swift => Friends struct - Friends(isPresented: $isShowingFriends) // Pass the binding to control visibility - } +// .sheet(isPresented: $isShowingFriends) { +// // Friends.swift => Friends struct +// Friends(isPresented: $isShowingFriends) // Pass the binding to control visibility +// } + } + + if isShowingFriends { + Friends(isPresented: $isShowingFriends) + .background(Color.gray) + .cornerRadius(12) + .shadow(radius: 10) + .padding() } } .frame(width: 350, height: 600) @@ -147,20 +177,31 @@ struct ProfileStats: View { var body: some View { HStack { - ForEach(stats, id: \.title) { stat in - VStack { - Text(stat.title) - .font(.caption) - .foregroundColor(.gray.opacity(0.8)) + VStack { + Text("Notes") + .font(.caption) + .foregroundColor(.gray.opacity(0.8)) - Text(stat.value) - .font(.headline) - } - .padding() - .background(Color.white.opacity(0.8)) - .cornerRadius(8) - .shadow(radius: 3) + Text("10") + .font(.headline) + } + .padding() + .background(Color.white.opacity(0.8)) + .cornerRadius(8) + .shadow(radius: 3) + + VStack { + Text("Friends") + .font(.caption) + .foregroundColor(.gray.opacity(0.8)) + + Text("100") + .font(.headline) } + .padding() + .background(Color.white.opacity(0.8)) + .cornerRadius(8) + .shadow(radius: 3) } .padding() } @@ -201,3 +242,4 @@ struct PostGrid: View { .padding() } } + diff --git a/app/newHere1/newHere/Views/ShareSheet/ShareSheet.swift b/app/newHere1/newHere/Views/ShareSheet/ShareSheet.swift new file mode 100644 index 0000000..edd054c --- /dev/null +++ b/app/newHere1/newHere/Views/ShareSheet/ShareSheet.swift @@ -0,0 +1,19 @@ +// +// ShareSheet.swift +// newHere +// +// Created by TRACY LI on 2023/12/2. +// + +import SwiftUI + +struct ShareSheet: UIViewControllerRepresentable { + var items: [Any] + + func makeUIViewController(context: Context) -> UIActivityViewController { + let controller = UIActivityViewController(activityItems: items, applicationActivities: nil) + return controller + } + + func updateUIViewController(_ uiViewController: UIActivityViewController, context: Context) {} +}