Swift displayed firebase photoUrl cannot replace image by image picker - swift

I use Firebase as the back-end of my app. When user finish authentication they will go to profile create page. It displays the user profile picture from facebook.
I use this code to display
func displayProfilePic(user: FIRUser?){
let photoURL = user?.photoURL
struct last {
static var photoURL: NSURL? = nil
}
last.photoURL = photoURL; // to prevent earlier image overwrites later one.
if let photoURL = photoURL {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), {
let data = NSData.init(contentsOfURL: photoURL)
if let data = data {
let image = UIImage.init(data: data)
dispatch_async(dispatch_get_main_queue(), {
if (photoURL == last.photoURL) {
self.profilePic.image = image
}
})
}
})
} else {
profilePic.image = UIImage.init(named: "DefaultPic")
}
However, I also let user to pick their own profile picture by camera or photo library. When user choose their Image it will display the picked Image for 1 to 2 second, and display back the facebook profile picture. That's mean, the "picked image cannot replace the facebook profile picture"
It is my code for the camera and photo library
func openGallary(){
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.SavedPhotosAlbum){
print("Pick Photo")
self.imagePicker.delegate = self
self.imagePicker.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
self.imagePicker.allowsEditing = true
self.presentViewController(self.imagePicker, animated: true, completion: nil)
}
}
func openCamera(){
if(UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.Camera)){
self.imagePicker.sourceType = UIImagePickerControllerSourceType.Camera
self.imagePicker.allowsEditing = true
self.presentViewController(self.imagePicker, animated: true, completion: nil)
}else{
print("you got no camara")
}
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage!, editingInfo: [NSObject : AnyObject]!) {
self.dismissViewControllerAnimated(true, completion: { () -> Void in
})
profilePic.image = image
}

Firebase Authentication takes a photo URL, so the public location where a profile photo for the user is present. If you want to allow the user to upload a new profile photo, you will have to find a place to store the photo and then put the URL into the Firebase Authentication profile.
One place to keep such a profile picture would be Firebase Storage. See the documentation on how to upload an image from iOS and then generate a download URL that you store in the user profile.

Related

Swift and Firebase - Receiving image from the user then uploading it to firebase

I want the user to upload an image from the photos library along with more input so I can write it to my database.
I made an object with the received data from the user and I uploaded it (using ".child()") to firebase realtime database, but then I had to add the photo to the object so I used the UIImagePicker to upload the photo then I got stuck.
my problem is that i don't know what type of info I should get from the image so I can add it to the object.
I'm not sure if using an object is the right choice but since the data I’m adding is related to a specific item I thought it would be suitable.
// The object
let object: [String : Any] = ["areaname": areaName! as Any ,"spotNo": spotNo, "loactionLat": areaLat, "locationLong": areaLong]
database.child("Areas").child("Area_\(Int.random(in: 0..<100))" ).setValue(object)
#IBAction func chooseImageButton() {
print("Add image button was pressed")
let vc = UIImagePickerController()
vc.sourceType = .photoLibrary
vc.delegate = self
vc.allowsEditing = true
present(vc, animated: true)
}
extension AddAreaViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediawithInfo info: [UIImagePickerController.InfoKey : Any]) {
print("\(info)")
if let image = info[UIImagePickerController.InfoKey(rawValue: "UIImagePickerControllerEditedImage")] as? UIImage {
}
picker.dismiss(animated: true, completion: nil) }
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
picker.dismiss(animated: true, completion: nil)
}
}
Firebase structure
My solution is saving the image using FirebaseStorage. And turn the image url to string write into database. When you need loading image. You can search by that urlstring.
I think #Evan Lu is correct.
You don't need to store the image on firebase database or realtime databse.
You can store the image on FirebaseStorage and save the url on database.

Updating thumbnail of UIDocument in iCloud

