Post

Replies

Boosts

Views

Activity

Issue with Keyboard Avoidance for Sheet View in SwiftUI
I am currently working on a comments section modeled after TikTok's/Instagram's comment sections for a media app. The view is a sheet view that is presented as follows: .sheet(isPresented: $showChat) { TakesChatView(viewModel: viewModel) .presentationDetents([.medium, .large]) .presentationDragIndicator(.hidden) .overlay( VStack { RoundedRectangle(cornerRadius: 2) .fill(Color.gray) .frame(width: 40, height: 5) .padding(.top, 15) .opacity(0.8) Label("Chat", systemImage: "message.badge") .lineLimit(nil) .padding(.top, 5) .padding([.leading, .trailing], 16) Divider() .padding(.top, 5) .padding([.leading, .trailing], 16) Spacer() } .frame(maxWidth: .infinity, alignment: .top) ) }.ignoresSafeArea(.keyboard, edges: .bottom) However, some issues arise regarding keyboard avoidance. Currently, when the user taps on the TextField to type a comment, the keyboard shifts the entire view upwards as it pops up. Instead, I need it where I can still view the comments without the keyboard affecting their placement when it pop up. Below is the associated code for the comment view: struct TakesChatView: View { @ObservedObject var viewModel: TakeCommentViewModel @FocusState var focus: Bool @State private var selectedMedia: [PhotosPickerItem] = [] @State private var selectedImageData: [Data] = [] @State private var selectedGIFData: [Data] = [] @State private var selectedVideoData: [Data] = [] var textFieldNotEmpty: Bool { !viewModel.textToPost.isEmpty || !selectedImageData.isEmpty || !selectedGIFData.isEmpty || !selectedVideoData.isEmpty } var body: some View { GeometryReader { _ in ZStack { VStack { contentView commentTextField .padding(.top,5) } } } .ignoresSafeArea(.keyboard, edges: .bottom) .background(Color.containerBackground) .onChange(of: viewModel.focus) { focus in self.focus = focus } .onChange(of: selectedMedia) { _ in loadMedia() } } var contentView: some View { VStack { Spacer().frame(height: 105) ScrollViewReader { scroll in ScrollView(showsIndicators: true) { ForEach(viewModel.comments, id: \.self) { comment in TakeCommentView( comment: comment, viewModel: self.viewModel ) .padding(.horizontal, 10) .id(comment.documentID) } .onChange(of: viewModel.commentAdded) { id in scroll.scrollTo(id, anchor: .bottom) viewModel.commentAdded = nil } } .scrollDismissesKeyboard(.immediately) } } } } extension TakesChatView { var commentTextField: some View { VStack { mediaPreview HStack { TextField("Type your comment", text: $viewModel.textToPost, axis: .vertical) .keyboardType(.twitter) .padding([.leading, .vertical], 6) .focused($focus) PhotosPicker(selection: $selectedMedia, matching: .any(of: [.images, .videos]), photoLibrary: .shared()) { ComposeType.media.image .frame(width: 40, height: 40, alignment: .center) } .onAppear { selectedMedia.removeAll() selectedImageData.removeAll() selectedGIFData.removeAll() selectedVideoData.removeAll() } postButton } .border(.lightGray, width: 1, cornerRadius: 10) .padding([.bottom, .horizontal], 10) } } } I have tried using .ignoresSafeAres(), .safeAreaInset(), and custom keyboard observer functions but to no avail. How do I fix this issue?
1
0
804
Sep ’24
SwiftUI SideMenu Navigation Issue
I am currently refactoring my app's side menu to be more like Twitter's. I have the UI down in terms of how the side menu looks and appears, but the issue is navigating to a view from the side menu. The views that a user can go to from the side menu are a mix of SwiftUI views & UIKit View Controllers. As of right now, when a user navigates to a view from the side menu, it presents it modally as a sheet. I want it to have regular navigation, where the user goes to the view displayed in full screen and can tap on the back button to go back to the previous view. Here is the associated code: SideMenuView.swift SideMenuViewModel.swift How can I modify the navigation logic to be like Twitter's? I've been stuck for days trying to find a fix but it has been a struggle.
1
0
834
Jun ’24
Error When Saving Video To Camera Roll
I am working on enabling the option for users to save a video from a post in a social media app to their cameral roll. I am trying to use PHPhotoLibrary to perform the task similarly to how I did the functionality for saving images and gifs. However, when I try to perform the task with the code as is, I get the following errors: Error Domain=PHPhotosErrorDomain Code=-1 "(null)" The operation couldn’t be completed. (PHPhotosErrorDomain error -1.) The implementation is as follows: Button(action: { guard let videoURL = URL(string: media.link.absoluteString) else { print("Invalid video url.") return } PHPhotoLibrary.shared().performChanges({ PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: videoURL) print("Video URL: \(videoURL)") }) { (success, error) in if let error = error { debugPrint(error) print(error.localizedDescription) } else { print("Video saved to camera roll!") } } }) { Text("Save Video") Image(systemName: "square.and.arrow.down") } The video URL is successfully fetched dynamically from the post, but there's an issue with storing it locally in the library. What am I missing?
1
0
1.1k
Feb ’24
Double Tap Not Being Detected Anywhere In Video
I am working on implementing tap gestures in a dynamic VideoPlayer made with AVKit. I intend to have it be when a video is viewed in a feed (this is for a social media app), the video plays without sound. Tapping on the video once enables sound, tapping on the video twice makes it full screen. Currently, the single tap works. However, the double tap isn't detected unless I tap on the top right corner of the video. import SwiftUI import AVKit struct VideoPlayerView: View { @StateObject private var viewModel: VideoPlayerViewModel init(url: URL, isFeedView: Bool = true) { _viewModel = StateObject(wrappedValue: .init(url: url, isFeedView: isFeedView)) } var body: some View { ZStack { if let player: AVPlayer = viewModel.player { VideoPlayer(player: player) .onAppear { // Start playing or resume from the last known position if in feed view if viewModel.isFeedView { if let lastKnownTime = viewModel.lastKnownTime { player.seek(to: CMTime(seconds: lastKnownTime, preferredTimescale: 600)) } player.play() player.volume = 0 // Set volume to 0 for feed view } } .onDisappear { // Pause the video and store the last known time viewModel.lastKnownTime = player.currentTime().seconds player.pause() } .contentShape(Rectangle()) .gesture(TapGesture(count: 2).onEnded { print("Double tap detected") viewModel.isFullScreen.toggle() }) .simultaneousGesture(TapGesture().onEnded { print("Single tap detected") player.volume = 1 // Set volume to 1 }) } } .maxSize() .fullScreenCover(isPresented: $viewModel.isFullScreen) { AVPlayerViewControllerRepresented(viewModel: viewModel) } } } class VideoPlayerViewModel: ObservableObject { @Published var player: AVPlayer? @Published var lastKnownTime: Double? @Published var isFullScreen: Bool = false @Published var isFeedView: Bool init(url: URL, isFeedView: Bool = true) { player = AVPlayer(url: url) lastKnownTime = nil self.isFeedView = isFeedView if isFeedView { registerForPlaybackEndNotification() } } private func registerForPlaybackEndNotification() { NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: player?.currentItem, queue: nil) { [weak self] _ in self?.videoDidFinish() } } private func videoDidFinish() { // Replay logic for feed view if isFeedView, let player = player { player.seek(to: .zero) player.play() } } } I tried using .contentShape(Rectangle()) as I read that it expands the detectable area for taps, but to no avail. How can I have it so that when I double tap anywhere in the video, it's detected and the video goes full screen?
0
0
855
Jan ’24
Inputted values in SignUpView won't save to backend
I am currently refactoring the signup process for a sports media app in SwiftUI and having issues trying to have it save data associated with the new user to the backend (comprised of a mix of Firebase and a custom backend) via a signup function in an AuthService class. Whenever I enter the required info to create an account (email, username, password, etc.), I get the following errors Error: The data couldn’t be read because it is missing. Swift.DecodingError.keyNotFound(CodingKeys(stringValue: "user", intValue: nil), Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "data", intValue: nil)], debugDescription: "No value associated with key CodingKeys(stringValue: \"user\", intValue: nil) (\"user\").", underlyingError: nil)) Here is all the relevant code: SignUpView.swift AuthService.swift Signup.swift For AuthService, the signup function is what's relevant as I call it in SignUpView and SignUp has the definition for AccountSignUp which is called in the other two files. What is not being read correctly in the data? What is missing and what can be done to fix it such that the info will be saved to the backend? All help will be greatly appreciated!
0
0
579
Nov ’23
Having Proper Message Functionality with Parse, UIKit and MessageKit
For my iOS Social Media App project, I am currently working on the Direct Messaging feature of the app. As of making this post, I have the basic functionality working where you can send messages to other users in the app. However, there are a few issues I am experiencing. 1.) When I go to the chat to send a message it shows two text input bars instead of one. It could have something to do with me also using InputBarAccessoryView but I am not sure how to go about removing one of the two input bars so there's only one. 2.) Being able to see the other user's texts and replies. I can send a message to the user but said user won't be able to see it and vice versa for some reason I haven't been able to fetch and load chat history properly. 3.) The chats don't have their own unique messages. If I send a message to one user, it shows up in my chats with other users as well rather than each chat having its own unique messages. Here is my code associated with Messaging import UIKit import MessageKit import InputBarAccessoryView import Parse struct Message: MessageType { var sender: SenderType var messageId: String var sentDate: Date var kind: MessageKind } class ChatViewController: MessagesViewController, MessagesDataSource, MessagesLayoutDelegate, MessagesDisplayDelegate, InputBarAccessoryViewDelegate { let currentUser = PFUser.current()! var otherUser: PFUser! var messages = [MessageType]() var inputBar = InputBarAccessoryView() override func viewDidLoad() { super.viewDidLoad() // Set up the other user let query = PFUser.query() query?.whereKey("objectId", notEqualTo: currentUser.objectId!) query?.findObjectsInBackground(block: { (objects, error) in if let users = objects as? [PFUser], let user = users.first { self.otherUser = user // Retrieve previous messages from Parse let messageQuery = PFQuery(className: "Message") messageQuery.whereKey("sender", equalTo: self.currentUser) messageQuery.whereKey("recipient", equalTo: self.otherUser!) let recipientQuery = PFQuery(className: "Message") recipientQuery.whereKey("sender", equalTo: self.otherUser!) recipientQuery.whereKey("recipient", equalTo: self.currentUser) let query = PFQuery.orQuery(withSubqueries: [messageQuery, recipientQuery]) query.findObjectsInBackground { (objects, error) in if let messages = objects { for message in messages { let sender = message["sender"] as! PFUser let text = message["text"] as! String let sentDate = message.createdAt! let messageKind = MessageKind.text(text) let messageSender: Sender do { try sender.fetchIfNeeded() messageSender = Sender(senderId: sender.objectId!, displayName: sender.username ?? "") } catch { messageSender = Sender(senderId: sender.objectId!, displayName: "Unknown") print("Error fetching sender: \(error.localizedDescription)") } let message = Message(sender: messageSender, messageId: message.objectId!, sentDate: sentDate, kind: messageKind) self.messages.append(message) print("Fetched previous messages!") } self.messagesCollectionView.reloadData() self.messagesCollectionView.scrollToLastItem(animated: false) } } } }) // Configure the messages collection view and input bar messagesCollectionView.messagesDataSource = self messagesCollectionView.messagesLayoutDelegate = self messagesCollectionView.messagesDisplayDelegate = self view.addSubview(inputBar) inputBar.delegate = self inputBar.inputTextView.placeholder = "Type a message..." inputBar.sendButton.setTitle("Send", for: .normal) inputBar.sendButton.setTitleColor(view.tintColor, for: .normal) inputBar.sendButton.addTarget(self, action: #selector(sendButtonPressed), for: .touchUpInside) inputBar.translatesAutoresizingMaskIntoConstraints = false inputBar.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true inputBar.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true inputBar.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true } func currentSender() -> SenderType { return Sender(senderId: currentUser.objectId!, displayName: currentUser.username ?? "") } func numberOfSections(in messagesCollectionView: MessagesCollectionView) -> Int { return messages.count } func messageForItem(at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageType { return messages[indexPath.section] } @objc func sendButtonPressed() { let messageText = inputBar.inputTextView.text.trimmingCharacters(in: .whitespacesAndNewlines) guard !messageText.isEmpty else { return } let message = Message(sender: currentSender(), messageId: UUID().uuidString, sentDate: Date(), kind: .text(messageText)) messages.append(message) inputBar.inputTextView.text = "" messagesCollectionView.reloadData() messagesCollectionView.scrollToLastItem(animated: true) print("Message sent!") // Save the message to Parse let parseMessage = PFObject(className: "Message") parseMessage["sender"] = currentUser parseMessage["recipient"] = otherUser parseMessage["text"] = messageText parseMessage.saveInBackground() print("Message saved!") } func inputBar(_ inputBar: InputBarAccessoryView, textViewTextDidChangeTo text: String) { if text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty { inputBar.sendButton.isEnabled = false } else { inputBar.sendButton.isEnabled = true } } func inputBar(_ inputBar: InputBarAccessoryView, didPressSendButtonWith text: String) { sendButtonPressed() } } The above code is for all the messaging functionality such as sending texts, receiving messages, and loading and showing chat history. All help would be greatly appreciated!
0
0
1.1k
Apr ’23
Having In-App Notifications Vary By User in App
I am working on in-app notifications for my social media app that I'm programming using Parse and UIKit on Xcode 14.2. My main issue is that while the notification system itself is working, it's not varying by the user. For example, say there are two users, User1 and User2. The way the notifications should be set up is when User1 likes User2's post or leaves a comment on User2's post, only User2 gets a notification saying "User1 liked your post!" or "User1 left a comment on your post!". However as of right now, when User1 likes or comment's on User2's post, User1 gets the notification saying "User1 liked your post!". Here is the code that implements notifications in my app: import UIKit import Parse class NotificationViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { @IBOutlet weak var tableView: UITableView! var notifications: [PFObject] = [] override func viewDidLoad() { super.viewDidLoad() tableView.delegate = self tableView.dataSource = self NotificationCenter.default.addObserver(self, selector: #selector(didLikePost(_:)), name: NSNotification.Name("PostLikedByOtherUser"), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(madeCommentOnPost(_:)), name: NSNotification.Name("CommentMade"), object: nil) let notificationClass = PFObject(className: "Notification") notificationClass["user"] = PFUser.current() notificationClass["fromUser"] = PFUser.current() notificationClass["post"] = PFObject(className: "Post") notificationClass.saveInBackground { (success, error) in if success { print("Notification class created successfully") } else if let error = error { print("Error creating notification class: \(error.localizedDescription)") } } } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) let query = PFQuery(className: "Notification") query.whereKey("user", equalTo: PFUser.current()!) query.includeKey("fromUser") query.includeKey("post") query.order(byDescending: "createdAt") query.findObjectsInBackground { (objects, error) in if let error = error { print("Error querying for notifications: \(error.localizedDescription)") } else if let notifications = objects { self.notifications = notifications self.tableView.reloadData() } } } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return notifications.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "NotificationCell", for: indexPath) as! NotificationCell let notification = notifications[indexPath.row] let fromUser = notification["fromUser"] as! PFUser let post = notification["post"] as? PFObject cell.usernameLabel.text = fromUser.username if let username = fromUser.username, let post = post { if let likes = post["likes"] as? [PFObject], let _ = likes.first(where: { $0["liker"] as? String == PFUser.current()?.objectId }), post["user"] as? String == PFUser.current()?.objectId { cell.messageLabel.text = "You liked your own post." } else if let comments = post["comments"] as? [PFObject], let _ = comments.first(where: { $0["commenter"] as? String == PFUser.current()?.objectId }) { cell.messageLabel.text = "You liked \(username)'s post." } else if let _ = notification["comment"] { cell.messageLabel.text = "\(username) commented on your post." } else { cell.messageLabel.text = "\(username) liked your post." } } return cell } @objc func didLikePost(_ notification: Notification) { guard let post = notification.object as? PFObject, let postOwner = post["user"] as? PFUser, let liker = notification.userInfo?["liker"] as? PFUser, postOwner.objectId != liker.objectId, postOwner.objectId == PFUser.current()?.objectId else { return } let notificationObject = PFObject(className: "Notification") notificationObject["user"] = postOwner notificationObject["fromUser"] = liker notificationObject["post"] = post notificationObject.saveInBackground { (success, error) in if success { print("Successfully created notification") } else if let error = error { print("Error creating notification: \(error.localizedDescription)") } } } @objc func madeCommentOnPost(_ notification: Notification) { guard let comment = notification.object as? PFObject, let post = comment["post"] as? PFObject, let postOwner = post["user"] as? PFUser, let commenter = notification.userInfo?["commenter"] as? PFUser, postOwner.objectId != commenter.objectId, postOwner.objectId == PFUser.current()?.objectId else { return } let notificationObject = PFObject(className: "Notification") notificationObject["user"] = postOwner notificationObject["fromUser"] = commenter notificationObject["post"] = post notificationObject.saveInBackground { (success, error) in if success { print("Successfully created notification") } else if let error = error { print("Error creating notification: \(error.localizedDescription)") } } } deinit { NotificationCenter.default.removeObserver(self) } } I would really appreciate all the help on here.
1
0
674
Apr ’23
Unable to get alerts to show on simulator screen
I am currently working on a social media app and so far I have been able to make a LoginViewController & a SignUpVIewController. Right now I am currently trying to have it where on the SignUpViewController if not all required fields are filled out then the app will display an alert. However, every time i run the app the alert doesn't show up on the simulator screen. Same goes for Xcode's terminal. My code for the SignUpViewController is as follows: import UIKit import Parse class SignUpViewController: UIViewController {   @IBOutlet weak var emailTextField: UITextField!       @IBOutlet weak var usernameTextField: UITextField!       @IBOutlet weak var passwordTextField: UITextField!       @IBOutlet weak var confirmPasswordFieldText: UITextField!       @IBOutlet weak var signUpButton: UIButton!           override func viewDidLoad() {     super.viewDidLoad()   }           @IBAction func signUpButtonTapped(_ sender: UIButton)   {     let username = usernameTextField.text     let password = passwordTextField.text     let email = emailTextField.text     let confirmpw = confirmPasswordFieldText.text           if username == "" || password == "" || email == "" || confirmpw == ""     {       let alert = UIAlertController(title: "Error", message: "Please fill out all required fields", preferredStyle: .alert)       alert.addAction(UIAlertAction(title: "OK", style: .default,handler: nil))       present(alert, animated: true, completion: nil)       return     }           let newUser = User(username: username!, password: password!, email: email!)   }         }     class User {   var username: String   var password: String   var email: String       init(username: String, password: String, email: String) {     self.username = username     self.password = password     self.email = email   } } All the buttons are connected to the correct spots. Would greatly appreciate if anyone can help me fix this.
1
0
565
Feb ’23
Repeated Crash Reports when I add code to a project
I am doing the Swift Landmarks app tutorial on Xcode 13.2.1 on my 2019 Macbook Pro. I am up to the Working with UI Controls section. Every time I add the following lines of code to ProfileSummary.swift: @EnvironmentObject var modelData: ModelData . . . Divider()                   VStack(alignment: .leading)         {                   Text("Recent Hikes")                     .font(.headline)                   HikeView(hike: modelData.hikes[0])         } and I then try to view the preview I repeatedly get a crash report and everything stops working. When I remove those lines of code everything goes back to working fine. The crash report is in this attachment: Translated Crash Report ^ That is the translated report. If you guys would like the full report I will post it. I am stuck and don't know what to do any help will be appreciated!
1
0
1.5k
Feb ’22
Issue with Keyboard Avoidance for Sheet View in SwiftUI
I am currently working on a comments section modeled after TikTok's/Instagram's comment sections for a media app. The view is a sheet view that is presented as follows: .sheet(isPresented: $showChat) { TakesChatView(viewModel: viewModel) .presentationDetents([.medium, .large]) .presentationDragIndicator(.hidden) .overlay( VStack { RoundedRectangle(cornerRadius: 2) .fill(Color.gray) .frame(width: 40, height: 5) .padding(.top, 15) .opacity(0.8) Label("Chat", systemImage: "message.badge") .lineLimit(nil) .padding(.top, 5) .padding([.leading, .trailing], 16) Divider() .padding(.top, 5) .padding([.leading, .trailing], 16) Spacer() } .frame(maxWidth: .infinity, alignment: .top) ) }.ignoresSafeArea(.keyboard, edges: .bottom) However, some issues arise regarding keyboard avoidance. Currently, when the user taps on the TextField to type a comment, the keyboard shifts the entire view upwards as it pops up. Instead, I need it where I can still view the comments without the keyboard affecting their placement when it pop up. Below is the associated code for the comment view: struct TakesChatView: View { @ObservedObject var viewModel: TakeCommentViewModel @FocusState var focus: Bool @State private var selectedMedia: [PhotosPickerItem] = [] @State private var selectedImageData: [Data] = [] @State private var selectedGIFData: [Data] = [] @State private var selectedVideoData: [Data] = [] var textFieldNotEmpty: Bool { !viewModel.textToPost.isEmpty || !selectedImageData.isEmpty || !selectedGIFData.isEmpty || !selectedVideoData.isEmpty } var body: some View { GeometryReader { _ in ZStack { VStack { contentView commentTextField .padding(.top,5) } } } .ignoresSafeArea(.keyboard, edges: .bottom) .background(Color.containerBackground) .onChange(of: viewModel.focus) { focus in self.focus = focus } .onChange(of: selectedMedia) { _ in loadMedia() } } var contentView: some View { VStack { Spacer().frame(height: 105) ScrollViewReader { scroll in ScrollView(showsIndicators: true) { ForEach(viewModel.comments, id: \.self) { comment in TakeCommentView( comment: comment, viewModel: self.viewModel ) .padding(.horizontal, 10) .id(comment.documentID) } .onChange(of: viewModel.commentAdded) { id in scroll.scrollTo(id, anchor: .bottom) viewModel.commentAdded = nil } } .scrollDismissesKeyboard(.immediately) } } } } extension TakesChatView { var commentTextField: some View { VStack { mediaPreview HStack { TextField("Type your comment", text: $viewModel.textToPost, axis: .vertical) .keyboardType(.twitter) .padding([.leading, .vertical], 6) .focused($focus) PhotosPicker(selection: $selectedMedia, matching: .any(of: [.images, .videos]), photoLibrary: .shared()) { ComposeType.media.image .frame(width: 40, height: 40, alignment: .center) } .onAppear { selectedMedia.removeAll() selectedImageData.removeAll() selectedGIFData.removeAll() selectedVideoData.removeAll() } postButton } .border(.lightGray, width: 1, cornerRadius: 10) .padding([.bottom, .horizontal], 10) } } } I have tried using .ignoresSafeAres(), .safeAreaInset(), and custom keyboard observer functions but to no avail. How do I fix this issue?
Replies
1
Boosts
0
Views
804
Activity
Sep ’24
SwiftUI SideMenu Navigation Issue
I am currently refactoring my app's side menu to be more like Twitter's. I have the UI down in terms of how the side menu looks and appears, but the issue is navigating to a view from the side menu. The views that a user can go to from the side menu are a mix of SwiftUI views & UIKit View Controllers. As of right now, when a user navigates to a view from the side menu, it presents it modally as a sheet. I want it to have regular navigation, where the user goes to the view displayed in full screen and can tap on the back button to go back to the previous view. Here is the associated code: SideMenuView.swift SideMenuViewModel.swift How can I modify the navigation logic to be like Twitter's? I've been stuck for days trying to find a fix but it has been a struggle.
Replies
1
Boosts
0
Views
834
Activity
Jun ’24
Error When Saving Video To Camera Roll
I am working on enabling the option for users to save a video from a post in a social media app to their cameral roll. I am trying to use PHPhotoLibrary to perform the task similarly to how I did the functionality for saving images and gifs. However, when I try to perform the task with the code as is, I get the following errors: Error Domain=PHPhotosErrorDomain Code=-1 "(null)" The operation couldn’t be completed. (PHPhotosErrorDomain error -1.) The implementation is as follows: Button(action: { guard let videoURL = URL(string: media.link.absoluteString) else { print("Invalid video url.") return } PHPhotoLibrary.shared().performChanges({ PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: videoURL) print("Video URL: \(videoURL)") }) { (success, error) in if let error = error { debugPrint(error) print(error.localizedDescription) } else { print("Video saved to camera roll!") } } }) { Text("Save Video") Image(systemName: "square.and.arrow.down") } The video URL is successfully fetched dynamically from the post, but there's an issue with storing it locally in the library. What am I missing?
Replies
1
Boosts
0
Views
1.1k
Activity
Feb ’24
Double Tap Not Being Detected Anywhere In Video
I am working on implementing tap gestures in a dynamic VideoPlayer made with AVKit. I intend to have it be when a video is viewed in a feed (this is for a social media app), the video plays without sound. Tapping on the video once enables sound, tapping on the video twice makes it full screen. Currently, the single tap works. However, the double tap isn't detected unless I tap on the top right corner of the video. import SwiftUI import AVKit struct VideoPlayerView: View { @StateObject private var viewModel: VideoPlayerViewModel init(url: URL, isFeedView: Bool = true) { _viewModel = StateObject(wrappedValue: .init(url: url, isFeedView: isFeedView)) } var body: some View { ZStack { if let player: AVPlayer = viewModel.player { VideoPlayer(player: player) .onAppear { // Start playing or resume from the last known position if in feed view if viewModel.isFeedView { if let lastKnownTime = viewModel.lastKnownTime { player.seek(to: CMTime(seconds: lastKnownTime, preferredTimescale: 600)) } player.play() player.volume = 0 // Set volume to 0 for feed view } } .onDisappear { // Pause the video and store the last known time viewModel.lastKnownTime = player.currentTime().seconds player.pause() } .contentShape(Rectangle()) .gesture(TapGesture(count: 2).onEnded { print("Double tap detected") viewModel.isFullScreen.toggle() }) .simultaneousGesture(TapGesture().onEnded { print("Single tap detected") player.volume = 1 // Set volume to 1 }) } } .maxSize() .fullScreenCover(isPresented: $viewModel.isFullScreen) { AVPlayerViewControllerRepresented(viewModel: viewModel) } } } class VideoPlayerViewModel: ObservableObject { @Published var player: AVPlayer? @Published var lastKnownTime: Double? @Published var isFullScreen: Bool = false @Published var isFeedView: Bool init(url: URL, isFeedView: Bool = true) { player = AVPlayer(url: url) lastKnownTime = nil self.isFeedView = isFeedView if isFeedView { registerForPlaybackEndNotification() } } private func registerForPlaybackEndNotification() { NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: player?.currentItem, queue: nil) { [weak self] _ in self?.videoDidFinish() } } private func videoDidFinish() { // Replay logic for feed view if isFeedView, let player = player { player.seek(to: .zero) player.play() } } } I tried using .contentShape(Rectangle()) as I read that it expands the detectable area for taps, but to no avail. How can I have it so that when I double tap anywhere in the video, it's detected and the video goes full screen?
Replies
0
Boosts
0
Views
855
Activity
Jan ’24
Inputted values in SignUpView won't save to backend
I am currently refactoring the signup process for a sports media app in SwiftUI and having issues trying to have it save data associated with the new user to the backend (comprised of a mix of Firebase and a custom backend) via a signup function in an AuthService class. Whenever I enter the required info to create an account (email, username, password, etc.), I get the following errors Error: The data couldn’t be read because it is missing. Swift.DecodingError.keyNotFound(CodingKeys(stringValue: "user", intValue: nil), Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "data", intValue: nil)], debugDescription: "No value associated with key CodingKeys(stringValue: \"user\", intValue: nil) (\"user\").", underlyingError: nil)) Here is all the relevant code: SignUpView.swift AuthService.swift Signup.swift For AuthService, the signup function is what's relevant as I call it in SignUpView and SignUp has the definition for AccountSignUp which is called in the other two files. What is not being read correctly in the data? What is missing and what can be done to fix it such that the info will be saved to the backend? All help will be greatly appreciated!
Replies
0
Boosts
0
Views
579
Activity
Nov ’23
Having Proper Message Functionality with Parse, UIKit and MessageKit
For my iOS Social Media App project, I am currently working on the Direct Messaging feature of the app. As of making this post, I have the basic functionality working where you can send messages to other users in the app. However, there are a few issues I am experiencing. 1.) When I go to the chat to send a message it shows two text input bars instead of one. It could have something to do with me also using InputBarAccessoryView but I am not sure how to go about removing one of the two input bars so there's only one. 2.) Being able to see the other user's texts and replies. I can send a message to the user but said user won't be able to see it and vice versa for some reason I haven't been able to fetch and load chat history properly. 3.) The chats don't have their own unique messages. If I send a message to one user, it shows up in my chats with other users as well rather than each chat having its own unique messages. Here is my code associated with Messaging import UIKit import MessageKit import InputBarAccessoryView import Parse struct Message: MessageType { var sender: SenderType var messageId: String var sentDate: Date var kind: MessageKind } class ChatViewController: MessagesViewController, MessagesDataSource, MessagesLayoutDelegate, MessagesDisplayDelegate, InputBarAccessoryViewDelegate { let currentUser = PFUser.current()! var otherUser: PFUser! var messages = [MessageType]() var inputBar = InputBarAccessoryView() override func viewDidLoad() { super.viewDidLoad() // Set up the other user let query = PFUser.query() query?.whereKey("objectId", notEqualTo: currentUser.objectId!) query?.findObjectsInBackground(block: { (objects, error) in if let users = objects as? [PFUser], let user = users.first { self.otherUser = user // Retrieve previous messages from Parse let messageQuery = PFQuery(className: "Message") messageQuery.whereKey("sender", equalTo: self.currentUser) messageQuery.whereKey("recipient", equalTo: self.otherUser!) let recipientQuery = PFQuery(className: "Message") recipientQuery.whereKey("sender", equalTo: self.otherUser!) recipientQuery.whereKey("recipient", equalTo: self.currentUser) let query = PFQuery.orQuery(withSubqueries: [messageQuery, recipientQuery]) query.findObjectsInBackground { (objects, error) in if let messages = objects { for message in messages { let sender = message["sender"] as! PFUser let text = message["text"] as! String let sentDate = message.createdAt! let messageKind = MessageKind.text(text) let messageSender: Sender do { try sender.fetchIfNeeded() messageSender = Sender(senderId: sender.objectId!, displayName: sender.username ?? "") } catch { messageSender = Sender(senderId: sender.objectId!, displayName: "Unknown") print("Error fetching sender: \(error.localizedDescription)") } let message = Message(sender: messageSender, messageId: message.objectId!, sentDate: sentDate, kind: messageKind) self.messages.append(message) print("Fetched previous messages!") } self.messagesCollectionView.reloadData() self.messagesCollectionView.scrollToLastItem(animated: false) } } } }) // Configure the messages collection view and input bar messagesCollectionView.messagesDataSource = self messagesCollectionView.messagesLayoutDelegate = self messagesCollectionView.messagesDisplayDelegate = self view.addSubview(inputBar) inputBar.delegate = self inputBar.inputTextView.placeholder = "Type a message..." inputBar.sendButton.setTitle("Send", for: .normal) inputBar.sendButton.setTitleColor(view.tintColor, for: .normal) inputBar.sendButton.addTarget(self, action: #selector(sendButtonPressed), for: .touchUpInside) inputBar.translatesAutoresizingMaskIntoConstraints = false inputBar.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true inputBar.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true inputBar.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true } func currentSender() -> SenderType { return Sender(senderId: currentUser.objectId!, displayName: currentUser.username ?? "") } func numberOfSections(in messagesCollectionView: MessagesCollectionView) -> Int { return messages.count } func messageForItem(at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageType { return messages[indexPath.section] } @objc func sendButtonPressed() { let messageText = inputBar.inputTextView.text.trimmingCharacters(in: .whitespacesAndNewlines) guard !messageText.isEmpty else { return } let message = Message(sender: currentSender(), messageId: UUID().uuidString, sentDate: Date(), kind: .text(messageText)) messages.append(message) inputBar.inputTextView.text = "" messagesCollectionView.reloadData() messagesCollectionView.scrollToLastItem(animated: true) print("Message sent!") // Save the message to Parse let parseMessage = PFObject(className: "Message") parseMessage["sender"] = currentUser parseMessage["recipient"] = otherUser parseMessage["text"] = messageText parseMessage.saveInBackground() print("Message saved!") } func inputBar(_ inputBar: InputBarAccessoryView, textViewTextDidChangeTo text: String) { if text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty { inputBar.sendButton.isEnabled = false } else { inputBar.sendButton.isEnabled = true } } func inputBar(_ inputBar: InputBarAccessoryView, didPressSendButtonWith text: String) { sendButtonPressed() } } The above code is for all the messaging functionality such as sending texts, receiving messages, and loading and showing chat history. All help would be greatly appreciated!
Replies
0
Boosts
0
Views
1.1k
Activity
Apr ’23
Having In-App Notifications Vary By User in App
I am working on in-app notifications for my social media app that I'm programming using Parse and UIKit on Xcode 14.2. My main issue is that while the notification system itself is working, it's not varying by the user. For example, say there are two users, User1 and User2. The way the notifications should be set up is when User1 likes User2's post or leaves a comment on User2's post, only User2 gets a notification saying "User1 liked your post!" or "User1 left a comment on your post!". However as of right now, when User1 likes or comment's on User2's post, User1 gets the notification saying "User1 liked your post!". Here is the code that implements notifications in my app: import UIKit import Parse class NotificationViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { @IBOutlet weak var tableView: UITableView! var notifications: [PFObject] = [] override func viewDidLoad() { super.viewDidLoad() tableView.delegate = self tableView.dataSource = self NotificationCenter.default.addObserver(self, selector: #selector(didLikePost(_:)), name: NSNotification.Name("PostLikedByOtherUser"), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(madeCommentOnPost(_:)), name: NSNotification.Name("CommentMade"), object: nil) let notificationClass = PFObject(className: "Notification") notificationClass["user"] = PFUser.current() notificationClass["fromUser"] = PFUser.current() notificationClass["post"] = PFObject(className: "Post") notificationClass.saveInBackground { (success, error) in if success { print("Notification class created successfully") } else if let error = error { print("Error creating notification class: \(error.localizedDescription)") } } } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) let query = PFQuery(className: "Notification") query.whereKey("user", equalTo: PFUser.current()!) query.includeKey("fromUser") query.includeKey("post") query.order(byDescending: "createdAt") query.findObjectsInBackground { (objects, error) in if let error = error { print("Error querying for notifications: \(error.localizedDescription)") } else if let notifications = objects { self.notifications = notifications self.tableView.reloadData() } } } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return notifications.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "NotificationCell", for: indexPath) as! NotificationCell let notification = notifications[indexPath.row] let fromUser = notification["fromUser"] as! PFUser let post = notification["post"] as? PFObject cell.usernameLabel.text = fromUser.username if let username = fromUser.username, let post = post { if let likes = post["likes"] as? [PFObject], let _ = likes.first(where: { $0["liker"] as? String == PFUser.current()?.objectId }), post["user"] as? String == PFUser.current()?.objectId { cell.messageLabel.text = "You liked your own post." } else if let comments = post["comments"] as? [PFObject], let _ = comments.first(where: { $0["commenter"] as? String == PFUser.current()?.objectId }) { cell.messageLabel.text = "You liked \(username)'s post." } else if let _ = notification["comment"] { cell.messageLabel.text = "\(username) commented on your post." } else { cell.messageLabel.text = "\(username) liked your post." } } return cell } @objc func didLikePost(_ notification: Notification) { guard let post = notification.object as? PFObject, let postOwner = post["user"] as? PFUser, let liker = notification.userInfo?["liker"] as? PFUser, postOwner.objectId != liker.objectId, postOwner.objectId == PFUser.current()?.objectId else { return } let notificationObject = PFObject(className: "Notification") notificationObject["user"] = postOwner notificationObject["fromUser"] = liker notificationObject["post"] = post notificationObject.saveInBackground { (success, error) in if success { print("Successfully created notification") } else if let error = error { print("Error creating notification: \(error.localizedDescription)") } } } @objc func madeCommentOnPost(_ notification: Notification) { guard let comment = notification.object as? PFObject, let post = comment["post"] as? PFObject, let postOwner = post["user"] as? PFUser, let commenter = notification.userInfo?["commenter"] as? PFUser, postOwner.objectId != commenter.objectId, postOwner.objectId == PFUser.current()?.objectId else { return } let notificationObject = PFObject(className: "Notification") notificationObject["user"] = postOwner notificationObject["fromUser"] = commenter notificationObject["post"] = post notificationObject.saveInBackground { (success, error) in if success { print("Successfully created notification") } else if let error = error { print("Error creating notification: \(error.localizedDescription)") } } } deinit { NotificationCenter.default.removeObserver(self) } } I would really appreciate all the help on here.
Replies
1
Boosts
0
Views
674
Activity
Apr ’23
Unable to get alerts to show on simulator screen
I am currently working on a social media app and so far I have been able to make a LoginViewController & a SignUpVIewController. Right now I am currently trying to have it where on the SignUpViewController if not all required fields are filled out then the app will display an alert. However, every time i run the app the alert doesn't show up on the simulator screen. Same goes for Xcode's terminal. My code for the SignUpViewController is as follows: import UIKit import Parse class SignUpViewController: UIViewController {   @IBOutlet weak var emailTextField: UITextField!       @IBOutlet weak var usernameTextField: UITextField!       @IBOutlet weak var passwordTextField: UITextField!       @IBOutlet weak var confirmPasswordFieldText: UITextField!       @IBOutlet weak var signUpButton: UIButton!           override func viewDidLoad() {     super.viewDidLoad()   }           @IBAction func signUpButtonTapped(_ sender: UIButton)   {     let username = usernameTextField.text     let password = passwordTextField.text     let email = emailTextField.text     let confirmpw = confirmPasswordFieldText.text           if username == "" || password == "" || email == "" || confirmpw == ""     {       let alert = UIAlertController(title: "Error", message: "Please fill out all required fields", preferredStyle: .alert)       alert.addAction(UIAlertAction(title: "OK", style: .default,handler: nil))       present(alert, animated: true, completion: nil)       return     }           let newUser = User(username: username!, password: password!, email: email!)   }         }     class User {   var username: String   var password: String   var email: String       init(username: String, password: String, email: String) {     self.username = username     self.password = password     self.email = email   } } All the buttons are connected to the correct spots. Would greatly appreciate if anyone can help me fix this.
Replies
1
Boosts
0
Views
565
Activity
Feb ’23
Repeated Crash Reports when I add code to a project
I am doing the Swift Landmarks app tutorial on Xcode 13.2.1 on my 2019 Macbook Pro. I am up to the Working with UI Controls section. Every time I add the following lines of code to ProfileSummary.swift: @EnvironmentObject var modelData: ModelData . . . Divider()                   VStack(alignment: .leading)         {                   Text("Recent Hikes")                     .font(.headline)                   HikeView(hike: modelData.hikes[0])         } and I then try to view the preview I repeatedly get a crash report and everything stops working. When I remove those lines of code everything goes back to working fine. The crash report is in this attachment: Translated Crash Report ^ That is the translated report. If you guys would like the full report I will post it. I am stuck and don't know what to do any help will be appreciated!
Replies
1
Boosts
0
Views
1.5k
Activity
Feb ’22