Minor refactoring

pull/265/head
nielsandriesse 4 years ago
parent 38c6d05236
commit d1a767aafa

@ -8,9 +8,6 @@
/* Begin PBXBuildFile section */
2400888E239F30A600305217 /* SessionRestorationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2400888D239F30A600305217 /* SessionRestorationView.swift */; };
241C6314231F64C000B4198E /* JazzIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 241C630E231F5AAC00B4198E /* JazzIcon.swift */; };
241C6315231F64CE00B4198E /* CGFloat+Rounding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 241C6312231F5F1D00B4198E /* CGFloat+Rounding.swift */; };
241C6316231F64CE00B4198E /* UIColor+Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 241C6310231F5C4400B4198E /* UIColor+Helper.swift */; };
2AE2882E4C2B96BFFF9EE27C /* Pods_SignalShareExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0F94C85CB0B235DA37F68ED0 /* Pods_SignalShareExtension.framework */; };
3403B95D20EA9527001A1F44 /* OWSContactShareButtonsView.m in Sources */ = {isa = PBXBuildFile; fileRef = 3403B95B20EA9526001A1F44 /* OWSContactShareButtonsView.m */; };
34074F61203D0CBE004596AE /* OWSSounds.m in Sources */ = {isa = PBXBuildFile; fileRef = 34074F5F203D0CBD004596AE /* OWSSounds.m */; };
@ -701,9 +698,6 @@
1C93CF3971B64E8B6C1F9AC1 /* Pods-SignalShareExtension.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SignalShareExtension.test.xcconfig"; path = "Pods/Target Support Files/Pods-SignalShareExtension/Pods-SignalShareExtension.test.xcconfig"; sourceTree = "<group>"; };
1CE3CD5C23334683BDD3D78C /* Pods-Signal.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Signal.test.xcconfig"; path = "Pods/Target Support Files/Pods-Signal/Pods-Signal.test.xcconfig"; sourceTree = "<group>"; };
2400888D239F30A600305217 /* SessionRestorationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionRestorationView.swift; sourceTree = "<group>"; };
241C630E231F5AAC00B4198E /* JazzIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JazzIcon.swift; sourceTree = "<group>"; };
241C6310231F5C4400B4198E /* UIColor+Helper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIColor+Helper.swift"; sourceTree = "<group>"; };
241C6312231F5F1D00B4198E /* CGFloat+Rounding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CGFloat+Rounding.swift"; sourceTree = "<group>"; };
264242150E87D10A357DB07B /* Pods_SignalMessaging.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SignalMessaging.framework; sourceTree = BUILT_PRODUCTS_DIR; };
3403B95B20EA9526001A1F44 /* OWSContactShareButtonsView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSContactShareButtonsView.m; sourceTree = "<group>"; };
3403B95C20EA9527001A1F44 /* OWSContactShareButtonsView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSContactShareButtonsView.h; sourceTree = "<group>"; };
@ -2591,23 +2585,10 @@
children = (
C3638C0324C7F09F00AF29BC /* Migrations */,
B8C9689223FA1B05005F64E0 /* Redesign */,
B8544E3623D520F600299F14 /* Jazz Icon */,
);
path = Loki;
sourceTree = "<group>";
};
B8544E3623D520F600299F14 /* Jazz Icon */ = {
isa = PBXGroup;
children = (
241C630E231F5AAC00B4198E /* JazzIcon.swift */,
B846365A22B7418B00AF1514 /* Identicon+ObjC.swift */,
241C6312231F5F1D00B4198E /* CGFloat+Rounding.swift */,
241C6310231F5C4400B4198E /* UIColor+Helper.swift */,
7BF3FEFF2505B8E400609570 /* PlaceholderIcon.swift */,
);
path = "Jazz Icon";
sourceTree = "<group>";
};
B8BB82A3238F356800BA5194 /* Style Guide */ = {
isa = PBXGroup;
children = (
@ -2643,6 +2624,8 @@
isa = PBXGroup;
children = (
B8BB82AC238F734800BA5194 /* ProfilePictureView.swift */,
7BF3FEFF2505B8E400609570 /* PlaceholderIcon.swift */,
B846365A22B7418B00AF1514 /* Identicon+ObjC.swift */,
);
path = Components;
sourceTree = "<group>";
@ -3611,7 +3594,6 @@
34AC0A1C211B39EA00997B47 /* OWSFlatButton.swift in Sources */,
340872D822397F4600CB25B0 /* AttachmentCaptionViewController.swift in Sources */,
34C3C7932040B0DD0000134C /* OWSAudioPlayer.m in Sources */,
241C6316231F64CE00B4198E /* UIColor+Helper.swift in Sources */,
34AC09E5211B39B100997B47 /* ScreenLockViewController.m in Sources */,
34AC09F7211B39B100997B47 /* MediaMessageView.swift in Sources */,
34BBC858220C7ADA00857249 /* ImageEditorContents.swift in Sources */,
@ -3683,7 +3665,6 @@
346129A61FD1F09100532771 /* OWSContactsManager.m in Sources */,
4541B71D209D3B7A0008608F /* ContactShareViewModel.swift in Sources */,
4C618199219DF03A009BD6B5 /* OWSButton.swift in Sources */,
241C6314231F64C000B4198E /* JazzIcon.swift in Sources */,
34AC09F3211B39B100997B47 /* NewNonContactConversationViewController.m in Sources */,
4C3E245C21F29FCE000AE092 /* Toast.swift in Sources */,
34BBC84B220B2CB200857249 /* ImageEditorTextViewController.swift in Sources */,
@ -3700,7 +3681,6 @@
34BBC85A220C7ADA00857249 /* ImageEditorTextItem.swift in Sources */,
34641E182088D7E900E2EDE5 /* OWSScreenLock.swift in Sources */,
346129721FD1D74C00532771 /* SignalKeyingStorage.m in Sources */,
241C6315231F64CE00B4198E /* CGFloat+Rounding.swift in Sources */,
34480B561FD0A7A400BC14EF /* DebugLogger.m in Sources */,
459B775C207BA46C0071D0AB /* OWSQuotedReplyModel.m in Sources */,
7BF3FF002505B8E400609570 /* PlaceholderIcon.swift in Sources */,

@ -1,9 +0,0 @@
extension CGFloat {
/// Round the number to the given amount of decimal places.
func rounded(toPlaces places:Int) -> CGFloat {
let divisor = pow(10.0, CGFloat(places))
return (self * divisor).rounded() / divisor
}
}

@ -1,22 +0,0 @@
@objc(LKIdenticon)
public final class Identicon : NSObject {
@objc public static func generateIcon(string: String, size: CGFloat) -> UIImage {
let icon = JazzIcon(seed: string)
let iconLayer = icon.generateLayer(ofSize: size)
let rect = CGRect(origin: CGPoint.zero, size: iconLayer.frame.size)
let renderer = UIGraphicsImageRenderer(size: rect.size)
let image = renderer.image { iconLayer.render(in: $0.cgContext) }
return image
}
@objc public static func generatePlaceholderIcon(seed: String, text: String, size: CGFloat) -> UIImage {
let icon = PlaceholderIcon(seed: seed)
let iconLayer = icon.generateLayer(ofSize: size, with: text.substring(to: 1))
let rect = CGRect(origin: CGPoint.zero, size: iconLayer.frame.size)
let renderer = UIGraphicsImageRenderer(size: rect.size)
let image = renderer.image { iconLayer.render(in: $0.cgContext) }
return image
}
}

@ -1,150 +0,0 @@
import CryptoSwift
extension String {
func matches(_ regex: String) -> Bool {
return self.range(of: regex, options: .regularExpression, range: nil, locale: nil) != nil
}
}
private class RNG {
private let int32Max = Int(Int32.max) // 2147483647
private var seed: Int
private var initial: Int
init(seed: Int) {
self.seed = seed % int32Max
if (self.seed <= 0) { self.seed += int32Max - 1 }
self.initial = self.seed
}
func next() -> Int {
// Casting to Int64 incase number goes above Int32
let seed = (Int64(self.seed) * 16807) % Int64(int32Max)
self.seed = Int(seed)
return self.seed
}
func nextFloat() -> Float {
return Float(next() - 1) / Float(int32Max - 1)
}
func nextCGFloat() -> CGFloat {
return CGFloat(nextFloat())
}
func reset() {
seed = initial
}
}
public class JazzIcon {
private let generator: RNG
// Colour palette
private var colours: [UIColor] = [
0x01888c, // Teal
0xfc7500, // bright orange
0x034f5d, // dark teal
0xE784BA, // light pink
0x81C8B6, // bright green
0xc7144c, // raspberry
0xf3c100, // goldenrod
0x1598f2, // lightning blue
0x2465e1, // sail blue
0xf19e02, // gold
].map { UIColor(rgb: $0) }
// Defaults
private let shapeCount = 4
private let wobble = 30
init(seed: Int, colours: [UIColor]? = nil) {
self.generator = RNG(seed: seed)
if let colours = colours {
self.colours = colours
}
}
convenience init(seed: String, colours: [UIColor]? = nil) {
// Ensure we have a correct hash
var hash = seed
if !hash.matches("^[0-9A-Fa-f]+$") || hash.count < 12 { hash = seed.sha512() }
guard let number = Int(hash.substring(to: 12), radix: 16) else {
owsFailDebug("[JazzIcon] Failed to generate number from seed string: \(seed)")
self.init(seed: 1234, colours: colours)
return
}
self.init(seed: number, colours: colours)
}
public func generateLayer(ofSize diameter: CGFloat) -> CALayer {
generator.reset()
let newColours = hueShift(colours: colours)
let shuffled = shuffle(newColours)
let base = getSquareLayer(with: diameter, colour: shuffled[0].cgColor)
base.masksToBounds = true
for index in 0..<shapeCount {
let layer = generateShapeLayer(diameter: diameter, colour: shuffled[index + 1].cgColor, index: index, total: shapeCount - 1)
base.addSublayer(layer)
}
return base
}
private func getSquareLayer(with diameter: CGFloat, colour: CGColor? = nil) -> CAShapeLayer {
let frame = CGRect(x: 0, y: 0, width: diameter, height: diameter)
let layer = CAShapeLayer()
layer.frame = frame
layer.path = UIBezierPath(roundedRect: frame, cornerRadius: 0).cgPath
layer.fillColor = colour
return layer
}
private func generateShapeLayer(diameter: CGFloat, colour: CGColor, index: Int, total: Int) -> CALayer {
let center = diameter / 2
let firstRotation = generator.nextCGFloat()
let angle = CGFloat.pi * 2 * firstRotation
let a = diameter / CGFloat(total)
let b: CGFloat = generator.nextCGFloat()
let c = CGFloat(index) * a
let velocity = a * b + c
let translation = CGPoint(x: cos(angle) * velocity, y: sin(angle) * velocity)
// Third random is a shape rotation ontop of all that
let secondRotation = generator.nextCGFloat()
let rotation = (firstRotation * 360.0) + (secondRotation * 180)
let radians = rotation.rounded(toPlaces: 1) * CGFloat.pi / 180.0
let layer = getSquareLayer(with: diameter, colour: colour)
layer.position = CGPoint(x: center + translation.x, y: center + translation.y)
layer.transform = CATransform3DMakeRotation(radians, 0, 0, center)
return layer
}
private func shuffle<T>(_ array: [T]) -> [T] {
var currentIndex = array.count
var mutated = array
while (currentIndex > 0) {
let randomIndex = generator.next() % currentIndex
currentIndex -= 1
mutated.swapAt(currentIndex, randomIndex)
}
return mutated
}
private func hueShift(colours: [UIColor]) -> [UIColor] {
let amount = generator.nextCGFloat() * 30 - CGFloat(wobble / 2);
return colours.map { $0.adjustHue(by: amount) }
}
}

@ -1,48 +0,0 @@
extension UIColor {
public func adjustHue(by degrees: CGFloat) -> UIColor {
var currentHue: CGFloat = 0.0
var currentSaturation: CGFloat = 0.0
var currentBrigthness: CGFloat = 0.0
var currentAlpha: CGFloat = 0.0
if getHue(&currentHue, saturation: &currentSaturation, brightness: &currentBrigthness, alpha: &currentAlpha) {
// Round values so we get closer values to Desktop
let currentHueDegrees = (currentHue * 360.0).rounded()
let normalizedDegrees = fmod(degrees, 360.0).rounded()
// Make sure we're in the range 0 to 360
var newHue = fmod(currentHueDegrees + normalizedDegrees, 360.0)
if (newHue < 0) { newHue = 360 + newHue }
let decimalHue = (currentHueDegrees + normalizedDegrees) / 360.0
return UIColor(hue: decimalHue,
saturation: currentSaturation,
brightness: currentBrigthness,
alpha: 1.0)
} else {
return self
}
}
convenience init(red: Int, green: Int, blue: Int, a: CGFloat = 1.0) {
self.init(
red: CGFloat(red) / 255.0,
green: CGFloat(green) / 255.0,
blue: CGFloat(blue) / 255.0,
alpha: a
)
}
convenience init(rgb: Int, a: CGFloat = 1.0) {
self.init(
red: (rgb >> 16) & 0xFF,
green: (rgb >> 8) & 0xFF,
blue: rgb & 0xFF,
a: a
)
}
}

@ -0,0 +1,12 @@
@objc(LKIdenticon)
public final class Identicon : NSObject {
@objc public static func generatePlaceholderIcon(seed: String, text: String, size: CGFloat) -> UIImage {
let icon = PlaceholderIcon(seed: seed)
let layer = icon.generateLayer(with: size, text: text.substring(to: 1))
let rect = CGRect(origin: CGPoint.zero, size: layer.frame.size)
let renderer = UIGraphicsImageRenderer(size: rect.size)
return renderer.image { layer.render(in: $0.cgContext) }
}
}

@ -1,4 +1,3 @@
import CryptoSwift
public class PlaceholderIcon {
@ -9,13 +8,11 @@ public class PlaceholderIcon {
0x26cdb9,
0xf3c615,
0xfcac5a
].map { UIColor(rgb: $0) }
].map { UIColor(hex: $0) }
init(seed: Int, colours: [UIColor]? = nil) {
self.seed = seed
if let colours = colours {
self.colours = colours
}
if let colours = colours { self.colours = colours }
}
convenience init(seed: String, colours: [UIColor]? = nil) {
@ -24,7 +21,7 @@ public class PlaceholderIcon {
if !hash.matches("^[0-9A-Fa-f]+$") || hash.count < 12 { hash = seed.sha512() }
guard let number = Int(hash.substring(to: 12), radix: 16) else {
owsFailDebug("[PlaceholderIcon] Failed to generate number from seed string: \(seed)")
owsFailDebug("Failed to generate number from seed string: \(seed).")
self.init(seed: 0, colours: colours)
return
}
@ -32,7 +29,7 @@ public class PlaceholderIcon {
self.init(seed: number, colours: colours)
}
public func generateLayer(ofSize diameter: CGFloat, with text: String) -> CALayer {
public func generateLayer(with diameter: CGFloat, text: String) -> CALayer {
let colour = self.colours[seed % self.colours.count].cgColor
let base = getTextLayer(with: diameter, colour: colour, text: text)
base.masksToBounds = true
@ -40,19 +37,20 @@ public class PlaceholderIcon {
}
private func getTextLayer(with diameter: CGFloat, colour: CGColor? = nil, text: String) -> CALayer {
let font = UIFont.boldSystemFont(ofSize: diameter/2)
let height = NSString(string: text).boundingRect(with: CGSize(width: diameter, height: CGFloat(MAXFLOAT)), options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: font], context: nil).height
let frame = CGRect(x: 0, y: (diameter - height)/2, width: diameter, height: height)
let font = UIFont.boldSystemFont(ofSize: diameter / 2)
let height = NSString(string: text).boundingRect(with: CGSize(width: diameter, height: CGFloat.greatestFiniteMagnitude),
options: .usesLineFragmentOrigin, attributes: [ NSAttributedString.Key.font : font ], context: nil).height
let frame = CGRect(x: 0, y: (diameter - height) / 2, width: diameter, height: height)
let layer = CATextLayer()
layer.frame = frame
layer.foregroundColor = UIColor.white.cgColor
layer.contentsScale = UIScreen.main.scale
let fontName = font.fontName;
let fontRef = CGFont(fontName as CFString);
layer.font = fontRef;
layer.fontSize = font.pointSize;
let fontName = font.fontName
let fontRef = CGFont(fontName as CFString)
layer.font = fontRef
layer.fontSize = font.pointSize
layer.alignmentMode = .center
layer.string = text
@ -65,3 +63,10 @@ public class PlaceholderIcon {
return base
}
}
private extension String {
func matches(_ regex: String) -> Bool {
return self.range(of: regex, options: .regularExpression, range: nil, locale: nil) != nil
}
}

@ -46,7 +46,6 @@ public final class ProfilePictureView : UIView {
@objc public func update() {
AssertIsOnMainThread()
func getProfilePicture(of size: CGFloat, for hexEncodedPublicKey: String) -> UIImage? {
OWSLogger.debug("[Ryan] \(hexEncodedPublicKey)")
guard !hexEncodedPublicKey.isEmpty else { return nil }
return OWSProfileManager.shared().profileAvatar(forRecipientId: hexEncodedPublicKey) ?? Identicon.generatePlaceholderIcon(seed: hexEncodedPublicKey, text: OWSProfileManager.shared().profileNameForRecipient(withID: hexEncodedPublicKey) ?? hexEncodedPublicKey, size: size)
}

@ -185,7 +185,7 @@ NS_ASSUME_NONNULL_BEGIN
}
*/
UIImage *image = [LKIdenticon generateIconWithString:self.signalId size:((CGFloat)self.diameter)];
UIImage *image = [LKIdenticon generatePlaceholderIconWithSeed:self.signalId text:@"0" size:((CGFloat)self.diameter)];
[OWSContactAvatarBuilder.contactsManager.avatarCache setImage:image forKey:self.cacheKey diameter:self.diameter];
return image;
}

Loading…
Cancel
Save