I have a UITableViewController which displays a list of NSMetaDataItems which are connected to a StoryDocument which subclasses UIDocument. Each StoryDocument has a UIImage property called image. Each row shows it's thumbnail.
I've overridden fileAttributesToWrite(to: URL, for: UIDocumentSaveOperation) to save the thumbnail as follows:
override func fileAttributesToWrite(to url: URL, for saveOperation: UIDocumentSaveOperation) throws -> [AnyHashable : Any] {
let thumbnailSize = CGSize(width: 1024, height: 1024)
if let thumbnail = image?.at(targetSize: thumbnailSize) {
return [
URLResourceKey.hasHiddenExtensionKey : true,
URLResourceKey.thumbnailDictionaryKey : [
URLThumbnailDictionaryItem.NSThumbnail1024x1024SizeKey : thumbnail
]
]
} else {
return [:]
}
}
I set the thumbnail in func tableView(_:, cellForRowAt:) where url is the url metadataItems.value(forAttribute: NSMetadataItemURLKey)
do {
var thumbnailDictionary: AnyObject?
let nsurl = url as NSURL
try nsurl.getPromisedItemResourceValue(&thumbnailDictionary, forKey: URLResourceKey.thumbnailDictionaryKey)
cell.thumbnailImageView.image = thumbnailDictionary?[URLThumbnailDictionaryItem.NSThumbnail1024x1024SizeKey] as? UIImage
} catch {
cell.thumbnailImageView.image = nil
}
If I change the StoryDocument's image in a detail view and then return to the UITableViewController, the original thumbnail (unchanged) is still shown, even though I'm telling the UITableView to reloadData(). The image only updates about 10 seconds later, when the next .NSMetadataQueryDidFinishGathering or .NSMetadataQueryDidUpdate notification comes in. Is there a good way to get the recently changed thumbnail for the cell rather than the old one?
I'm using Swift 4, although I expect I could adapt suggestions in Swift 3 too.
Many thanks in advance.

Share a video and text on Twitter, Instagram and other services using UIActivityViewController

I am trying to share a video and a text on Instagram, Facebook, Twitter and the native services like Mail, Messages, .... I can not figure out how to get both, Instagram and Twitter to show up in the sharing actionsheet:
If i pass in an array of text and a URL as activity items into the controller, just Instagram shows up, but not Twitter.
let url: NSURL = NSURL() // a url that directs to a video
let items: [AnyObject] = ["Check out this video", url]
let shareable = UIActivityViewController(activityItems: items, applicationActivities: nil)
controller.presentViewController(shareable,
animated: true,
completion: nil)
If i create a class that implements the UIActivityItemSource protocol instead and use that as activityItems, just Twitter shows up, but not Instagram:
class VideoActivityItemSource: NSObject, UIActivityItemSource {
private let videoUrl: NSURL
private let shareText = "View the full video here!"
init(url: NSURL) {
self.videoUrl = url
}
func activityViewControllerPlaceholderItem(activityViewController: UIActivityViewController) -> AnyObject {
return ""
}
func activityViewController(activityViewController: UIActivityViewController, itemForActivityType activityType: String) -> AnyObject? {
switch activityType {
case UIActivityTypePostToFacebook:
return self.videoUrl
case UIActivityTypeMail:
return self.videoUrl
default:
return ["text": self.shareText, "url": self.videoUrl]
}
}
func activityViewController(activityViewController: UIActivityViewController, subjectForActivityType activityType: String?) -> String {
return "Hey check this new cool app!!!"
}
func activityViewController(activityViewController: UIActivityViewController, thumbnailImageForActivityType activityType: String?, suggestedSize size: CGSize) -> UIImage? {
return nil
}
}
and then replace the items by this:
items = [VideoActivityItemSource(url: url)]
I have no idea why in this case Twitter won't show up in the action sheet. Does somebody have an idea how to solve this?
I found the answer. The correct way to do this is to use the implementation of the UIActivityItemSource protocol. The reason for Instagram not showing up in the second solution where i am using the VideoActivityItemSource class is that i am returning an empty String in the activityViewControllerPlaceholderItem function.
Although Apple's documentation says that the type of the object returned in this function does not have to match the type that is used by the itemForActivityType function, it actually needs to be processable by the sharing service. In the case of Instagram it needs to be a video or an image, otherwise Instagram does not show up as a sharing option in the actionsheet.
So the solution is to return a UIImage in the activityViewControllerPlaceholderItem function instead of an empty String, then both Twitter and Instagram will show up as sharing options.
func activityViewControllerPlaceholderItem(activityViewController: UIActivityViewController) -> AnyObject {
// this needs to return some random image to make sure Twitter and Instagram show up in the sharing actionsheet
return UIImage(named: "someImage")!
}
Make sure you have the Instagram app on your phone.
`let activityVC = UIActivityViewController(activityItems: yourobjectArray, applicationActivities: nil)
activityVC.setValue("clipSnapshot", forKey: "subject")
if let activityPopOver = activityVC.popoverPresentationController {
activityPopOver.sourceView = self.view
activityPopOver.permittedArrowDirections = self.subviewView.isHidden ? .up : .left
}
self.present(activityVC, animated: true, completion: nil)
}`
When you see the sharing window and still don't see Instagram then goto the end of the list.
Click on "More" and check if instagram and twitter are included

