132 lines
4.3 KiB
Swift
132 lines
4.3 KiB
Swift
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
import Foundation
|
|
|
|
class AvatarManager {
|
|
enum AvatarType: String {
|
|
case Normal
|
|
case Call
|
|
}
|
|
|
|
fileprivate let theme: Theme
|
|
fileprivate let cache: NSCache<AnyObject, AnyObject>
|
|
|
|
init(theme: Theme) {
|
|
self.theme = theme
|
|
self.cache = NSCache()
|
|
}
|
|
|
|
/**
|
|
Returns round avatar created from string with a given diameter. Searches for an avatar in cache first,
|
|
if not found creates it.
|
|
|
|
- Parameters:
|
|
- string: String to create avatar from. In case of empty string avatar will be set to "?".
|
|
- diameter: Diameter of circle with avatar.
|
|
|
|
- Returns: Avatar from given string with given size.
|
|
*/
|
|
func avatarFromString(_ string: String, diameter: CGFloat, type: AvatarType = .Normal) -> UIImage {
|
|
var string = string
|
|
|
|
if string.isEmpty {
|
|
string = "?"
|
|
}
|
|
|
|
let key = keyFromString(string, diameter: diameter, type: type)
|
|
|
|
if let avatar = cache.object(forKey: key as AnyObject) as? UIImage {
|
|
return avatar
|
|
}
|
|
|
|
let avatar = createAvatarFromString(string, diameter: diameter, type: type)
|
|
cache.setObject(avatar, forKey: key as AnyObject)
|
|
|
|
return avatar
|
|
}
|
|
}
|
|
|
|
private extension AvatarManager {
|
|
func keyFromString(_ string: String, diameter: CGFloat, type: AvatarType) -> String {
|
|
return "\(string)-\(diameter)-\(type.rawValue)"
|
|
}
|
|
|
|
func createAvatarFromString(_ string: String, diameter: CGFloat, type: AvatarType) -> UIImage {
|
|
let avatarString = avatarStringFromString(string)
|
|
|
|
let label = UILabel()
|
|
label.layer.borderWidth = 1.0
|
|
label.layer.masksToBounds = true
|
|
label.textAlignment = .center
|
|
label.text = avatarString
|
|
|
|
switch type {
|
|
case .Normal:
|
|
label.backgroundColor = theme.colorForType(.NormalBackground)
|
|
label.layer.borderColor = theme.colorForType(.LinkText).cgColor
|
|
label.textColor = theme.colorForType(.LinkText)
|
|
case .Call:
|
|
label.backgroundColor = .clear
|
|
label.layer.borderColor = theme.colorForType(.CallButtonIconColor).cgColor
|
|
label.textColor = theme.colorForType(.CallButtonIconColor)
|
|
}
|
|
|
|
var size: CGSize
|
|
var fontSize = diameter
|
|
|
|
repeat {
|
|
fontSize -= 1
|
|
|
|
let font = UIFont.antidoteFontWithSize(fontSize, weight: .light)
|
|
size = avatarString.stringSizeWithFont(font)
|
|
}
|
|
while (max(size.width, size.height) > diameter)
|
|
|
|
let frame = CGRect(x: 0, y: 0, width: diameter, height: diameter)
|
|
|
|
label.font = UIFont.antidoteFontWithSize(fontSize * 0.6, weight: .light)
|
|
label.layer.cornerRadius = frame.size.width / 2
|
|
label.frame = frame
|
|
|
|
return imageWithLabel(label)
|
|
}
|
|
|
|
func avatarStringFromString(_ string: String) -> String {
|
|
guard !string.isEmpty else {
|
|
return ""
|
|
}
|
|
|
|
// Avatar can have alphanumeric symbols and ? sign.
|
|
let badSymbols = (CharacterSet.alphanumerics.inverted as NSCharacterSet).mutableCopy() as! NSMutableCharacterSet
|
|
badSymbols.removeCharacters(in: "?")
|
|
|
|
let words = string.components(separatedBy: CharacterSet.whitespaces).map {
|
|
$0.components(separatedBy: badSymbols as CharacterSet).joined(separator: "")
|
|
}.filter {
|
|
!$0.isEmpty
|
|
}
|
|
|
|
var result = words.map {
|
|
$0.isEmpty ? "" : $0[$0.startIndex ..< $0.index($0.startIndex, offsetBy: 1)]
|
|
}.joined(separator: "")
|
|
|
|
let numberOfLetters = min(2, result.count)
|
|
|
|
result = result.uppercased()
|
|
return String(result[result.startIndex ..< result.index(result.startIndex, offsetBy: numberOfLetters)])
|
|
}
|
|
|
|
func imageWithLabel(_ label: UILabel) -> UIImage {
|
|
UIGraphicsBeginImageContextWithOptions(label.bounds.size, false, 0.0)
|
|
label.layer.render(in: UIGraphicsGetCurrentContext()!)
|
|
|
|
let image = UIGraphicsGetImageFromCurrentImageContext()
|
|
|
|
UIGraphicsEndImageContext()
|
|
|
|
return image!
|
|
}
|
|
}
|