Closed macbaszii closed 8 years ago
This is poorly documented, but eventually I've figured out that after assigning image, you have to call finishReceivingMessage(). You're doing that right after appending message, and that's ok, but you have to apparently call it again after assigning image.
@sebastian-zarzycki-es - this isn't quite correct, but has the same affect.
what you need to do is reload the specific item/section with the media if it is not available immediately.
I've found no way to do just that (reloading a specific item).
UICollectionView has APIs for this. :smile:
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UICollectionView_class/
@macbaszii same problem here .. did you find anything????
@BhavinBhadani Did you forget to override method call mediaView
and return the image view ? It is defined on JSQMediaItem Protocol ?
@macbaszii this is what I have done it ...
JSQPhotoMediaItem *photoItem = [[JSQPhotoMediaItem alloc] initWithImage:img.image];
JSQMessage *photoMessage = [JSQMessage messageWithSenderId:self.senderId
displayName:self.senderDisplayName
media:photoItem];
[messages addObject:photoMessage];
[JSQSystemSoundPlayer jsq_playMessageSentSound];
[self finishSendingMessageAnimated:YES];
@BhavinBhadani Have you written this ?
override func mediaView() -> UIView! {
return imageView
}
override func mediaViewDisplaySize() -> CGSize {
return imageView.frame.size
}
@macbaszii no ... let me try it ... thanx
This is my class if you wanted
import Foundation
import JSQMessagesViewController
import Kingfisher
class AsyncPhotoMediaItem: JSQPhotoMediaItem {
var asyncImageView: UIImageView!
override init!(maskAsOutgoing: Bool) {
super.init(maskAsOutgoing: maskAsOutgoing)
}
init(withURL url: NSURL, imageSize: CGSize, isOperator: Bool) {
super.init()
appliesMediaViewMaskAsOutgoing = (isOperator == false)
var size = (imageSize == CGSizeZero) ? super.mediaViewDisplaySize() : ImageType(withSize: imageSize).frameSize()
let resizedImageSize = UbikHelper.resizeFrameWithSize(imageSize, targetSize: size)
size.width = min(size.width, resizedImageSize.width)
size.height = min(size.height, resizedImageSize.height)
asyncImageView = UIImageView()
asyncImageView.frame = CGRectMake(0, 0, size.width, size.height)
asyncImageView.contentMode = .ScaleAspectFit
asyncImageView.clipsToBounds = true
asyncImageView.layer.cornerRadius = 20
asyncImageView.backgroundColor = UIColor.jsq_messageBubbleLightGrayColor()
let activityIndicator = JSQMessagesMediaPlaceholderView.viewWithActivityIndicator()
activityIndicator.frame = asyncImageView.frame
asyncImageView.addSubview(activityIndicator)
KingfisherManager.sharedManager.cache.retrieveImageForKey(url.hashString(), options: nil) { (image, cacheType) -> () in
if let image = image {
self.asyncImageView.image = image
activityIndicator.removeFromSuperview()
} else {
KingfisherManager.sharedManager.downloader.downloadImageWithURL(url, progressBlock: nil) { (image, error, imageURL, originalData) -> () in
if let image = image {
self.asyncImageView.image = image
activityIndicator.removeFromSuperview()
KingfisherManager.sharedManager.cache.storeImage(image, forKey: url.hashString(), toDisk: true, completionHandler: nil)
}
}
}
}
}
override func mediaView() -> UIView! {
return asyncImageView
}
override func mediaViewDisplaySize() -> CGSize {
return asyncImageView.frame.size
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
@macbaszii the problem is in setting avatar pf user ... it also referenced UIImage ...so how to set image with url there ...
- (id<JSQMessageAvatarImageDataSource>)collectionView:(JSQMessagesCollectionView *)collectionView avatarImageDataForItemAtIndexPath:(NSIndexPath *)indexPath{
JSQMessage *message = [arrChatMessage objectAtIndex:indexPath.item];
UIImageView *img = [[UIImageView alloc]init];
[img setImageWithURL:[NSURL URLWithString:[dict_Avatars valueForKey:message.senderId.lowercaseString]] placeholderImage:[UIImage imageNamed:@"icon-user"]];
JSQMessagesAvatarImage *imgAvatar = [JSQMessagesAvatarImageFactory avatarImageWithImage:img.image diameter:kJSQMessagesCollectionViewAvatarSizeDefault];
return imgAvatar;
}
thanx for your time
@BhavinBhadani
Declare @property (strong, nonatomic) JSQMessagesAvatarImage *userAvatarImage;
Download the image with following code block in viewDidLoad
[[SDWebImageManager sharedManager] downloadImageWithURL:[NSURL URLWithString:avatarImageURL] options:0 progress:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
if (!error) {
self.userAvatarImage = [JSQMessagesAvatarImageFactory avatarImageWithImage:image diameter:kJSQMessagesCollectionViewAvatarSizeDefault];
}
}];
and return the avatar in
- (id<JSQMessageAvatarImageDataSource>)collectionView:(JSQMessagesCollectionView *)collectionView avatarImageDataForItemAtIndexPath:(NSIndexPath *)indexPath
{
JSQMessage *message = [self.chatData.messages objectAtIndex:indexPath.item];
if ([message.senderId isEqualToString:userInfo.id]) {
return self.selfAvatarImage;
} else {
return self.userAvatarImage;
}
}
If anyone would like to have the class in Objective-C that @macbaszii develop in Swift:
#import "JSQPhotoMediaItem.h"
@interface ChatAsyncPhoto : JSQPhotoMediaItem
@property (nonatomic, strong) UIImageView *asyncImageView;
- (instancetype)initWithURL:(NSURL *)URL;
@end
#import "ChatAsyncPhoto.h"
#import "UIColor+JSQMessages.h"
#import "JSQMessagesMediaPlaceholderView.h"
#import "UIImageView+WebCache.h"
@implementation ChatAsyncPhoto
- (instancetype)init
{
return [self initWithMaskAsOutgoing:YES];
}
- (instancetype)initWithURL:(NSURL *)URL {
self = [super init];
if (self) {
CGSize size = [self mediaViewDisplaySize];
self.asyncImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, size.width, size.height)];
self.asyncImageView.contentMode = UIViewContentModeScaleToFill;
self.asyncImageView.clipsToBounds = YES;
self.asyncImageView.layer.cornerRadius = 20;
self.asyncImageView.backgroundColor = [UIColor jsq_messageBubbleLightGrayColor];
UIView *activityIndicator = [JSQMessagesMediaPlaceholderView viewWithActivityIndicator];
activityIndicator.frame = self.asyncImageView.frame;
[self.asyncImageView addSubview:activityIndicator];
UIImage *image = [[SDImageCache sharedImageCache] imageFromDiskCacheForKey:URL.absoluteString];
if(image == nil)
{
[self.asyncImageView sd_setImageWithURL:URL completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
if (error == nil) {
[self.asyncImageView setImage:image];
[activityIndicator removeFromSuperview];
} else {
NSLog(@"Image downloading error: %@", [error localizedDescription]);
}
}];
} else {
[self.asyncImageView setImage:image];
[activityIndicator removeFromSuperview];
}
}
return self;
}
#pragma mark - JSQMessageMediaData protocol
- (UIView *)mediaView
{
return self.asyncImageView;
}
#pragma mark - NSCoding
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
NSLog(@"init coder has not been implemented");
return self;
}
@end
Then you can use the class as follows:
ChatAsyncPhoto *photoItem = [[ChatAsyncPhoto alloc] initWithURL:[NSURL URLWithString:messageItem.content]];
JSQMessage *message = [[JSQMessage alloc] initWithSenderId:messageItem.userInfo.id
senderDisplayName:messageItem.userInfo.username
date:[DateUtil getTimeDateStringFromDate:messageItem.createdDate]
media:photoItem];
[self.chatData.messages addObject:message];
I use a combined slim version of @macbaszii and @maksumon's code (thanks for sharing!), but the media bubble is not in line with the regular text bubbles and I have no idea, how to move it on the x axis:
My code:
import Foundation
import JSQMessagesViewController
import Kingfisher
class AsyncPhotoMediaItem: JSQPhotoMediaItem {
var asyncImageView: UIImageView!
override init!(maskAsOutgoing: Bool) {
super.init(maskAsOutgoing: maskAsOutgoing)
}
init(withURL url: NSURL) {
super.init()
asyncImageView = UIImageView()
asyncImageView.frame = CGRectMake(0, 0, 170, 130)
asyncImageView.contentMode = .ScaleAspectFill
asyncImageView.clipsToBounds = true
asyncImageView.layer.cornerRadius = 20
asyncImageView.backgroundColor = UIColor.jsq_messageBubbleLightGrayColor()
let activityIndicator = JSQMessagesMediaPlaceholderView.viewWithActivityIndicator()
activityIndicator.frame = asyncImageView.frame
asyncImageView.addSubview(activityIndicator)
KingfisherManager.sharedManager.cache.retrieveImageForKey(url.absoluteString, options: nil) { (image, cacheType) -> () in
if let image = image {
self.asyncImageView.image = image
activityIndicator.removeFromSuperview()
} else {
KingfisherManager.sharedManager.downloader.downloadImageWithURL(url, progressBlock: nil) { (image, error, imageURL, originalData) -> () in
if let image = image {
self.asyncImageView.image = image
activityIndicator.removeFromSuperview()
KingfisherManager.sharedManager.cache.storeImage(image, forKey: url.absoluteString, toDisk: true, completionHandler: nil)
}
}
}
}
}
override func mediaView() -> UIView! {
return asyncImageView
}
override func mediaViewDisplaySize() -> CGSize {
return asyncImageView.frame.size
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
If you are using that swizzle code from the tail/tailless bubble issue, look no further than the insets:
return [self initWithBubbleImage:[UIImage imageNamed:@"chat_bubble_tailless"] capInsets:UIEdgeInsetsZero];
There are other insets available in lots of places to tweak the layout. For example:
self.collectionView.collectionViewLayout.messageBubbleTextViewTextContainerInsets
self.collectionView.collectionViewLayout.messageBubbleTextViewFrameInsets
You can also adjust the bubble insets directly for any of the text bubbles created by the JSQMessagesBubbleImageFactory returned from:
- (id<JSQMessageBubbleImageDataSource>)collectionView:(JSQMessagesCollectionView *)collectionView messageBubbleImageDataForItemAtIndexPath:(NSIndexPath *)indexPath
And you can adjust the text insets directly in your cellForItem and willDisplayCell methods:
- (UICollectionViewCell *)collectionView:(JSQMessagesCollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
JSQMessagesCollectionViewCell *cell = (JSQMessagesCollectionViewCell *)[super collectionView:collectionView cellForItemAtIndexPath:indexPath];
if (cell.messageBubbleTopLabel.textInsets.left) {
cell.messageBubbleTopLabel.textInsets = UIEdgeInsetsMake(0, 2 + cell.avatarImageView.image.size.width, 2, 0);
}
This is of course all objective C. Translation to swift is left as an exercise for the reader 😄
Hi,
thanks for all the hints, but none of them seems to work. Using UIEdgeInsetsMake
doesn't make any difference. It seems to have something to do with the asyncImageView
. If I comment it out everything is allright:
Interestingly this also has no effect:
override func mediaView() -> UIView! {
self.asyncImageView.center.x += 30
return asyncImageView
}
Edit:
This what it looks like when the corner radius is disabled. No matter what I try the gray box is not moving. Chaning frame or bounds only moves the loading indicator.
Any help is appreciated.
Update: This workaround has fixed it for me:
override func mediaView() -> UIView! {
let view = UIView()
view.addSubview(asyncImageView)
asyncImageView.frame.origin.x = self.appliesMediaViewMaskAsOutgoing ? -6 : 6
return view
}
I am still interested in the non-hacky solution though. :)
import UIKit import JSQMessagesViewController.JSQMessages import AlamofireImage
class JSQPhotoMediaItemCustom: JSQPhotoMediaItem {
var imgView : UIImageView!
var uRL :NSURL?
override init!(maskAsOutgoing: Bool) {
super.init(maskAsOutgoing: maskAsOutgoing)
}
init(withURL url: NSURL, isOperator: Bool) {
super.init()
uRL = url
appliesMediaViewMaskAsOutgoing = (isOperator == true)
let size = super.mediaViewDisplaySize()
imgView = UIImageView()
imgView.frame = CGRectMake(0, 0, size.width, size.height)
imgView.contentMode = .ScaleAspectFill
imgView.clipsToBounds = true
imgView.backgroundColor = UIColor.jsq_messageBubbleLightGrayColor()
let activityIndicator = JSQMessagesMediaPlaceholderView.viewWithActivityIndicator()
activityIndicator.frame = imgView.frame
imgView.addSubview(activityIndicator)
let filter = AspectScaledToFillSizeWithRoundedCornersFilter(
size: size,
radius: 0
)
JSQMessagesMediaViewBubbleImageMasker.applyBubbleImageMaskToMediaView(self.imgView, isOutgoing: self.appliesMediaViewMaskAsOutgoing)
imgView.af_setImageWithURL(url, filter: filter) { (
response ) in
let image = response.result.value
if image != nil{
activityIndicator.removeFromSuperview()
self.imgView.image = image
}
}
}
override func mediaView() -> UIView! {
return imgView
}
override func mediaViewDisplaySize() -> CGSize {
return imgView.frame.size
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
@macbaszii code updated for Swift 3
Swift 3 Update
//
// AsyncPhotoMediaItem.swift
// *******
//
// Created by IndrajitSinh Rayjada on 16/11/16.
// Copyright © 2016 ******. All rights reserved.
//
import Foundation
import JSQMessagesViewController
import Kingfisher
class AsyncPhotoMediaItem: JSQPhotoMediaItem {
var asyncImageView: UIImageView!
override init!(maskAsOutgoing: Bool) {
super.init(maskAsOutgoing: maskAsOutgoing)
}
init(withURL url: URL, imageSize: CGSize, isOperator: Bool) {
super.init()
appliesMediaViewMaskAsOutgoing = (isOperator == false)
ImageType(withSize: imageSize).frameSize()
asyncImageView = UIImageView()
asyncImageView.frame = CGRect(x: 0, y: 0, width: imageSize.width, height: imageSize.height)
asyncImageView.contentMode = .scaleAspectFit
asyncImageView.clipsToBounds = true
asyncImageView.layer.cornerRadius = 20
asyncImageView.backgroundColor = UIColor.jsq_messageBubbleLightGray()
let activityIndicator = JSQMessagesMediaPlaceholderView.withActivityIndicator()
activityIndicator?.frame = asyncImageView.frame
asyncImageView.addSubview(activityIndicator!)
KingfisherManager.shared.cache.retrieveImage(forKey: url.absoluteString, options: nil) { (image, cacheType) -> () in
if let image = image {
self.asyncImageView.image = image
activityIndicator?.removeFromSuperview()
} else {
KingfisherManager.shared.downloader.downloadImage(with: url , progressBlock: nil) { (image, error, imageURL, originalData) -> () in
if let image = image {
self.asyncImageView.image = image
activityIndicator?.removeFromSuperview()
KingfisherManager.shared.cache.store(image, forKey: url.absoluteString)
}
}
}
}
}
override func mediaView() -> UIView! {
return asyncImageView
}
override func mediaViewDisplaySize() -> CGSize {
return asyncImageView.frame.size
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
To avoid to set null in dict here
I tried to set self.image after [self.asyncImageView setImage]
. It seems to work
Tested on @macbaszii code
@indrajitsinh @macbaszii Where's this ImageType
(ImageType(withSize: imageSize).frameSize()
) object from?
as @Isuru-Nanayakkara .. where is ImageType from?
@Isuru-Nanayakkara @nothingimportant55 It's my internal helper to determine that the image is vertical or horizontal. For my case, I have to do it in my backend side.
For you case, you can return any size that you'd like it to be or return super.mediaViewDisplaySize()
for default size you've set below.
Sorry for there is no comment for describing this.
Can anyone tell me what I am doing wrong? I am following what @MHX792 is using. When I send an image the user has to back out of the message and go back in for the image to show. If not it will just keep showing the activity indicator.
Hey guys I am totally new IOS developer. How do I use @macbaszii code ?
@thongtran715 I would say find one of the youtube videos that walk you through using this. It help me understand it better.
Did you find anything on Youtube @rlee1990 . I personally could not find one
@thongtran715 How to Build a Whatsapp Clone App with Firebase 3 and JSQMessageViewController in Swift 2.2: https://www.youtube.com/playlist?list=PLM-WD6b2B_nJoIkl7SfFiBrloNJ3zfU6n
Its easy to follow for and 3.0 and up also
Thanks man. I will take sometime watching these videos
Welcome
Hey Man I have my code here. I am facing the problem exact the same above. How can I fix this? func observeMessage () {
guard let uid = FIRAuth.auth()?.currentUser?.uid else {
return
}
let ref = FIRDatabase.database().reference().child("users-messages").child(uid).child(toId!)
ref.observe(.childAdded, with: { (snapshot) in
let messageId = snapshot.key
let messageRef = FIRDatabase.database().reference().child("Messages").child(messageId)
messageRef.observeSingleEvent(of: .value, with: { (snapshot) in
if let dictionary = snapshot.value as? [String: AnyObject] {
let message = Message()
message.fromId = dictionary["fromId"] as? String
message.text = dictionary["text"] as? String
message.timeStamp = dictionary["timeStamp"] as? Int
message.toId = dictionary["toId"] as? String
message.imageURL = dictionary["ImageURL"] as? String
let id = FIRAuth.auth()?.currentUser?.uid
if let text = message.text {
if message.fromId == id {
let messageJQ = JSQMessage(senderId: "1", displayName: self.user.full_name, text: text)
self.messages.append(messageJQ!)
}
else
{
let messageJQ = JSQMessage(senderId: "2", displayName: self.tutor_to_chat?.full_name, text: text)
self.messages.append(messageJQ!)
}
}
else if message.imageURL != nil {
let imageURL = message.imageURL!
let imageView = UIImageView()
DispatchQueue.main.async {
imageView.loadImageFromURl(url_name: imageURL)
let image = JSQPhotoMediaItem(image: imageView.image)
if message.fromId == id {
let messageJQ = JSQMessage(senderId: "1", displayName: self.user.full_name, media: image)
self.messages.append(messageJQ!)
}
else
{
let messageJQ = JSQMessage(senderId: "2", displayName: self.tutor_to_chat?.full_name, media: image)
self.messages.append(messageJQ!)
}
}
}
self.collectionView.reloadData()
}
}, withCancel: nil)
}, withCancel: nil)
}
@thongtran715 try this: ` let imageView = AsyncPhotoMediaItem(withURL: URL(string: mediaUrl)!)
if senderId == Auth.auth().currentUser!.uid {
imageView.appliesMediaViewMaskAsOutgoing = true
} else {
imageView.appliesMediaViewMaskAsOutgoing = false
}
self.messages.append(JSQMessage(senderId: senderId, senderDisplayName: displayName, date: timeStamp, media: imageView));`
to get that i used this `import Foundation import JSQMessagesViewController import Kingfisher
class AsyncPhotoMediaItem: JSQPhotoMediaItem { var asyncImageView: UIImageView!
override init!(maskAsOutgoing: Bool) {
super.init(maskAsOutgoing: maskAsOutgoing)
}
init(withURL url: URL) {
super.init()
asyncImageView = UIImageView()
asyncImageView.frame = CGRect(x: 0, y: 0, width: 170, height: 130)
asyncImageView.contentMode = .scaleAspectFill
asyncImageView.clipsToBounds = true
asyncImageView.layer.cornerRadius = 20
asyncImageView.backgroundColor = UIColor.jsq_messageBubbleLightGray()
let activityIndicator = JSQMessagesMediaPlaceholderView.withActivityIndicator()
activityIndicator?.frame = asyncImageView.frame
asyncImageView.addSubview(activityIndicator!)
KingfisherManager.shared.cache.retrieveImage(forKey: url.absoluteString, options: nil) { (image, cacheType) -> () in
if let image = image {
self.asyncImageView.image = image
activityIndicator?.removeFromSuperview()
} else {
KingfisherManager.shared.downloader.downloadImage(with: url , progressBlock: nil) { (image, error, imageURL, originalData) -> () in
if let image = image {
self.asyncImageView.image = image
activityIndicator?.removeFromSuperview()
KingfisherManager.shared.cache.store(image, forKey: url.absoluteString)
}
}
}
}
}
override func mediaView() -> UIView! {
return asyncImageView
}
override func mediaViewDisplaySize() -> CGSize {
return asyncImageView.frame.size
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
} `
HI @rlee1990 I tried to install pod Kingfisher, however xcode asks me to change to current version swift 3.0 which shows me the error. I do not if I install it correctly here is what I did pod 'Kingfisher', '~> 1.2'
it should be pod 'Kingfisher', '~> 3.0'
I am so sorry for bothering you, but I am complete new ios developer. I got the message error here when I install kingfisher 3.0 [!] Unable to satisfy the following requirements:
Kingfisher (~> 3.0)
required by Podfile
None of your spec sources contain a spec satisfying the dependency: Kingfisher (~> 3.0)
.
You have either:
pod repo update
.Note: as of C/ocoaPods 1.0, pod repo update
does not happen on pod install
by default.
How do I fix it
Have you tried the guide? https://github.com/onevcat/Kingfisher
Holy Mama and Buddha I got the problem fixed. There is no words to say thank you enough @rlee1990
@thongtran715 glad I could help. We all have been there.
Thank you so so much
Welcome
Hey @rlee1990 . I got an error or crashed like this. I opened the chat log on my phone, I locked it and I unlocked the phone again. The app was crashed, the error said that image != nil. I do not know why I have that problem Here is my code // // ChatLogController.swift // Find-Tutor // // Created by Thong Tran on 7/30/17. // Copyright © 2017 ThongApp. All rights reserved. //
import UIKit import Firebase import JSQMessagesViewController import SDWebImage import AVKit
class ChatLogController: JSQMessagesViewController{
var user = User()
var timer : Timer?
func fetch_current_user_name () ->String {
return user.full_name!
}
// Variables
var tutor_to_chat: User?
var toId : String?
// all messages of users1, users2
var messages = [JSQMessage]()
}
extension ChatLogController { func handle_photo_picture() { let picker = UIImagePickerController() picker.delegate = self picker.allowsEditing = true present(picker, animated: true, completion: nil) }
override func didPressSend(_ button: UIButton!, withMessageText text: String!, senderId: String!, senderDisplayName: String!, date: Date!) {
handleMessage(text: text, toId: toId!, fromId: (FIRAuth.auth()?.currentUser?.uid)!)
finishSendingMessage()
}
override func didPressAccessoryButton(_ sender: UIButton!) {
let alert = UIAlertController(title: nil, message: "Tap Photos to send Photo", preferredStyle: .actionSheet)
let photo = UIAlertAction(title: "Photos", style: .default) { (action) in
self.handle_photo_picture()
}
let cancel = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
//let videos = UIAlertAction(title: "Videos", style: .default) { (action) in
//}
alert.addAction(photo)
// alert.addAction(videos)
alert.addAction(cancel)
present(alert, animated: true, completion: nil)
}
override func collectionView(_ collectionView: JSQMessagesCollectionView!, attributedTextForMessageBubbleTopLabelAt indexPath: IndexPath!) -> NSAttributedString! {
let message = messages[indexPath.row]
let messageUsersname = message.senderDisplayName
return NSAttributedString(string: messageUsersname!)
}
override func collectionView(_ collectionView: JSQMessagesCollectionView!, didTapMessageBubbleAt indexPath: IndexPath!) {
let msg = messages[indexPath.item];
if msg.isMediaMessage {
if let mediaItem = msg.media as? JSQVideoMediaItem {
let player = AVPlayer(url: mediaItem.fileURL);
let playerController = AVPlayerViewController();
playerController.player = player;
self.present(playerController, animated: true, completion: nil);
}
}
else {
self.performZoom()
}
}
func performZoom() {
print(123)
}
override func collectionView(_ collectionView: JSQMessagesCollectionView!, layout collectionViewLayout: JSQMessagesCollectionViewFlowLayout!, heightForMessageBubbleTopLabelAt indexPath: IndexPath!) -> CGFloat {
return 15
}
override func collectionView(_ collectionView: JSQMessagesCollectionView!, avatarImageDataForItemAt indexPath: IndexPath!) -> JSQMessageAvatarImageDataSource! {
let imageView = UIImageView()
var profile_image : String?
if "1" == messages[indexPath.row].senderId {
profile_image = self.user.profileImageUrl
}
else
{
profile_image = self.tutor_to_chat?.profileImageUrl
}
imageView.loadImageFromURl(url_name: profile_image!)
let avatarImage = JSQMessagesAvatarImageFactory.avatarImage(with: imageView.image, diameter: UInt(kJSQMessagesCollectionViewAvatarSizeDefault))
return avatarImage
}
override func collectionView(_ collectionView: JSQMessagesCollectionView!, messageBubbleImageDataForItemAt indexPath: IndexPath!) -> JSQMessageBubbleImageDataSource! {
let bubbleFactory = JSQMessagesBubbleImageFactory()
let message = messages[indexPath.row]
if "1" == message.senderId {
return bubbleFactory?.outgoingMessagesBubbleImage(with: .red)
} else {
return bubbleFactory?.incomingMessagesBubbleImage(with: .green)
}
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return messages.count
}
override func collectionView(_ collectionView: JSQMessagesCollectionView!, messageDataForItemAt indexPath: IndexPath!) -> JSQMessageData! {
return messages[indexPath.row]
}
}
extension ChatLogController { override func viewDidLoad() {
super.viewDidLoad()
self.senderId = "1"
self.senderDisplayName = self.fetch_current_user_name()
observeMessage()
self.navigationController?.navigationBar.tintColor = UIColor.red
self.set_up_user_nav_bar(name: (tutor_to_chat?.full_name)!, profileImageURL: (tutor_to_chat?.profileImageUrl)!)
finishReceivingMessage()
}
} extension ChatLogController { func handleMessage (text: String, toId: String , fromId: String ) { let ref = FIRDatabase.database().reference().child("Messages") let childUnique = ref.childByAutoId() let timeStamp: Int = Int(NSDate().timeIntervalSince1970) let values = ["text" : text, "toId": toId, "fromId": fromId, "timeStamp": timeStamp ] as [String : Any] childUnique.updateChildValues(values) { (error, ref) in if error != nil { print(error as Any) return } let userMessageRef = FIRDatabase.database().reference().child("users-messages").child(fromId).child(toId) let messageId = childUnique.key userMessageRef.updateChildValues([messageId : 1])
let receiverMessageRef = FIRDatabase.database().reference().child("users-messages").child(toId).child(fromId)
receiverMessageRef.updateChildValues([messageId : 1])
}
}
}
extension ChatLogController: UIImagePickerControllerDelegate, UINavigationControllerDelegate { func imagePickerControllerDidCancel( picker: UIImagePickerController) { self.dismiss(animated: true, completion: nil) } func imagePickerController( picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) { var image_temp : UIImage? if let orignialImage = info["UIImagePickerControllerOriginalImage"] as? UIImage { image_temp = orignialImage } else if let editedImage = info["UIImagePickerControllerEditedImage"] as? UIImage { image_temp = editedImage } if let image = image_temp { //self.profileImage.image = image self.uploadImageToDB(image: image) } self.dismiss(animated: true) { self.finishSendingMessage() } self.collectionView.reloadData() }
func uploadImageToDB ( image : UIImage) {
let messageName = NSUUID().uuidString
let storageRef = FIRStorage.storage().reference().child("Messages_Images").child("\(messageName).png")
if let uploadData = UIImageJPEGRepresentation(image, 0.1) {
storageRef.put(uploadData, metadata: nil, completion: { (metadata, error) in
if error != nil {
print(error?.localizedDescription as Any)
}
self.uploadImageMessage(imageURL: (metadata?.downloadURL()?.absoluteString)!, toId: self.toId!, fromId: (FIRAuth.auth()?.currentUser?.uid)!)
})
}
}
private func uploadImageMessage (imageURL : String ,toId: String , fromId : String) {
let ref = FIRDatabase.database().reference().child("Messages")
let childUnique = ref.childByAutoId()
let timeStamp: Int = Int(NSDate().timeIntervalSince1970)
let values = ["ImageURL" : imageURL, "toId": toId, "fromId": fromId, "timeStamp": timeStamp ] as [String : Any]
childUnique.updateChildValues(values) { (error, ref) in
if error != nil {
print(error as Any)
return
}
let userMessageRef = FIRDatabase.database().reference().child("users-messages").child(fromId).child(toId)
let messageId = childUnique.key
userMessageRef.updateChildValues([messageId : 1])
let receiverMessageRef = FIRDatabase.database().reference().child("users-messages").child(toId).child(fromId)
receiverMessageRef.updateChildValues([messageId : 1])
}
}
}
// Fetch Users Messsages -OR- Observe Messages extension ChatLogController {
func observeMessage () {
guard let uid = FIRAuth.auth()?.currentUser?.uid else {
return
}
let ref = FIRDatabase.database().reference().child("users-messages").child(uid).child(toId!)
ref.observe(.childAdded, with: { (snapshot) in
let messageId = snapshot.key
let messageRef = FIRDatabase.database().reference().child("Messages").child(messageId)
messageRef.observeSingleEvent(of: .value, with: { (snapshot) in
if let dictionary = snapshot.value as? [String: AnyObject] {
let message = Message()
message.fromId = dictionary["fromId"] as? String
message.text = dictionary["text"] as? String
message.timeStamp = dictionary["timeStamp"] as? Int
message.toId = dictionary["toId"] as? String
message.imageURL = dictionary["ImageURL"] as? String
let id = FIRAuth.auth()?.currentUser?.uid
if let text = message.text {
if message.fromId == id {
let messageJQ = JSQMessage(senderId: "1", displayName: self.user.full_name, text: text)
self.messages.append(messageJQ!)
}
else
{
let messageJQ = JSQMessage(senderId: "2", displayName: self.tutor_to_chat?.full_name, text: text)
self.messages.append(messageJQ!)
}
}
else if message.imageURL != nil {
let imageURL = message.imageURL!
let imageView = AsyncPhotoMediaItem(withURL: URL(string: imageURL)!)
let date = Date()
if message.fromId == id {
imageView.appliesMediaViewMaskAsOutgoing = true
let messageJQ = JSQMessage(senderId: "1", senderDisplayName: self.user.full_name, date: date , media: imageView)
self.messages.append(messageJQ!)
}
else
{
imageView.appliesMediaViewMaskAsOutgoing = false
let messageJQ = JSQMessage(senderId: "2", senderDisplayName: self.tutor_to_chat?.full_name, date: date , media: imageView)
self.messages.append(messageJQ!)
}
}
DispatchQueue.main.async {
self.collectionView.reloadData()
let indexPath = NSIndexPath(item: self.messages.count - 1, section: 0)
self.collectionView.scrollToItem(at: indexPath as IndexPath, at: .bottom, animated: true)
}
}
}, withCancel: nil)
}, withCancel: nil)
}
}
extension ChatLogController { func set_up_user_nav_bar ( name : String , profileImageURL : String ) { let titleView = UIView() titleView.frame = CGRect(x: 0, y: 0, width: 100, height: 40) let containerView = UIView() containerView.translatesAutoresizingMaskIntoConstraints = false titleView.addSubview(containerView)
let profileImageView = UIImageView()
profileImageView.translatesAutoresizingMaskIntoConstraints = false
profileImageView.contentMode = .scaleAspectFill
profileImageView.layer.cornerRadius = 20
profileImageView.clipsToBounds = true
profileImageView.loadImageFromURl(url_name: profileImageURL)
containerView.addSubview(profileImageView)
profileImageView.leftAnchor.constraint(equalTo: containerView.leftAnchor).isActive = true
profileImageView.centerYAnchor.constraint(equalTo: containerView.centerYAnchor).isActive = true
profileImageView.widthAnchor.constraint(equalToConstant: 40).isActive = true
profileImageView.heightAnchor.constraint(equalToConstant: 40).isActive = true
let name_label = UILabel()
containerView.addSubview(name_label)
name_label.text = name
name_label.translatesAutoresizingMaskIntoConstraints = false
name_label.leftAnchor.constraint(equalTo: profileImageView.rightAnchor, constant: 8).isActive = true
name_label.centerYAnchor.constraint(equalTo: profileImageView.centerYAnchor).isActive = true
name_label.rightAnchor.constraint(equalTo: containerView.rightAnchor).isActive = true
name_label.heightAnchor.constraint(equalTo: profileImageView.heightAnchor).isActive = true
containerView.centerXAnchor.constraint(equalTo: titleView.centerXAnchor).isActive = true
containerView.centerYAnchor.constraint(equalTo: titleView.centerYAnchor).isActive = true
self.navigationItem.titleView = titleView
}
}
Dears
my issue
all images align right
Hey guys, I'm developing a IM app with JSQMessagesViewController. I want to know how to notify the view controller to reload the correct cell when its media item's content has downloaded. I am confusing on it for several days.
I try to load image from URL with this code, but image view still not showing the image. I'm not sure, I'm on the right way to show an image from url
this is my code which is adding message to the messages array I used Kingfisher to load image