diff --git a/.DS_Store b/.DS_Store index 7fa1be84..00b84f80 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/.gitignore b/.gitignore index 166face2..464e66e7 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ *.xcworkspace/xcuserdata/ DerivedData/ build/ +*DS_Store* diff --git a/MobileAcebook.xcodeproj/project.pbxproj b/MobileAcebook.xcodeproj/project.pbxproj index 5506db3b..119e3713 100644 --- a/MobileAcebook.xcodeproj/project.pbxproj +++ b/MobileAcebook.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 919D73622C886922000BA941 /* NavigationBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 919D73612C886922000BA941 /* NavigationBar.swift */; }; AE5D85B02AC8A221009680C6 /* MobileAcebookApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE5D85AF2AC8A221009680C6 /* MobileAcebookApp.swift */; }; AE5D85B42AC8A224009680C6 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = AE5D85B32AC8A224009680C6 /* Assets.xcassets */; }; AE5D85B72AC8A224009680C6 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = AE5D85B62AC8A224009680C6 /* Preview Assets.xcassets */; }; @@ -19,6 +20,14 @@ AE5D85E32AC9AFD2009680C6 /* MockAuthenticationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE5D85E22AC9AFD2009680C6 /* MockAuthenticationService.swift */; }; AE5D85E62AC9B077009680C6 /* AuthenticationServiceProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE5D85E52AC9B077009680C6 /* AuthenticationServiceProtocol.swift */; }; AE5D85E82AC9B29A009680C6 /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE5D85E72AC9B29A009680C6 /* User.swift */; }; + F12EC4E32C873A1800467C46 /* ImagePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = F12EC4E22C873A1700467C46 /* ImagePicker.swift */; }; + F52702832C872E7900C5B8E7 /* Post.swift in Sources */ = {isa = PBXBuildFile; fileRef = F52702822C872E7900C5B8E7 /* Post.swift */; }; + F52702852C872FB500C5B8E7 /* PostsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F52702842C872FB500C5B8E7 /* PostsViewModel.swift */; }; + F8E51E812C861051005418F9 /* SignUpPageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8E51E802C861051005418F9 /* SignUpPageView.swift */; }; + F8E51E832C861062005418F9 /* LoginPageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8E51E822C861062005418F9 /* LoginPageView.swift */; }; + F8E51E852C861071005418F9 /* FeedPageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8E51E842C861071005418F9 /* FeedPageView.swift */; }; + F8E51E872C861086005418F9 /* CreatePostsPageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8E51E862C861086005418F9 /* CreatePostsPageView.swift */; }; + F8E51E892C861095005418F9 /* ProfilePageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8E51E882C861095005418F9 /* ProfilePageView.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -39,6 +48,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 919D73612C886922000BA941 /* NavigationBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationBar.swift; sourceTree = ""; }; AE5D85AC2AC8A221009680C6 /* MobileAcebook.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MobileAcebook.app; sourceTree = BUILT_PRODUCTS_DIR; }; AE5D85AF2AC8A221009680C6 /* MobileAcebookApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MobileAcebookApp.swift; sourceTree = ""; }; AE5D85B32AC8A224009680C6 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; @@ -54,6 +64,14 @@ AE5D85E22AC9AFD2009680C6 /* MockAuthenticationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockAuthenticationService.swift; sourceTree = ""; }; AE5D85E52AC9B077009680C6 /* AuthenticationServiceProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationServiceProtocol.swift; sourceTree = ""; }; AE5D85E72AC9B29A009680C6 /* User.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = User.swift; sourceTree = ""; }; + F12EC4E22C873A1700467C46 /* ImagePicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImagePicker.swift; sourceTree = ""; }; + F52702822C872E7900C5B8E7 /* Post.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Post.swift; sourceTree = ""; }; + F52702842C872FB500C5B8E7 /* PostsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostsViewModel.swift; sourceTree = ""; }; + F8E51E802C861051005418F9 /* SignUpPageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpPageView.swift; sourceTree = ""; }; + F8E51E822C861062005418F9 /* LoginPageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginPageView.swift; sourceTree = ""; }; + F8E51E842C861071005418F9 /* FeedPageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedPageView.swift; sourceTree = ""; }; + F8E51E862C861086005418F9 /* CreatePostsPageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreatePostsPageView.swift; sourceTree = ""; }; + F8E51E882C861095005418F9 /* ProfilePageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfilePageView.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -111,6 +129,13 @@ AE5D85B32AC8A224009680C6 /* Assets.xcassets */, AE5D85B52AC8A224009680C6 /* Preview Content */, AE5D85D92AC8A337009680C6 /* WelcomePageView.swift */, + F8E51E802C861051005418F9 /* SignUpPageView.swift */, + F8E51E822C861062005418F9 /* LoginPageView.swift */, + F8E51E842C861071005418F9 /* FeedPageView.swift */, + F8E51E862C861086005418F9 /* CreatePostsPageView.swift */, + F8E51E882C861095005418F9 /* ProfilePageView.swift */, + F12EC4E22C873A1700467C46 /* ImagePicker.swift */, + 919D73612C886922000BA941 /* NavigationBar.swift */, ); path = MobileAcebook; sourceTree = ""; @@ -162,6 +187,8 @@ isa = PBXGroup; children = ( AE5D85E72AC9B29A009680C6 /* User.swift */, + F52702822C872E7900C5B8E7 /* Post.swift */, + F52702842C872FB500C5B8E7 /* PostsViewModel.swift */, ); path = Models; sourceTree = ""; @@ -238,7 +265,7 @@ attributes = { BuildIndependentTargetsInParallel = 1; LastSwiftUpdateCheck = 1420; - LastUpgradeCheck = 1420; + LastUpgradeCheck = 1540; TargetAttributes = { AE5D85AB2AC8A221009680C6 = { CreatedOnToolsVersion = 14.2; @@ -305,8 +332,17 @@ buildActionMask = 2147483647; files = ( AE5D85E12AC9AFA9009680C6 /* AuthenticationService.swift in Sources */, + F52702832C872E7900C5B8E7 /* Post.swift in Sources */, + F8E51E892C861095005418F9 /* ProfilePageView.swift in Sources */, + F8E51E852C861071005418F9 /* FeedPageView.swift in Sources */, AE5D85E62AC9B077009680C6 /* AuthenticationServiceProtocol.swift in Sources */, + F8E51E832C861062005418F9 /* LoginPageView.swift in Sources */, AE5D85B02AC8A221009680C6 /* MobileAcebookApp.swift in Sources */, + F8E51E812C861051005418F9 /* SignUpPageView.swift in Sources */, + F12EC4E32C873A1800467C46 /* ImagePicker.swift in Sources */, + F52702852C872FB500C5B8E7 /* PostsViewModel.swift in Sources */, + F8E51E872C861086005418F9 /* CreatePostsPageView.swift in Sources */, + 919D73622C886922000BA941 /* NavigationBar.swift in Sources */, AE5D85E82AC9B29A009680C6 /* User.swift in Sources */, AE5D85DA2AC8A337009680C6 /* WelcomePageView.swift in Sources */, ); @@ -383,6 +419,7 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -443,6 +480,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -469,6 +507,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"MobileAcebook/Preview Content\""; + DEVELOPMENT_TEAM = 93ARFXYW45; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; @@ -497,6 +536,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"MobileAcebook/Preview Content\""; + DEVELOPMENT_TEAM = 93ARFXYW45; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; diff --git a/MobileAcebook.xcodeproj/xcshareddata/xcschemes/MobileAcebook.xcscheme b/MobileAcebook.xcodeproj/xcshareddata/xcschemes/MobileAcebook.xcscheme new file mode 100644 index 00000000..2ded4968 --- /dev/null +++ b/MobileAcebook.xcodeproj/xcshareddata/xcschemes/MobileAcebook.xcscheme @@ -0,0 +1,114 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MobileAcebook/Assets.xcassets/AccentColor.colorset/Contents.json b/MobileAcebook/Assets.xcassets/AccentColor.colorset/Contents.json index eb878970..7c4d70c2 100644 --- a/MobileAcebook/Assets.xcassets/AccentColor.colorset/Contents.json +++ b/MobileAcebook/Assets.xcassets/AccentColor.colorset/Contents.json @@ -1,6 +1,15 @@ { "colors" : [ { + "color" : { + "color-space" : "display-p3", + "components" : { + "alpha" : "1.000", + "blue" : "0.697", + "green" : "0.696", + "red" : "0.671" + } + }, "idiom" : "universal" } ], diff --git a/MobileAcebook/Assets.xcassets/makers-logo.imageset/Contents.json b/MobileAcebook/Assets.xcassets/Logo.imageset/Contents.json similarity index 81% rename from MobileAcebook/Assets.xcassets/makers-logo.imageset/Contents.json rename to MobileAcebook/Assets.xcassets/Logo.imageset/Contents.json index 216c5e2c..7d56d46f 100644 --- a/MobileAcebook/Assets.xcassets/makers-logo.imageset/Contents.json +++ b/MobileAcebook/Assets.xcassets/Logo.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "makers-logo.png", + "filename" : "Screenshot 2024-09-02 at 15.59.50.png", "idiom" : "universal", "scale" : "1x" }, diff --git a/MobileAcebook/Assets.xcassets/Logo.imageset/Screenshot 2024-09-02 at 15.59.50.png b/MobileAcebook/Assets.xcassets/Logo.imageset/Screenshot 2024-09-02 at 15.59.50.png new file mode 100644 index 00000000..0be2bb06 Binary files /dev/null and b/MobileAcebook/Assets.xcassets/Logo.imageset/Screenshot 2024-09-02 at 15.59.50.png differ diff --git a/MobileAcebook/Assets.xcassets/makers-logo.imageset/makers-logo.png b/MobileAcebook/Assets.xcassets/makers-logo.imageset/makers-logo.png deleted file mode 100644 index 8e9844cb..00000000 Binary files a/MobileAcebook/Assets.xcassets/makers-logo.imageset/makers-logo.png and /dev/null differ diff --git a/MobileAcebook/CreatePostsPageView.swift b/MobileAcebook/CreatePostsPageView.swift new file mode 100644 index 00000000..b70086cf --- /dev/null +++ b/MobileAcebook/CreatePostsPageView.swift @@ -0,0 +1,101 @@ +import SwiftUI +import UIKit + + +// The main view +struct CreatePostsPageView: View { + @State private var postMessage = "" + @State private var selectedImage: UIImage? = nil + @State private var isImagePickerPresented = false + @State private var isLogin = true + + var body: some View { + NavigationView { + HStack { + VStack(alignment: .center) { + // Display the selected image, or a button to select one + if let image = selectedImage { + Image(uiImage: image) + .resizable() + .scaledToFit() + .frame(width: 200, height: 200) + .padding() + } else { + Button(action: { + }) { + TextField("What's on your mind...", text: $postMessage) + .padding() + // .scrollContentBackground(.hidden) + } + .padding() + } + + Form { + Button ("selected an Image", action:{ + + isImagePickerPresented = true + }) + NavigationLink(destination: ContentView()) { + Text("Submit") + } + } + .frame(width: 300.0, height: 150.0) + // .scrollContentBackground(/*@START_MENU_TOKEN@*/.hidden/*@END_MENU_TOKEN@*/) + } + .padding() + .sheet(isPresented: $isImagePickerPresented) { + ImagePicker(image: $selectedImage) + } + + .navigationBarBackButtonHidden(false) + } + CustomNavigationBar() + } + } + } + +// Preview +struct CreatePostsPageView_Previews: PreviewProvider { + static var previews: some View { + CreatePostsPageView() + } +} + + +class PostService { + static let shared = PostService() + + let baseURL = "https://your-backend-url.com/api" // Replace with your actual backend URL + + func createPost(post: Post, completion: @escaping (Result) -> Void) { + guard let url = URL(string: "\(baseURL)/posts") else { return } + + var request = URLRequest(url: url) + request.httpMethod = "POST" + request.setValue("application/json", forHTTPHeaderField: "Content-Type") + + do { + let jsonData = try JSONEncoder().encode(post) + request.httpBody = jsonData + + let task = URLSession.shared.dataTask(with: request) { data, response, error in + if let error = error { + completion(.failure(error)) + return + } + + guard let data = data else { return } + + do { + let createdPost = try JSONDecoder().decode(Post.self, from: data) + completion(.success(createdPost)) + } catch { + completion(.failure(error)) + } + } + task.resume() + } catch { + completion(.failure(error)) + } + } +} diff --git a/MobileAcebook/FeedPageView.swift b/MobileAcebook/FeedPageView.swift new file mode 100644 index 00000000..53713c14 --- /dev/null +++ b/MobileAcebook/FeedPageView.swift @@ -0,0 +1,97 @@ +// FeedPageView.swift +// MobileAcebook + +import Foundation +import SwiftUI + +// Mock up a simple posting +// Make a call to the Acebook API to retreive a posting +// Loop through and render each posting + + +// Main View +struct ContentView: View { + @StateObject private var viewModel = PostViewModel() + + var body: some View { + NavigationView { + List { + ForEach(viewModel.posts) { post in + PostView(post: post) + .environmentObject(viewModel) + } + } + .navigationTitle("Postings") + } + .navigationBarBackButtonHidden(true) + } + +} + +// View for a single post +struct PostView: View { + @EnvironmentObject var viewModel: PostViewModel + @State private var newComment: String = "" + var post: Post + + var body: some View { + VStack(alignment: .leading) { + Text(post.message) + .font(.headline) + + Text(post.comment) + .font(.subheadline) + .foregroundColor(.gray) + + Text(post.imageUrl) + .font(.subheadline) + .foregroundColor(.gray) + + Text(post.createdAt) + .font(.subheadline) + .foregroundColor(.gray) + + HStack { + Button(action: { + viewModel.likePost(post) + }) { + HStack { + Image(systemName: "hand.thumbsup") + Text("\(post.likes) Likes") + } + } + .buttonStyle(BorderlessButtonStyle()) + + Spacer() + } + .padding(.top, 5) + + TextField("Add a comment...", text: $newComment, onCommit: { + viewModel.addComment(post, newComment: newComment) + newComment = "" + }) + .textFieldStyle(RoundedBorderTextFieldStyle()) + .padding(.top, 5) + } + .padding() + .onAppear{ + viewModel.fetchPosts() + viewModel.printPosts() + } + } +} + +/*@main +struct PostingsApp: App { + var body: some Scene { + WindowGroup { + ContentView() + } + } +}*/ + +struct PostView_Previews: PreviewProvider { + static var previews: some View { + ContentView() + } +} diff --git a/MobileAcebook/ImagePicker.swift b/MobileAcebook/ImagePicker.swift new file mode 100644 index 00000000..41d0d8ad --- /dev/null +++ b/MobileAcebook/ImagePicker.swift @@ -0,0 +1,49 @@ +// +// ImagePicker.swift +// MobileAcebook +// +// Created by Marya Shariq on 03/09/2024. +// +import PhotosUI +import SwiftUI + +struct ImagePicker: UIViewControllerRepresentable { + @Binding var image: UIImage? + + func makeUIViewController(context: Context) -> PHPickerViewController { + var config = PHPickerConfiguration() + config.filter = .images + let picker = PHPickerViewController(configuration: config) + picker.delegate = context.coordinator + return picker + } + + func updateUIViewController(_ uiViewController: PHPickerViewController, context: Context) { + + } + + func makeCoordinator() -> Coordinator { + Coordinator(self) + } + + class Coordinator: NSObject, PHPickerViewControllerDelegate { + let parent: ImagePicker + + init(_ parent: ImagePicker) { + self.parent = parent + } + + func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) { + picker.dismiss(animated: true) + + guard let provider = results.first?.itemProvider else { return } + + if provider.canLoadObject(ofClass: UIImage.self) { + provider.loadObject(ofClass: UIImage.self) { image, _ in + self.parent.image = image as? UIImage + } + } + } + } +} + diff --git a/MobileAcebook/LoginPageView.swift b/MobileAcebook/LoginPageView.swift new file mode 100644 index 00000000..5b2278e4 --- /dev/null +++ b/MobileAcebook/LoginPageView.swift @@ -0,0 +1,68 @@ +// +// LoginPageView.swift +// MobileAcebook +// +// Created by Santosh Dasari on 02/09/2024. +// + +import Foundation +import SwiftUI + +struct LoginPageView: View { + @State private var username = "" + @State private var password = "" + var body: some View { + ZStack { + Color.black + .ignoresSafeArea() + + VStack { + Image("Logo") + .resizable() + .scaledToFit() + .frame(width: 200, height: 200) + .accessibilityIdentifier("Acebook-Logo") + + Text("Login") + .font(.largeTitle) + .padding(.bottom, 20) + .accessibilityIdentifier("Login Button") + .foregroundColor(Color.white) + .background(Color.black) + .font(.system(.body, design: .monospaced)) + Form { + Section { + TextField("Username", text: $username) + TextField("Password", text: $password) + } header:{ + Text("Account Details") + .foregroundColor(Color.white) + .background(Color.black) + .font(.system(.body, design: .monospaced)) + // TODO: sign up logic + } + + } + .frame(width: 300.0, height: 150.0) + .scrollContentBackground(/*@START_MENU_TOKEN@*/.hidden/*@END_MENU_TOKEN@*/) + + Button("Login") { + print("Button Tapped") + } + .accessibilityIdentifier("LogInButton") + .buttonStyle(.borderedProminent) + .foregroundColor(Color.white) + .buttonBorderShape(.roundedRectangle(radius: 20)) + .font(.system(.body, design: .monospaced)) + .padding(40) + } + } + } + } + + +struct LoginPageView_Previews: PreviewProvider { + static var previews: some View { + LoginPageView() + } +} diff --git a/MobileAcebook/MobileAcebookApp.swift b/MobileAcebook/MobileAcebookApp.swift index e0c3eb42..6c4ce161 100644 --- a/MobileAcebook/MobileAcebookApp.swift +++ b/MobileAcebook/MobileAcebookApp.swift @@ -13,5 +13,8 @@ struct MobileAcebookApp: App { WindowGroup { WelcomePageView() } + WindowGroup { + SignUpPageView() + } } } diff --git a/MobileAcebook/Models/Post.swift b/MobileAcebook/Models/Post.swift new file mode 100644 index 00000000..d1af7c87 --- /dev/null +++ b/MobileAcebook/Models/Post.swift @@ -0,0 +1,17 @@ +// +// Post.swift +// MobileAcebook +// +// Created by Reza Jugon on 03/09/2024. +// +import Foundation + +// Model for a single Post +struct Post: Codable, Identifiable { + let id = UUID() + var message: String + var comment: String + var likes: Int + var imageUrl: String + var createdAt: String +} diff --git a/MobileAcebook/Models/PostsViewModel.swift b/MobileAcebook/Models/PostsViewModel.swift new file mode 100644 index 00000000..600721e5 --- /dev/null +++ b/MobileAcebook/Models/PostsViewModel.swift @@ -0,0 +1,86 @@ +// +// PostsViewModel.swift +// MobileAcebook +// +// Created by Reza Jugon on 03/09/2024. +// + +import Foundation + +class PostViewModel: ObservableObject { + + @Published var posts: [Post] = [ + Post(message: "This is my first post", comment: "This is a comment on post 1", likes: 0, imageUrl: "placeholder img url 1", createdAt: "2024-09-03"), + Post(message: "This is my second post", comment: "This is a comment on post 2", likes: 0, imageUrl: "placeholder img url 2", createdAt: "2024-09-04"), + Post(message: "This is my third post", comment: "This is a comment on post 3", likes: 0, imageUrl: "placeholder img url 3", createdAt: "2024-09-05") + ] + + @Published var posts2: [Post] = [] + func fetchPosts() { + + guard let url = URL(string: "https://jsonplaceholder.typicode.com/posts") else { return } + + URLSession.shared.dataTask(with: url) { data, response, error in + guard let data = data, error == nil else { return } + + let posts2 = try? JSONDecoder().decode([Post].self, from: data) + DispatchQueue.main.async { + self.posts2 = posts2 ?? [] + } + print("=> fetch posts2") + //print(posts2) + + }.resume() + + } + + func printPosts() { + // Loop through the array and print each Post's properties + for post in posts { + print("Post ID: \(post.id)") + print("Message: \(post.message)") + print("Comment: \(post.comment)") + print("Likes: \(post.likes)") + print("Image URL: \(post.imageUrl)") + print("Created At: \(post.createdAt)") + print("-----") // Separator between posts + } + } + + func likePost(_ post: Post) { + if let index = posts.firstIndex(where: { $0.id == post.id }) { + posts[index].likes += 1 + } + } + + func addComment(_ post: Post, newComment: String) { + if let index = posts.firstIndex(where: { $0.id == post.id }) { + posts[index].comment = newComment + } + } +} + +// ----------------------------------------------------------------------------------------------- + + +//// View Model to manage the list of posts +//class PostViewModel: ObservableObject { +// +// @Published var posts: [Post] = [ +// Post(title: "This is my first post", comment: "This is a comment on post 1", likes: 0), +// Post(title: "This is my second post", comment: "This is a comment on post 2", likes: 0), +// Post(title: "This is my third post", comment: "This is a comment on post 3", likes: 0) +// ] +// +// func likePost(_ post: Post) { +// if let index = posts.firstIndex(where: { $0.id == post.id }) { +// posts[index].likes += 1 +// } +// } +// +// func addComment(_ post: Post, newComment: String) { +// if let index = posts.firstIndex(where: { $0.id == post.id }) { +// posts[index].comment = newComment +// } +// } +//} diff --git a/MobileAcebook/Models/User.swift b/MobileAcebook/Models/User.swift index ea748dd0..d34a628c 100644 --- a/MobileAcebook/Models/User.swift +++ b/MobileAcebook/Models/User.swift @@ -7,5 +7,7 @@ public struct User { let username: String + let email: String let password: String + let image: String } diff --git a/MobileAcebook/NavigationBar.swift b/MobileAcebook/NavigationBar.swift new file mode 100644 index 00000000..0301a8d0 --- /dev/null +++ b/MobileAcebook/NavigationBar.swift @@ -0,0 +1,69 @@ +import SwiftUI + +struct CustomNavigationBar: View { + var body: some View { + HStack { + Spacer() + + NavigationLink(destination: ContentView()) { + VStack { + Image(systemName: "house.fill") + .font(.system(size: 24)) + .foregroundColor(.white) + Text("Home") + .font(.caption) + .foregroundColor(.white) + } + } + + Spacer() + + NavigationLink(destination: ProfilePageView()) { + VStack { + Image(systemName: "person.fill") + .font(.system(size: 24)) + .foregroundColor(.white) + Text("My Profile") + .font(.caption) + .foregroundColor(.white) + } + } + + Spacer() + + NavigationLink(destination: CreatePostsPageView()) { + VStack { + Image(systemName: "plus.circle.fill") + .font(.system(size: 24)) + .foregroundColor(.white) + Text("Create Post") + .font(.caption) + .foregroundColor(.white) + } + } + + Spacer() + + NavigationLink(destination: WelcomePageView()) { + VStack { + Image(systemName: "arrowshape.turn.up.left.fill") + .font(.system(size: 24)) + .foregroundColor(.white) + Text("Logout") + .font(.caption) + .foregroundColor(.white) + } + } + + Spacer() + } + .padding() + .background(Color.gray.opacity(0.8)) + } +} + +struct CustomNavigationBar_Previews: PreviewProvider { + static var previews: some View { + CustomNavigationBar() + } +} diff --git a/MobileAcebook/ProfilePageView.swift b/MobileAcebook/ProfilePageView.swift new file mode 100644 index 00000000..dce946de --- /dev/null +++ b/MobileAcebook/ProfilePageView.swift @@ -0,0 +1,142 @@ +import SwiftUI + +struct ProfilePageView: View { + var body: some View { + NavigationView { + VStack { + ScrollView { + VStack { + VStack { + Image("profilePicture") // Replace with your actual image name + .resizable() + .aspectRatio(contentMode: .fill) + .frame(width: 150, height: 150) + .clipShape(Circle()) + .overlay( + Circle().stroke(Color.white, lineWidth: 4) + ) + .shadow(radius: 10) + + Text("John King") + .font(.title) + .foregroundColor(.white) + .padding(.top, 8) + } + .padding() + + VStack(spacing: 10) { + // Image Post + ImagePostView(imageName: "post1", caption: "Had a great time hiking!") + + // Text-Only Post + TextPostView(text: "Enjoying a quiet evening with a good book. Highly recommend 'The Midnight Library'!") + + // Another Image Post + ImagePostView(imageName: "post2", caption: "Loving the new cafe in town!") + + // Another Text-Only Post + TextPostView(text: "Excited for the weekend! Anyone up for a road trip?") + } + .padding([.leading, .trailing]) + } + } + CustomNavigationBar() + + } + .background(Color.black.edgesIgnoringSafeArea(.all)) + .navigationBarHidden(true) // Hides the default navigation bar + } + .navigationBarBackButtonHidden(true) + } + } + +struct ImagePostView: View { + var imageName: String + var caption: String + + var body: some View { + VStack(alignment: .leading, spacing: 10) { + Image(imageName) + .resizable() + .aspectRatio(contentMode: .fill) + .frame(maxHeight: 300) + .cornerRadius(10) + + Text(caption) + .font(.body) + .foregroundColor(.white) + .padding([.leading, .trailing]) + + HStack { + Button(action: { + // Like action + }) { + Text("Like") + .foregroundColor(.gray) + } + Spacer() + Button(action: { + // Comment action + }) { + Text("Comment") + .foregroundColor(.gray) + } + Spacer() + Button(action: { + // Share action + }) { + Text("Share") + .foregroundColor(.gray) + } + } + .padding([.leading, .trailing, .bottom]) + } + .background(Color.gray.opacity(0.2)) + .cornerRadius(10) + } +} + +struct TextPostView: View { + var text: String + + var body: some View { + VStack(alignment: .leading, spacing: 10) { + Text(text) + .font(.body) + .foregroundColor(.white) + .padding([.leading, .trailing, .top]) + + HStack { + Button(action: { + // Like action + }) { + Text("Like") + .foregroundColor(.gray) + } + Spacer() + Button(action: { + // Comment action + }) { + Text("Comment") + .foregroundColor(.gray) + } + Spacer() + Button(action: { + // Share action + }) { + Text("Share") + .foregroundColor(.gray) + } + } + .padding([.leading, .trailing, .bottom]) + } + .background(Color.gray.opacity(0.2)) + .cornerRadius(10) + } +} + +struct ProfilePageView_Previews: PreviewProvider { + static var previews: some View { + ProfilePageView() + } +} diff --git a/MobileAcebook/SignUpPageView.swift b/MobileAcebook/SignUpPageView.swift new file mode 100644 index 00000000..b65e53fd --- /dev/null +++ b/MobileAcebook/SignUpPageView.swift @@ -0,0 +1,120 @@ +// +// SignUpPageView.swift +// MobileAcebook +// +// Created by Santosh Dasari on 02/09/2024. +// + +import SwiftUI + +struct SignUpPageView: View { + + @State private var username = "" + @State private var email = "" + @State private var password = "" + @State private var confirmed_password = "" + @State private var checkedBox = false + +// This is the image stuff added just now 3rd september by Marya + @State private var selectedImage: UIImage? + @State private var isShowingImagePicker = false + + + var body: some View { + ZStack { + Color.black + .ignoresSafeArea() + + VStack { + Image("Logo") + .resizable() + .scaledToFit() + .frame(width: 200, height: 200) + .accessibilityIdentifier("Acebook-Logo") + + Text("Signup") + .font(.largeTitle) + .padding(.bottom, 20) + .accessibilityIdentifier("Signup Button") + .foregroundColor(Color.white) + .background(Color.black) + .font(.system(.body, design: .monospaced)) + + Button(action: { + isShowingImagePicker = true + }) { + if let selectedImage = selectedImage { + Image(uiImage: selectedImage) + .resizable() + .scaledToFill() + .frame(width: 100, height: 100) + .clipShape(Circle()) + .overlay(Circle().stroke(Color.white, lineWidth: 2)) + .shadow(radius: 10) + + } else { + Image(systemName: "person.crop.circle.badge.plus") + .resizable() + .scaledToFit() + .frame(width: 100, height: 100) + .foregroundColor(.white) + .padding() + } + } .sheet(isPresented: $isShowingImagePicker) { + ImagePicker(image: $selectedImage) + } + + Form { + Section { + TextField("Username", text: $username) + TextField("Email", text: $email) + TextField("Password", text: $password) + TextField("Confirm password", text: $confirmed_password) + } header:{ + Text("Account Details") + .foregroundColor(Color.white) + .background(Color.black) + .font(.system(.body, design: .monospaced)) + // TODO: sign up logic + } + } + .frame(width: 300.0, height: 250.0) + .scrollContentBackground(/*@START_MENU_TOKEN@*/.hidden/*@END_MENU_TOKEN@*/) + HStack{ + Text("Terms and Conditions") + .foregroundStyle(Color.white) + .font(.system(.body, design: .monospaced, weight: .light)) + Image(systemName: checkedBox ? "checkmark.circle.fill" : "circle") + .font(.system(size: 10)) + .scaleEffect(checkedBox ? 1.25 : 1.0) + .foregroundColor(checkedBox ? .green : .black) + .padding() + .onTapGesture { + withAnimation(.easeInOut(duration: 1.0)){ + checkedBox.toggle() + } + } + .background(.ultraThinMaterial, in: RoundedRectangle(cornerRadius: 20, style: .continuous)) + } + Button("Signup") { + print("Button Tapped") + } + .accessibilityIdentifier("Signup Button") + .buttonStyle(.borderedProminent) + .foregroundColor(Color.white) + .buttonBorderShape(.roundedRectangle(radius: 20)) + .font(.system(.body, design: .monospaced)) + .padding(40) + } + } + } + } + + + + struct SignUpPageView_Previews: PreviewProvider { + static var previews: some View { + SignUpPageView() + } + } + diff --git a/MobileAcebook/WelcomePageView.swift b/MobileAcebook/WelcomePageView.swift index 96006af9..afd7b58e 100644 --- a/MobileAcebook/WelcomePageView.swift +++ b/MobileAcebook/WelcomePageView.swift @@ -2,43 +2,70 @@ // WelcomePageView.swift // MobileAcebook // -// Created by Josué Estévez Fernández on 30/09/2023. +// Created by MARYA Estévez Fernández on 30/09/2023. // import SwiftUI + + + + struct WelcomePageView: View { var body: some View { - ZStack { - VStack { - Spacer() - - Text("Welcome to Acebook!") - .font(.largeTitle) - .padding(.bottom, 20) - .accessibilityIdentifier("welcomeText") - - Spacer() - - Image("makers-logo") - .resizable() - .scaledToFit() - .frame(width: 200, height: 200) - .accessibilityIdentifier("makers-logo") - - Spacer() - - Button("Sign Up") { - // TODO: sign up logic + NavigationView { + ZStack { + Color.black + .ignoresSafeArea() + + VStack { + Image("Logo") + .resizable() + .scaledToFit() + .frame(width: 200, height: 200) + .accessibilityIdentifier("Acebook-Logo") + + + Text("Welcome to acebook!") + .font(.largeTitle) + .padding(.bottom, 20) + .accessibilityIdentifier("welcomeText") + .foregroundColor(Color.white) + .background(Color.black) + .font(.system(.body, design: .monospaced)) + + HStack { + NavigationLink(destination: SignUpPageView()){ + Text("Sign Up") + + } + .accessibilityIdentifier("signUpButton") + .buttonStyle(.borderedProminent) + .foregroundColor(Color.white) + .buttonBorderShape(.roundedRectangle(radius: 20)) + .font(.system(.body, design: .monospaced)) + .padding(40) + + NavigationLink(destination: LoginPageView()) { // Changed to LoginView + Text("Login") + + } + .accessibilityIdentifier("LogInButton") + .buttonStyle(.borderedProminent) + .foregroundColor(Color.white) + .buttonBorderShape(.roundedRectangle(radius: 20)) + .font(.system(.body, design: .monospaced)) + .padding(40) + } } - .accessibilityIdentifier("signUpButton") - - Spacer() } } + .navigationBarBackButtonHidden(true) } } + + struct WelcomePageView_Previews: PreviewProvider { static var previews: some View { WelcomePageView() diff --git a/kin b/kin new file mode 100644 index 00000000..e69de29b