Get larger facebook image through firebase login

I am using firebase to login a user through facebook. This all works fine and I can get the users FB profile image, although it is to small. Can somebody tell me how to get a larger one, the code I am using:
override func viewDidLoad() {
let loginButton = FBSDKLoginButton()
loginButton.readPermissions = ["public_profile", "email"]
loginButton.delegate = self
self.view.addSubview(loginButton)
}
func loginButton(loginButton: FBSDKLoginButton!, didCompleteWithResult result: FBSDKLoginManagerLoginResult!, error: NSError?) {
let credential = FIRFacebookAuthProvider.credentialWithAccessToken(FBSDKAccessToken.currentAccessToken().tokenString)
FIRAuth.auth()?.signInWithCredential(credential) { (user, error) in
if let user = FIRAuth.auth()?.currentUser {
for profile in user.providerData {
let photoUrl = profile.photoURL?.absoluteString //SMALL IMAGE
}
}
}
}
(This is done in swift)
Once the FB user authenticates, make a FBSDKGraphRequest using FBSDKGraphRequestConnection to get the users FBid, using which you can get the users profile picture by pluggin the id here:
https://graph.facebook.com//picture?type=large&return_ssl_resources=1
instead of type=large you can use ?width=<width>&height=<height> too
too
Once you get the photo Url, just add "?width=400&height=400" to the photo url. Here, height=width=400, you can choose your own height and width. It surely works!
According to the Facebook documentation on Profile Picture, you should be able to specify the size by appending width and height to the url:
let photoUrl = profile.photoURL?.absoluteString + "?width=\(width)&height=\(height)"
or by specifying the type:
let photoUrl = profile.photoURL?.absoluteString + "?type=large"

Can't Compare Images Received From Photo Gallery in Swift

func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
imgProfileIcon.image=info[UIImagePickerControllerOriginalImage] as? UIImage
self.dismissViewControllerAnimated(true, completion: nil)
print(info)
if let _ = imagePicked
{
if imagePicked.isEqualToData(UIImagePNGRepresentation(info[UIImagePickerControllerOriginalImage] as! UIImage)!)
{
print("U Picked The Same Image")
}
else
{
print("Different Image Picked")
}
}
imagePicked=UIImagePNGRepresentation(info[UIImagePickerControllerOriginalImage] as! UIImage)
isImagePicked=true
}
This is the delegate function that I use to select an image from The photoLibrary and my objective is to ensure that I don't hit a web service if an user selects the same image..... So while I was trying to compare images it always prints "Different Image Picked" Even though I pick the same image from the photo library.
I've tried all possibilities....even with .equal() but it shows the same... I think that some additional data is added due to which the comparison fails.
Can someone help me out?