From 88ab0d847a03b92646f826f77bc3058854be1a6f Mon Sep 17 00:00:00 2001 From: Vitaly Takmazov Date: Sun, 14 May 2023 00:56:46 +0300 Subject: MessageCell conversion --- Juick/Views/MessageCell.swift | 181 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 181 insertions(+) create mode 100644 Juick/Views/MessageCell.swift (limited to 'Juick/Views/MessageCell.swift') diff --git a/Juick/Views/MessageCell.swift b/Juick/Views/MessageCell.swift new file mode 100644 index 0000000..ebebec2 --- /dev/null +++ b/Juick/Views/MessageCell.swift @@ -0,0 +1,181 @@ +// +// MessageCell.swift +// Juick +// +// Created by Vitaly Takmazov on 13.05.2023. +// Copyright © 2023 com.juick. All rights reserved. +// + +import UIKit + +@objc protocol MessageCellDelegate { + @objc func avatarClicked(_ uname: String) + @objc func linkClicked(_ url: String) +} + +@objc +class MessageCell: UITableViewCell { + @IBOutlet weak var avatar: UIImageView! + @IBOutlet weak var message: UITextView! + @IBOutlet weak var title: UILabel! + @IBOutlet weak var timestamp: UILabel! + @IBOutlet weak var attach: UIImageView! + @IBOutlet weak var attachmentHeight: NSLayoutConstraint! + @IBOutlet weak var attachmentWidth: NSLayoutConstraint! + @IBOutlet weak var summary: UILabel! + @objc var delegate: MessageCellDelegate? + + var _quoteStyle: NSMutableParagraphStyle? + var _boldFont: UIFont? + var _italicFont: UIFont? + var attachment: String? + + @objc + func configure(msg: Message, selectable: Bool) { + updateAvatar(url: msg.user.avatar) + if (msg.user.uid == nil) { + AppDelegate.shared().api.getUserByUri(msg.user.uri) { user in + self.title.text = user?.uname + if let url = user?.avatar ?? API.defaultAvatarUrl() { + self.updateAvatar(url: url) + } + } + } + if (msg.attach != nil) { + self.attachment = msg.attachment.url + let imageHeight = msg.attachment.medium.height as! CGFloat / UIScreen.main.scale + let imageWidth = msg.attachment.medium.width as! CGFloat / UIScreen.main.scale + self.attach.image = UIImage.placeholderImage(with: UIColor(named: "Muted"), size: CGSizeMake(imageWidth, imageHeight)) + + self.attachmentHeight.constant = imageHeight + self.attachmentWidth.constant = imageWidth + AppDelegate.shared().api.fetchImage(with: URL(string: msg.attachment.medium.url)) { data in + if let imageData = data { + UIView.transition(with: self.attach, duration: 0.3, options: .transitionCrossDissolve, animations: { + self.attach.image = UIImage(data: imageData) + }) + } + } + let attachmentTapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(linkClicked(_:))) + attachmentTapGestureRecognizer.isEnabled = true + self.attach.addGestureRecognizer(attachmentTapGestureRecognizer) + self.attach.isUserInteractionEnabled = true + } else { + self.attachmentHeight.constant = 0 + self.attach.image = nil + } + if (msg.user.premium) { + self.title.text = "\(msg.user.uname!) ☆" + } else { + self.title.text = msg.user.uname! + } + + self.timestamp.text = (AppDelegate.shared().sharedDateFormatter.date(from: msg.timestamp)! as NSDate).timeAgo() + let count = msg.repliesCount?.uintValue ?? 0 + if (count > 0) { + if (msg.repliesBy != nil) { + self.summary.text = "\(msg.repliesCount!) replies by \(msg.repliesBy!)" + } else { + self.summary.text = "\(msg.repliesCount!) replies" + } + } else { + self.summary.text = nil + } + if (msg.unread) { + self.summary.text = "\(unreadMarker) \(self.summary.text!)" + self.summary.textColor = UIColor(named: "Funny") + } else { + self.summary.textColor = UIColor(named: "Muted") + } + self.message.attributedText = nil + if (msg.text != nil) { + self.message.isHidden = false + self.message.isSelectable = selectable + self.message.isUserInteractionEnabled = selectable + let txt = NSMutableAttributedString(string: msg.text, attributes: [ + NSAttributedString.Key.font: UIFont.preferredFont(forTextStyle: .body), + NSAttributedString.Key.foregroundColor: UIColor(named: "Text")! + ]) + txt.beginEditing() + for entity in msg.entities { + let start = entity.start?.intValue ?? 0 + let end = entity.end?.intValue ?? 0 + let text = entity.text ?? "" + let currentRange = NSMakeRange(start, end - start) + txt.addAttribute(NSAttributedString.Key(rawValue: "displayText"), value: text, range: currentRange) + if entity.type == "a" { + txt.addAttribute(NSAttributedString.Key.link, value:entity.link!, range:currentRange) + } + if entity.type == "q" { + txt.addAttribute(NSAttributedString.Key.foregroundColor, value:UIColor(named: "Muted")!, range:currentRange) + txt.addAttribute(NSAttributedString.Key.paragraphStyle, value:_quoteStyle!, range:currentRange) + } + if entity.type == "u" { + txt.addAttribute(NSAttributedString.Key.underlineStyle, value:NSUnderlineStyle.single, range:currentRange) + } + + if entity.type == "b" { + txt.addAttribute(NSAttributedString.Key.font, value:_boldFont!, range:currentRange) + } + if entity.type == "i" { + txt.addAttribute(NSAttributedString.Key.font, value:_italicFont!, range:currentRange) + } + } + txt.enumerateAttribute(NSAttributedString.Key(rawValue: "displayText"), in: NSMakeRange(0, txt.length)) { value, range, stop in + if let text = value as? String { + txt.replaceCharacters(in: range, with:text) + } + } + + if msg.tags != nil { + let tagsList = "\(msg.tags.joined(separator: ", "))\n" + txt.insert(NSAttributedString(string: tagsList, attributes: [ + NSAttributedString.Key.font: _italicFont!, + NSAttributedString.Key.foregroundColor: UIColor(named: "Muted")! + ]), at: 0) + } + txt.endEditing() + self.message.attributedText = txt + } else { + self.message.isHidden = true + } + } + + let unreadMarker = "●" + + func updateAvatar(url: String) { + self.avatar.image = nil + AppDelegate.shared().api.fetchImage(with: URL(string: url)) { data in + if let imageData = data { + UIView.transition(with: self.avatar, duration: 0.3, options: .transitionCrossDissolve, animations: { + self.avatar.image = UIImage(data: imageData) + }) + } + } + } + + @objc func avatarClicked(_ sender: UITapGestureRecognizer) { + if let name = self.title.text { + self.delegate?.avatarClicked(name) + } + } + @objc func linkClicked(_ sender: UITapGestureRecognizer){ + self.delegate?.linkClicked(self.attachment!) + } + + override func awakeFromNib() { + let avatarTapRecognizer = UITapGestureRecognizer(target: self, action: #selector(avatarClicked(_:))) + avatarTapRecognizer.isEnabled = true + self.avatar.addGestureRecognizer(avatarTapRecognizer) + self.avatar.isUserInteractionEnabled = true + _quoteStyle = NSParagraphStyle.default.mutableCopy() as? NSMutableParagraphStyle + _quoteStyle?.firstLineHeadIndent = 12.0 + _quoteStyle?.headIndent = 12.0 + _quoteStyle?.paragraphSpacing = 6.0 + let fontDescriptor = UIFontDescriptor.preferredFontDescriptor(withTextStyle: .body) + guard let boldFontDescriptor = fontDescriptor.withSymbolicTraits(.traitBold) else { fatalError("Font error") } + _boldFont = UIFont(descriptor: boldFontDescriptor, size: 0.0) + guard let italicFontDescriptor = fontDescriptor.withSymbolicTraits(.traitItalic) else { fatalError("Font error") } + _italicFont = UIFont(descriptor: italicFontDescriptor, size: 0.0) + } +} -- cgit v1.2.3