Update avatar colors; add shaded conversation color constants, modify color picker to be color-name-based, not color-based, use shaded conversation colors, remove JSQ.
This commit is contained in:
parent
c89033591d
commit
ae84528dc3
|
@ -42,16 +42,6 @@
|
|||
340FC8CD20518C77007AEB0F /* OWSBackupJob.m in Sources */ = {isa = PBXBuildFile; fileRef = 340FC8CC20518C76007AEB0F /* OWSBackupJob.m */; };
|
||||
340FC8D0205BF2FA007AEB0F /* OWSBackupIO.m in Sources */ = {isa = PBXBuildFile; fileRef = 340FC8CE205BF2FA007AEB0F /* OWSBackupIO.m */; };
|
||||
341F2C0F1F2B8AE700D07D6B /* DebugUIMisc.m in Sources */ = {isa = PBXBuildFile; fileRef = 341F2C0E1F2B8AE700D07D6B /* DebugUIMisc.m */; };
|
||||
3421980F21061A0700C57195 /* UIColor+JSQMessages.m in Sources */ = {isa = PBXBuildFile; fileRef = 3421980521061A0600C57195 /* UIColor+JSQMessages.m */; };
|
||||
3421981021061A0700C57195 /* JSQMessagesAvatarImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 3421980621061A0600C57195 /* JSQMessagesAvatarImage.m */; };
|
||||
3421981121061A0700C57195 /* JSQMessagesAvatarImageFactory.h in Headers */ = {isa = PBXBuildFile; fileRef = 3421980721061A0600C57195 /* JSQMessagesAvatarImageFactory.h */; };
|
||||
3421981221061A0700C57195 /* JSQMVC-LICENSE in Resources */ = {isa = PBXBuildFile; fileRef = 3421980821061A0600C57195 /* JSQMVC-LICENSE */; };
|
||||
3421981321061A0700C57195 /* JSQMessagesAvatarImageFactory.m in Sources */ = {isa = PBXBuildFile; fileRef = 3421980921061A0700C57195 /* JSQMessagesAvatarImageFactory.m */; };
|
||||
3421981421061A0700C57195 /* JSQMessagesAvatarImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 3421980A21061A0700C57195 /* JSQMessagesAvatarImage.h */; };
|
||||
3421981521061A0700C57195 /* UIColor+JSQMessages.h in Headers */ = {isa = PBXBuildFile; fileRef = 3421980B21061A0700C57195 /* UIColor+JSQMessages.h */; };
|
||||
3421981621061A0700C57195 /* JSQMVC-README.md in Resources */ = {isa = PBXBuildFile; fileRef = 3421980C21061A0700C57195 /* JSQMVC-README.md */; };
|
||||
3421981721061A0700C57195 /* JSQMVC-SIGNAL.md in Resources */ = {isa = PBXBuildFile; fileRef = 3421980D21061A0700C57195 /* JSQMVC-SIGNAL.md */; };
|
||||
3421981821061A0700C57195 /* JSQMessageAvatarImageDataSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 3421980E21061A0700C57195 /* JSQMessageAvatarImageDataSource.h */; };
|
||||
3421981C21061D2E00C57195 /* ByteParserTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3421981B21061D2E00C57195 /* ByteParserTest.swift */; };
|
||||
34277A5E20751BDC006049F2 /* OWSQuotedMessageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 34277A5C20751BDC006049F2 /* OWSQuotedMessageView.m */; };
|
||||
3427C64320F500E000EEC730 /* OWSMessageTimerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 3427C64220F500DF00EEC730 /* OWSMessageTimerView.m */; };
|
||||
|
@ -662,16 +652,6 @@
|
|||
341458471FBE11C4005ABCF9 /* fa */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fa; path = translations/fa.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
341F2C0D1F2B8AE700D07D6B /* DebugUIMisc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DebugUIMisc.h; sourceTree = "<group>"; };
|
||||
341F2C0E1F2B8AE700D07D6B /* DebugUIMisc.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DebugUIMisc.m; sourceTree = "<group>"; };
|
||||
3421980521061A0600C57195 /* UIColor+JSQMessages.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIColor+JSQMessages.m"; sourceTree = "<group>"; };
|
||||
3421980621061A0600C57195 /* JSQMessagesAvatarImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQMessagesAvatarImage.m; sourceTree = "<group>"; };
|
||||
3421980721061A0600C57195 /* JSQMessagesAvatarImageFactory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSQMessagesAvatarImageFactory.h; sourceTree = "<group>"; };
|
||||
3421980821061A0600C57195 /* JSQMVC-LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "JSQMVC-LICENSE"; sourceTree = "<group>"; };
|
||||
3421980921061A0700C57195 /* JSQMessagesAvatarImageFactory.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQMessagesAvatarImageFactory.m; sourceTree = "<group>"; };
|
||||
3421980A21061A0700C57195 /* JSQMessagesAvatarImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSQMessagesAvatarImage.h; sourceTree = "<group>"; };
|
||||
3421980B21061A0700C57195 /* UIColor+JSQMessages.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIColor+JSQMessages.h"; sourceTree = "<group>"; };
|
||||
3421980C21061A0700C57195 /* JSQMVC-README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = "JSQMVC-README.md"; sourceTree = "<group>"; };
|
||||
3421980D21061A0700C57195 /* JSQMVC-SIGNAL.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = "JSQMVC-SIGNAL.md"; sourceTree = "<group>"; };
|
||||
3421980E21061A0700C57195 /* JSQMessageAvatarImageDataSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSQMessageAvatarImageDataSource.h; sourceTree = "<group>"; };
|
||||
3421981B21061D2E00C57195 /* ByteParserTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ByteParserTest.swift; sourceTree = "<group>"; };
|
||||
34277A5C20751BDC006049F2 /* OWSQuotedMessageView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSQuotedMessageView.m; sourceTree = "<group>"; };
|
||||
34277A5D20751BDC006049F2 /* OWSQuotedMessageView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSQuotedMessageView.h; sourceTree = "<group>"; };
|
||||
|
@ -1470,28 +1450,10 @@
|
|||
34219803210619D300C57195 /* Libraries */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3421980421061A0600C57195 /* JSQMessagesViewController */,
|
||||
);
|
||||
path = Libraries;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
3421980421061A0600C57195 /* JSQMessagesViewController */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3421980521061A0600C57195 /* UIColor+JSQMessages.m */,
|
||||
3421980621061A0600C57195 /* JSQMessagesAvatarImage.m */,
|
||||
3421980721061A0600C57195 /* JSQMessagesAvatarImageFactory.h */,
|
||||
3421980821061A0600C57195 /* JSQMVC-LICENSE */,
|
||||
3421980921061A0700C57195 /* JSQMessagesAvatarImageFactory.m */,
|
||||
3421980A21061A0700C57195 /* JSQMessagesAvatarImage.h */,
|
||||
3421980B21061A0700C57195 /* UIColor+JSQMessages.h */,
|
||||
3421980C21061A0700C57195 /* JSQMVC-README.md */,
|
||||
3421980D21061A0700C57195 /* JSQMVC-SIGNAL.md */,
|
||||
3421980E21061A0700C57195 /* JSQMessageAvatarImageDataSource.h */,
|
||||
);
|
||||
path = JSQMessagesViewController;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
34330A581E7875FB00DF2FB9 /* Fonts */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -2527,7 +2489,6 @@
|
|||
346129711FD1D74C00532771 /* SignalKeyingStorage.h in Headers */,
|
||||
34AC0A20211B39EA00997B47 /* ThreadViewHelper.h in Headers */,
|
||||
34AC09DE211B39B100997B47 /* OWSNavigationController.h in Headers */,
|
||||
3421981121061A0700C57195 /* JSQMessagesAvatarImageFactory.h in Headers */,
|
||||
34C82E5120F8E1F300E9688D /* Theme.h in Headers */,
|
||||
34612A011FD5F31400532771 /* OWS104CreateRecipientIdentities.h in Headers */,
|
||||
450998691FD8C10200D89EB3 /* AttachmentSharing.h in Headers */,
|
||||
|
@ -2535,7 +2496,6 @@
|
|||
34AC09EC211B39B100997B47 /* OWSTableViewController.h in Headers */,
|
||||
451F8A3C1FD71392005CB9DA /* UIUtil.h in Headers */,
|
||||
346129D61FD20ADC00532771 /* UIViewController+OWS.h in Headers */,
|
||||
3421981421061A0700C57195 /* JSQMessagesAvatarImage.h in Headers */,
|
||||
34612A061FD7238600532771 /* OWSContactsSyncing.h in Headers */,
|
||||
34480B571FD0A7A400BC14EF /* OWSScrubbingLogFormatter.h in Headers */,
|
||||
346129FC1FD5F31400532771 /* OWS101ExistingUsersBlockOnIdentityChange.h in Headers */,
|
||||
|
@ -2543,11 +2503,9 @@
|
|||
451F8A491FD715CF005CB9DA /* OWSAvatarBuilder.h in Headers */,
|
||||
346129951FD1E30000532771 /* OWSDatabaseMigration.h in Headers */,
|
||||
34B6D27420F664C900765BE2 /* OWSUnreadIndicator.h in Headers */,
|
||||
3421981821061A0700C57195 /* JSQMessageAvatarImageDataSource.h in Headers */,
|
||||
34AC09E4211B39B100997B47 /* ScreenLockViewController.h in Headers */,
|
||||
34AC09F1211B39B100997B47 /* LockInteractionController.h in Headers */,
|
||||
346129B41FD1F7E800532771 /* OWSProfileManager.h in Headers */,
|
||||
3421981521061A0700C57195 /* UIColor+JSQMessages.h in Headers */,
|
||||
342950892124CB0A0000B063 /* OWSSearchBar.h in Headers */,
|
||||
346129FA1FD5F31400532771 /* OWS100RemoveTSRecipientsMigration.h in Headers */,
|
||||
346129E21FD5C0BE00532771 /* VersionMigrations.h in Headers */,
|
||||
|
@ -2837,9 +2795,6 @@
|
|||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
3421981621061A0700C57195 /* JSQMVC-README.md in Resources */,
|
||||
3421981721061A0700C57195 /* JSQMVC-SIGNAL.md in Resources */,
|
||||
3421981221061A0700C57195 /* JSQMVC-LICENSE in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -3181,7 +3136,6 @@
|
|||
34AC09EE211B39B100997B47 /* EditContactShareNameViewController.swift in Sources */,
|
||||
346129F71FD5F31400532771 /* OWS105AttachmentFilePaths.m in Sources */,
|
||||
45194F931FD7215C00333B2C /* OWSContactOffersInteraction.m in Sources */,
|
||||
3421980F21061A0700C57195 /* UIColor+JSQMessages.m in Sources */,
|
||||
4523D016206EDC2B00A2AB51 /* LRUCache.swift in Sources */,
|
||||
450998681FD8C0FF00D89EB3 /* AttachmentSharing.m in Sources */,
|
||||
347850711FDAEB17007B8332 /* OWSUserProfile.m in Sources */,
|
||||
|
@ -3190,7 +3144,6 @@
|
|||
34074F61203D0CBE004596AE /* OWSSounds.m in Sources */,
|
||||
346129B51FD1F7E800532771 /* OWSProfileManager.m in Sources */,
|
||||
342950832124C9750000B063 /* OWSTextView.m in Sources */,
|
||||
3421981321061A0700C57195 /* JSQMessagesAvatarImageFactory.m in Sources */,
|
||||
452EC6E1205FF5DC000E787C /* Bench.swift in Sources */,
|
||||
342950882124CB0A0000B063 /* OWSSearchBar.m in Sources */,
|
||||
342950822124C9750000B063 /* OWSTextField.m in Sources */,
|
||||
|
@ -3259,7 +3212,6 @@
|
|||
34AC0A18211B39EA00997B47 /* TappableStackView.swift in Sources */,
|
||||
34B6D27520F664C900765BE2 /* OWSUnreadIndicator.m in Sources */,
|
||||
346129A61FD1F09100532771 /* OWSContactsManager.m in Sources */,
|
||||
3421981021061A0700C57195 /* JSQMessagesAvatarImage.m in Sources */,
|
||||
4541B71D209D3B7A0008608F /* ContactShareViewModel.swift in Sources */,
|
||||
4598198F204E2F28009414F2 /* OWS108CallLoggingPreference.m in Sources */,
|
||||
34AC09F3211B39B100997B47 /* NewNonContactConversationViewController.m in Sources */,
|
||||
|
|
|
@ -46,7 +46,7 @@ class ColorPickerViewController: UIViewController, UIPickerViewDelegate, UIPicke
|
|||
|
||||
private let pickerView: UIPickerView
|
||||
private let thread: TSThread
|
||||
private let colors: [UIColor]
|
||||
private let colorNames: [String]
|
||||
|
||||
@objc public weak var delegate: ColorPickerDelegate?
|
||||
|
||||
|
@ -54,7 +54,7 @@ class ColorPickerViewController: UIViewController, UIPickerViewDelegate, UIPicke
|
|||
required init(thread: TSThread) {
|
||||
self.thread = thread
|
||||
self.pickerView = UIPickerView()
|
||||
self.colors = UIColor.ows_conversationColors
|
||||
self.colorNames = UIColor.ows_conversationColorNames
|
||||
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
|
||||
|
@ -83,8 +83,7 @@ class ColorPickerViewController: UIViewController, UIPickerViewDelegate, UIPicke
|
|||
super.viewDidLoad()
|
||||
|
||||
if let colorName = thread.conversationColorName,
|
||||
let currentColor = UIColor.ows_conversationColor(colorName: colorName),
|
||||
let index = colors.index(of: currentColor) {
|
||||
let index = colorNames.index(of: colorName) {
|
||||
pickerView.selectRow(index, inComponent: 0, animated: false)
|
||||
}
|
||||
}
|
||||
|
@ -96,7 +95,7 @@ class ColorPickerViewController: UIViewController, UIPickerViewDelegate, UIPicke
|
|||
}
|
||||
|
||||
public func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
|
||||
return self.colors.count
|
||||
return self.colorNames.count
|
||||
}
|
||||
|
||||
// MARK: UIPickerViewDelegate
|
||||
|
@ -107,34 +106,32 @@ class ColorPickerViewController: UIViewController, UIPickerViewDelegate, UIPicke
|
|||
}
|
||||
|
||||
public func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
|
||||
guard let color = colors[safe: row] else {
|
||||
guard let colorName = colorNames[safe: row] else {
|
||||
owsFailDebug("color was unexpectedly nil")
|
||||
return ColorView(color: .white)
|
||||
}
|
||||
|
||||
guard let color = UIColor.ows_conversationColor(colorName: colorName,
|
||||
isShaded: Theme.isDarkThemeEnabled) else {
|
||||
owsFailDebug("unknown color name")
|
||||
return ColorView(color: .white)
|
||||
}
|
||||
return ColorView(color: color)
|
||||
}
|
||||
|
||||
// MARK: Actions
|
||||
|
||||
var currentColor: UIColor {
|
||||
var currentColorName: String {
|
||||
let index = pickerView.selectedRow(inComponent: 0)
|
||||
guard let color = self.colors[safe: index] else {
|
||||
guard let colorName = colorNames[safe: index] else {
|
||||
owsFailDebug("index was unexpectedly nil")
|
||||
return UIColor.white
|
||||
return UIColor.ows_defaultConversationColorName()
|
||||
}
|
||||
|
||||
return color
|
||||
return colorName
|
||||
}
|
||||
|
||||
@objc
|
||||
public func didTapSave() {
|
||||
guard let colorName = UIColor.ows_conversationColorName(color: self.currentColor) else {
|
||||
owsFailDebug("colorName was unexpectedly nil")
|
||||
self.delegate?.colorPickerDidCancel(self)
|
||||
return
|
||||
}
|
||||
|
||||
let colorName = self.currentColorName
|
||||
self.delegate?.colorPicker(self, didPickColorName: colorName)
|
||||
}
|
||||
|
||||
|
|
|
@ -269,11 +269,10 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
}
|
||||
|
||||
TSIncomingMessage *incomingMessage = (TSIncomingMessage *)self.viewItem.interaction;
|
||||
OWSAvatarBuilder *avatarBuilder = [[OWSContactAvatarBuilder alloc] initWithSignalId:incomingMessage.authorId
|
||||
color:self.conversationStyle.primaryColor
|
||||
diameter:self.avatarSize
|
||||
contactsManager:contactsManager];
|
||||
self.avatarView.image = [avatarBuilder build];
|
||||
TSThread *authorThread = [TSContactThread getOrCreateThreadWithContactId:incomingMessage.authorId];
|
||||
UIImage *_Nullable authorAvatarImage =
|
||||
[OWSAvatarBuilder buildImageForThread:authorThread diameter:self.avatarSize contactsManager:contactsManager];
|
||||
self.avatarView.image = authorAvatarImage;
|
||||
[self.contentView addSubview:self.avatarView];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
|
|
|
@ -289,7 +289,9 @@ const CGFloat kIconViewLength = 24;
|
|||
[mainSection addItem:[OWSTableItem
|
||||
itemWithCustomCellBlock:^{
|
||||
NSString *colorName = self.thread.conversationColorName;
|
||||
UIColor *currentColor = [UIColor ows_conversationColorForColorName:colorName];
|
||||
UIColor *currentColor =
|
||||
[UIColor ows_conversationColorForColorName:colorName
|
||||
isShaded:Theme.isDarkThemeEnabled];
|
||||
NSString *title = NSLocalizedString(@"CONVERSATION_SETTINGS_CONVERSATION_COLOR",
|
||||
@"Label for table cell which leads to picking a new conversation color");
|
||||
return [weakSelf disclosureCellWithName:title iconColor:currentColor];
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
|
||||
MIT License
|
||||
Copyright (c) 2013-present Jesse Squires
|
||||
|
||||
http://www.jessesquires.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
associated documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
|
||||
following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
||||
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
||||
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -1,104 +0,0 @@
|
|||
![JSQMessagesViewController banner](https://raw.githubusercontent.com/jessesquires/JSQMessagesViewController/develop/Assets/jsq_messages_banner.png)
|
||||
|
||||
[![Build Status](https://secure.travis-ci.org/jessesquires/JSQMessagesViewController.svg)](https://travis-ci.org/jessesquires/JSQMessagesViewController) [![Version Status](https://img.shields.io/cocoapods/v/JSQMessagesViewController.svg)][podLink] [![license MIT](https://img.shields.io/cocoapods/l/JSQMessagesViewController.svg)][mitLink] [![codecov](https://codecov.io/gh/jessesquires/JSQMessagesViewController/branch/develop/graph/badge.svg)](https://codecov.io/gh/jessesquires/JSQMessagesViewController) [![Platform](https://img.shields.io/cocoapods/p/JSQMessagesViewController.svg)][docsLink]
|
||||
|
||||
![Screenshot0][img0] ![Screenshot1][img1]
|
||||
|
||||
![Screenshot2][img2] ![Screenshot3][img3]
|
||||
|
||||
> More screenshots available at [CocoaControls](https://www.cocoacontrols.com/controls/jsqmessagesviewcontroller)
|
||||
|
||||
## Features
|
||||
|
||||
See the [website](http://www.jessesquires.com/JSQMessagesViewController/) for the list of features.
|
||||
|
||||
## Design Goals
|
||||
|
||||
- Closely mimic the [iOS Messages](http://www.apple.com/ios/messages/) style and behavior
|
||||
- [SOLID](https://en.wikipedia.org/wiki/SOLID_(object-oriented_design)) design
|
||||
- Easy customization and extension for clients
|
||||
|
||||
## Dependencies
|
||||
|
||||
* [JSQSystemSoundPlayer][playerLink]
|
||||
|
||||
## Requirements
|
||||
|
||||
* iOS 7.0+
|
||||
* ARC
|
||||
|
||||
## Installation
|
||||
|
||||
### [CocoaPods](https://cocoapods.org/) (recommended)
|
||||
|
||||
````ruby
|
||||
# For latest release in cocoapods
|
||||
pod 'JSQMessagesViewController'
|
||||
|
||||
# Latest on develop
|
||||
pod 'JSQMessagesViewController', :git => 'https://github.com/jessesquires/JSQMessagesViewController.git', :branch => 'develop'
|
||||
|
||||
# For version 5.3.2
|
||||
pod 'JSQMessagesViewController', :git => 'https://github.com/jessesquires/JSQMessagesViewController', :branch => 'version_5.3.2_patch'
|
||||
````
|
||||
|
||||
## Getting Started
|
||||
|
||||
See the [Getting Started](https://github.com/jessesquires/JSQMessagesViewController/blob/develop/Documentation/getting_started.md) guide!
|
||||
|
||||
## Questions & Help
|
||||
|
||||
* Review the [FAQ](https://github.com/jessesquires/JSQMessagesViewController/blob/develop/Documentation/faq.md).
|
||||
* Search issues for previous and current [questions](https://github.com/jessesquires/JSQMessagesViewController/issues?utf8=✓&q=label%3A%22questions+%26+help%22+). *Do not open duplicates.*
|
||||
* [StackOverflow](http://stackoverflow.com/questions/tagged/jsqmessagesviewcontroller) is often the most appropriate place for questions and help. We have our own tag, `jsqmessagesviewcontroller`.
|
||||
* See the [Migration Guide](https://github.com/jessesquires/JSQMessagesViewController/blob/develop/Documentation/migration.md) for migrating between major versions of the library.
|
||||
* **Only ask questions that are _specific_ to this library.**
|
||||
* **Please avoid emailing questions.** I prefer to keep questions and their answers open-source.
|
||||
|
||||
## Documentation
|
||||
|
||||
Read the docs, [available here][docsLink] via [@CocoaDocs](https://twitter.com/CocoaDocs).
|
||||
|
||||
## Core team
|
||||
|
||||
- Jesse Squires ([**@jesse_squires**](https://twitter.com/jesse_squires))
|
||||
- Harlan Haskans ([**@harlanhaskins**](https://github.com/harlanhaskins))
|
||||
- Eli Burke ([**@eliburke**](https://github.com/eliburke))
|
||||
|
||||
## Contributing
|
||||
|
||||
Please follow these sweet [contribution guidelines](https://github.com/jessesquires/JSQMessagesViewController/blob/develop/.github/CONTRIBUTING.md).
|
||||
|
||||
> **Interested in becoming a core contributor with push access? See our [onboarding guide](https://github.com/jessesquires/JSQMessagesViewController/blob/develop/Documentation/contributor_onboarding.md) for details.**
|
||||
|
||||
## Donate
|
||||
|
||||
Support the development of this **free** library! **[Donate](https://cash.me/$jsq)** via [Square Cash](https://cash.me/).
|
||||
|
||||
## Credits
|
||||
|
||||
* Created and maintained by [**@jesse_squires**](https://twitter.com/jesse_squires).
|
||||
* Many thanks to [**the contributors**](https://github.com/jessesquires/JSQMessagesViewController/graphs/contributors) of this project.
|
||||
* iOS assets extracted using [**@0xced**](https://github.com/0xced) / [iOS-Artwork-Extractor](https://github.com/0xced/iOS-Artwork-Extractor).
|
||||
|
||||
## Apps using this library
|
||||
|
||||
According to [CocoaPods stats](https://cocoapods.org/pods/JSQMessagesViewController), over **9,000 apps** are using `JSQMessagesViewController`. [Here are the ones](https://github.com/jessesquires/JSQMessagesViewController/blob/develop/Documentation/apps_using_this_library.md) that we know about. Please submit a [pull request](https://github.com/jessesquires/JSQMessagesViewController/compare) to add your app! :smile:
|
||||
|
||||
## License
|
||||
|
||||
`JSQMessagesViewController` is released under an [MIT License][mitLink]. See `LICENSE` for details.
|
||||
|
||||
>**Copyright © 2013-present Jesse Squires.**
|
||||
|
||||
*Please provide attribution, it is greatly appreciated.*
|
||||
|
||||
[docsLink]:http://cocoadocs.org/docsets/JSQMessagesViewController/
|
||||
[podLink]:https://cocoapods.org/pods/JSQMessagesViewController
|
||||
[mitLink]:http://opensource.org/licenses/MIT
|
||||
[playerLink]:https://github.com/jessesquires/JSQSystemSoundPlayer
|
||||
|
||||
[img0]:https://raw.githubusercontent.com/jessesquires/JSQMessagesViewController/develop/Screenshots/screenshot0.png
|
||||
[img1]:https://raw.githubusercontent.com/jessesquires/JSQMessagesViewController/develop/Screenshots/screenshot1.png
|
||||
[img2]:https://raw.githubusercontent.com/jessesquires/JSQMessagesViewController/develop/Screenshots/screenshot2.png
|
||||
[img3]:https://raw.githubusercontent.com/jessesquires/JSQMessagesViewController/develop/Screenshots/screenshot3.png
|
|
@ -1,7 +0,0 @@
|
|||
The files in this directory are drawn from JSQMessagesViewController, created by Jesse Squires. These files have been pulled into the Signal-iOS repository with his permission.
|
||||
|
||||
https://github.com/jessesquires/JSQMessagesViewController
|
||||
|
||||
These files are available under the MIT License. See JSQMVC-LICENSE.
|
||||
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
//
|
||||
// Created by Jesse Squires
|
||||
// http://www.jessesquires.com
|
||||
//
|
||||
//
|
||||
// Documentation
|
||||
// http://cocoadocs.org/docsets/JSQMessagesViewController
|
||||
//
|
||||
//
|
||||
// GitHub
|
||||
// https://github.com/jessesquires/JSQMessagesViewController
|
||||
//
|
||||
//
|
||||
// License
|
||||
// Copyright (c) 2014 Jesse Squires
|
||||
// Released under an MIT license: http://opensource.org/licenses/MIT
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
/**
|
||||
* The `JSQMessageAvatarImageDataSource` protocol defines the common interface through which
|
||||
* a `JSQMessagesViewController` and `JSQMessagesCollectionView` interact with avatar image model objects.
|
||||
*
|
||||
* It declares the required and optional methods that a class must implement so that instances
|
||||
* of that class can be display properly within a `JSQMessagesCollectionViewCell`.
|
||||
*
|
||||
* A concrete class that conforms to this protocol is provided in the library. See `JSQMessagesAvatarImage`.
|
||||
*
|
||||
* @see JSQMessagesAvatarImage.
|
||||
*/
|
||||
@protocol JSQMessageAvatarImageDataSource <NSObject>
|
||||
|
||||
@required
|
||||
|
||||
/**
|
||||
* @return The avatar image for a regular display state.
|
||||
*
|
||||
* @discussion You may return `nil` from this method while the image is being downloaded.
|
||||
*/
|
||||
- (UIImage *)avatarImage;
|
||||
|
||||
/**
|
||||
* @return The avatar image for a highlighted display state.
|
||||
*
|
||||
* @discussion You may return `nil` from this method if this does not apply.
|
||||
*/
|
||||
- (UIImage *)avatarHighlightedImage;
|
||||
|
||||
/**
|
||||
* @return A placeholder avatar image to be displayed if avatarImage is not yet available, or `nil`.
|
||||
* For example, if avatarImage needs to be downloaded, this placeholder image
|
||||
* will be used until avatarImage is not `nil`.
|
||||
*
|
||||
* @discussion If you do not need support for a placeholder image, that is, your images
|
||||
* are stored locally on the device, then you may simply return the same value as avatarImage here.
|
||||
*
|
||||
* @warning You must not return `nil` from this method.
|
||||
*/
|
||||
- (UIImage *)avatarPlaceholderImage;
|
||||
|
||||
@end
|
|
@ -1,86 +0,0 @@
|
|||
//
|
||||
// Created by Jesse Squires
|
||||
// http://www.jessesquires.com
|
||||
//
|
||||
//
|
||||
// Documentation
|
||||
// http://cocoadocs.org/docsets/JSQMessagesViewController
|
||||
//
|
||||
//
|
||||
// GitHub
|
||||
// https://github.com/jessesquires/JSQMessagesViewController
|
||||
//
|
||||
//
|
||||
// License
|
||||
// Copyright (c) 2014 Jesse Squires
|
||||
// Released under an MIT license: http://opensource.org/licenses/MIT
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "JSQMessageAvatarImageDataSource.h"
|
||||
|
||||
/**
|
||||
* A `JSQMessagesAvatarImage` model object represents an avatar image.
|
||||
* This is a concrete class that implements the `JSQMessageAvatarImageDataSource` protocol.
|
||||
* It contains a regular avatar image, a highlighted avatar image, and a placeholder avatar image.
|
||||
*
|
||||
* @see JSQMessagesAvatarImageFactory.
|
||||
*/
|
||||
@interface JSQMessagesAvatarImage : NSObject <JSQMessageAvatarImageDataSource, NSCopying>
|
||||
|
||||
/**
|
||||
* The avatar image for a regular display state.
|
||||
*/
|
||||
@property (nonatomic, strong) UIImage *avatarImage;
|
||||
|
||||
/**
|
||||
* The avatar image for a highlighted display state.
|
||||
*/
|
||||
@property (nonatomic, strong) UIImage *avatarHighlightedImage;
|
||||
|
||||
/**
|
||||
* Returns the placeholder image for an avatar to display if avatarImage is `nil`.
|
||||
*/
|
||||
@property (nonatomic, strong, readonly) UIImage *avatarPlaceholderImage;
|
||||
|
||||
/**
|
||||
* Initializes and returns an avatar image object having the specified image.
|
||||
*
|
||||
* @param image The image for this avatar image. This image will be used for the all of the following
|
||||
* properties: avatarImage, avatarHighlightedImage, avatarPlaceholderImage;
|
||||
* This value must not be `nil`.
|
||||
*
|
||||
* @return An initialized `JSQMessagesAvatarImage` object if successful, `nil` otherwise.
|
||||
*/
|
||||
+ (instancetype)avatarWithImage:(UIImage *)image;
|
||||
|
||||
/**
|
||||
* Initializes and returns an avatar image object having the specified placeholder image.
|
||||
*
|
||||
* @param placeholderImage The placeholder image for this avatar image. This value must not be `nil`.
|
||||
*
|
||||
* @return An initialized `JSQMessagesAvatarImage` object if successful, `nil` otherwise.
|
||||
*/
|
||||
+ (instancetype)avatarImageWithPlaceholder:(UIImage *)placeholderImage;
|
||||
|
||||
/**
|
||||
* Initializes and returns an avatar image object having the specified regular, highlighed, and placeholder images.
|
||||
*
|
||||
* @param avatarImage The avatar image for a regular display state.
|
||||
* @param highlightedImage The avatar image for a highlighted display state.
|
||||
* @param placeholderImage The placeholder image for this avatar image. This value must not be `nil`.
|
||||
*
|
||||
* @return An initialized `JSQMessagesAvatarImage` object if successful, `nil` otherwise.
|
||||
*/
|
||||
- (instancetype)initWithAvatarImage:(UIImage *)avatarImage
|
||||
highlightedImage:(UIImage *)highlightedImage
|
||||
placeholderImage:(UIImage *)placeholderImage NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
/**
|
||||
* Not a valid initializer.
|
||||
*/
|
||||
- (id)init NS_UNAVAILABLE;
|
||||
|
||||
@end
|
|
@ -1,78 +0,0 @@
|
|||
//
|
||||
// Created by Jesse Squires
|
||||
// http://www.jessesquires.com
|
||||
//
|
||||
//
|
||||
// Documentation
|
||||
// http://cocoadocs.org/docsets/JSQMessagesViewController
|
||||
//
|
||||
//
|
||||
// GitHub
|
||||
// https://github.com/jessesquires/JSQMessagesViewController
|
||||
//
|
||||
//
|
||||
// License
|
||||
// Copyright (c) 2014 Jesse Squires
|
||||
// Released under an MIT license: http://opensource.org/licenses/MIT
|
||||
//
|
||||
|
||||
#import "JSQMessagesAvatarImage.h"
|
||||
|
||||
@implementation JSQMessagesAvatarImage
|
||||
|
||||
#pragma mark - Initialization
|
||||
|
||||
+ (instancetype)avatarWithImage:(UIImage *)image
|
||||
{
|
||||
NSParameterAssert(image != nil);
|
||||
|
||||
return [[JSQMessagesAvatarImage alloc] initWithAvatarImage:image
|
||||
highlightedImage:image
|
||||
placeholderImage:image];
|
||||
}
|
||||
|
||||
+ (instancetype)avatarImageWithPlaceholder:(UIImage *)placeholderImage
|
||||
{
|
||||
return [[JSQMessagesAvatarImage alloc] initWithAvatarImage:nil
|
||||
highlightedImage:nil
|
||||
placeholderImage:placeholderImage];
|
||||
}
|
||||
|
||||
- (instancetype)initWithAvatarImage:(UIImage *)avatarImage
|
||||
highlightedImage:(UIImage *)highlightedImage
|
||||
placeholderImage:(UIImage *)placeholderImage
|
||||
{
|
||||
NSParameterAssert(placeholderImage != nil);
|
||||
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_avatarImage = avatarImage;
|
||||
_avatarHighlightedImage = highlightedImage;
|
||||
_avatarPlaceholderImage = placeholderImage;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - NSObject
|
||||
|
||||
- (NSString *)description
|
||||
{
|
||||
return [NSString stringWithFormat:@"<%@: avatarImage=%@, avatarHighlightedImage=%@, avatarPlaceholderImage=%@>",
|
||||
[self class], self.avatarImage, self.avatarHighlightedImage, self.avatarPlaceholderImage];
|
||||
}
|
||||
|
||||
- (id)debugQuickLookObject
|
||||
{
|
||||
return [[UIImageView alloc] initWithImage:self.avatarImage ?: self.avatarPlaceholderImage];
|
||||
}
|
||||
|
||||
#pragma mark - NSCopying
|
||||
|
||||
- (instancetype)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
return [[[self class] allocWithZone:zone] initWithAvatarImage:[UIImage imageWithCGImage:self.avatarImage.CGImage]
|
||||
highlightedImage:[UIImage imageWithCGImage:self.avatarHighlightedImage.CGImage]
|
||||
placeholderImage:[UIImage imageWithCGImage:self.avatarPlaceholderImage.CGImage]];
|
||||
}
|
||||
|
||||
@end
|
|
@ -1,99 +0,0 @@
|
|||
//
|
||||
// Created by Jesse Squires
|
||||
// http://www.jessesquires.com
|
||||
//
|
||||
//
|
||||
// Documentation
|
||||
// http://cocoadocs.org/docsets/JSQMessagesViewController
|
||||
//
|
||||
//
|
||||
// GitHub
|
||||
// https://github.com/jessesquires/JSQMessagesViewController
|
||||
//
|
||||
//
|
||||
// License
|
||||
// Copyright (c) 2014 Jesse Squires
|
||||
// Released under an MIT license: http://opensource.org/licenses/MIT
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "JSQMessagesAvatarImage.h"
|
||||
|
||||
/**
|
||||
* `JSQMessagesAvatarImageFactory` is a factory that provides a means for creating and styling
|
||||
* `JSQMessagesAvatarImage` objects to be displayed in a `JSQMessagesCollectionViewCell` of a `JSQMessagesCollectionView`.
|
||||
*/
|
||||
@interface JSQMessagesAvatarImageFactory : NSObject
|
||||
|
||||
/**
|
||||
* Creates and returns a `JSQMessagesAvatarImage` object with the specified placeholderImage that is
|
||||
* cropped to a circle of the given diameter.
|
||||
*
|
||||
* @param placeholderImage An image object that represents a placeholder avatar image. This value must not be `nil`.
|
||||
* @param diameter An integer value specifying the diameter size of the avatar in points. This value must be greater than `0`.
|
||||
*
|
||||
* @return An initialized `JSQMessagesAvatarImage` object if created successfully, `nil` otherwise.
|
||||
*/
|
||||
+ (JSQMessagesAvatarImage *)avatarImageWithPlaceholder:(UIImage *)placeholderImage diameter:(NSUInteger)diameter;
|
||||
|
||||
/**
|
||||
* Creates and returns a `JSQMessagesAvatarImage` object with the specified image that is
|
||||
* cropped to a circle of the given diameter and used for the `avatarImage` and `avatarPlaceholderImage` properties
|
||||
* of the returned `JSQMessagesAvatarImage` object. This image is then copied and has a transparent black mask applied to it,
|
||||
* which is used for the `avatarHighlightedImage` property of the returned `JSQMessagesAvatarImage` object.
|
||||
*
|
||||
* @param image An image object that represents an avatar image. This value must not be `nil`.
|
||||
* @param diameter An integer value specifying the diameter size of the avatar in points. This value must be greater than `0`.
|
||||
*
|
||||
* @return An initialized `JSQMessagesAvatarImage` object if created successfully, `nil` otherwise.
|
||||
*/
|
||||
+ (JSQMessagesAvatarImage *)avatarImageWithImage:(UIImage *)image diameter:(NSUInteger)diameter;
|
||||
|
||||
/**
|
||||
* Returns a copy of the specified image that is cropped to a circle with the given diameter.
|
||||
*
|
||||
* @param image The image to crop. This value must not be `nil`.
|
||||
* @param diameter An integer value specifying the diameter size of the image in points. This value must be greater than `0`.
|
||||
*
|
||||
* @return A new image object if successful, `nil` otherwise.
|
||||
*/
|
||||
+ (UIImage *)circularAvatarImage:(UIImage *)image withDiameter:(NSUInteger)diameter;
|
||||
|
||||
/**
|
||||
* Returns a copy of the specified image that is cropped to a circle with the given diameter.
|
||||
* Additionally, a transparent overlay is applied to the image to represent a pressed or highlighted state.
|
||||
*
|
||||
* @param image The image to crop. This value must not be `nil`.
|
||||
* @param diameter An integer value specifying the diameter size of the image in points. This value must be greater than `0`.
|
||||
*
|
||||
* @return A new image object if successful, `nil` otherwise.
|
||||
*/
|
||||
+ (UIImage *)circularAvatarHighlightedImage:(UIImage *)image withDiameter:(NSUInteger)diameter;
|
||||
|
||||
/**
|
||||
* Creates and returns a `JSQMessagesAvatarImage` object with a circular shape that displays the specified userInitials
|
||||
* with the given backgroundColor, textColor, font, and diameter.
|
||||
*
|
||||
* @param userInitials The user initials to display in the avatar image. This value must not be `nil`.
|
||||
* @param backgroundColor The background color of the avatar. This value must not be `nil`.
|
||||
* @param textColor The color of the text of the userInitials. This value must not be `nil`.
|
||||
* @param font The font applied to userInitials. This value must not be `nil`.
|
||||
* @param diameter The diameter of the avatar image. This value must be greater than `0`.
|
||||
*
|
||||
* @return An initialized `JSQMessagesAvatarImage` object if created successfully, `nil` otherwise.
|
||||
*
|
||||
* @discussion This method does not attempt to detect or correct incompatible parameters.
|
||||
* That is to say, you are responsible for providing a font size and diameter that make sense.
|
||||
* For example, a font size of `14.0f` and a diameter of `34.0f` will result in an avatar similar to Messages in iOS 7.
|
||||
* However, a font size `30.0f` and diameter of `10.0f` will not produce a desirable image.
|
||||
* Further, this method does not check the length of userInitials. It is recommended that you pass a string of length `2` or `3`.
|
||||
*/
|
||||
+ (JSQMessagesAvatarImage *)avatarImageWithUserInitials:(NSString *)userInitials
|
||||
backgroundColor:(UIColor *)backgroundColor
|
||||
textColor:(UIColor *)textColor
|
||||
font:(UIFont *)font
|
||||
diameter:(NSUInteger)diameter;
|
||||
|
||||
@end
|
|
@ -1,159 +0,0 @@
|
|||
//
|
||||
// Created by Jesse Squires
|
||||
// http://www.jessesquires.com
|
||||
//
|
||||
//
|
||||
// Documentation
|
||||
// http://cocoadocs.org/docsets/JSQMessagesViewController
|
||||
//
|
||||
//
|
||||
// GitHub
|
||||
// https://github.com/jessesquires/JSQMessagesViewController
|
||||
//
|
||||
//
|
||||
// License
|
||||
// Copyright (c) 2014 Jesse Squires
|
||||
// Released under an MIT license: http://opensource.org/licenses/MIT
|
||||
//
|
||||
|
||||
#import "JSQMessagesAvatarImageFactory.h"
|
||||
|
||||
#import "UIColor+JSQMessages.h"
|
||||
|
||||
|
||||
@implementation JSQMessagesAvatarImageFactory
|
||||
|
||||
#pragma mark - Public
|
||||
|
||||
+ (JSQMessagesAvatarImage *)avatarImageWithPlaceholder:(UIImage *)placeholderImage diameter:(NSUInteger)diameter
|
||||
{
|
||||
UIImage *circlePlaceholderImage = [JSQMessagesAvatarImageFactory jsq_circularImage:placeholderImage
|
||||
withDiameter:diameter
|
||||
highlightedColor:nil];
|
||||
|
||||
return [JSQMessagesAvatarImage avatarImageWithPlaceholder:circlePlaceholderImage];
|
||||
}
|
||||
|
||||
+ (JSQMessagesAvatarImage *)avatarImageWithImage:(UIImage *)image diameter:(NSUInteger)diameter
|
||||
{
|
||||
UIImage *avatar = [JSQMessagesAvatarImageFactory circularAvatarImage:image withDiameter:diameter];
|
||||
UIImage *highlightedAvatar = [JSQMessagesAvatarImageFactory circularAvatarHighlightedImage:image withDiameter:diameter];
|
||||
|
||||
return [[JSQMessagesAvatarImage alloc] initWithAvatarImage:avatar
|
||||
highlightedImage:highlightedAvatar
|
||||
placeholderImage:avatar];
|
||||
}
|
||||
|
||||
+ (UIImage *)circularAvatarImage:(UIImage *)image withDiameter:(NSUInteger)diameter
|
||||
{
|
||||
return [JSQMessagesAvatarImageFactory jsq_circularImage:image
|
||||
withDiameter:diameter
|
||||
highlightedColor:nil];
|
||||
}
|
||||
|
||||
+ (UIImage *)circularAvatarHighlightedImage:(UIImage *)image withDiameter:(NSUInteger)diameter
|
||||
{
|
||||
return [JSQMessagesAvatarImageFactory jsq_circularImage:image
|
||||
withDiameter:diameter
|
||||
highlightedColor:[UIColor colorWithWhite:0.1f alpha:0.3f]];
|
||||
}
|
||||
|
||||
+ (JSQMessagesAvatarImage *)avatarImageWithUserInitials:(NSString *)userInitials
|
||||
backgroundColor:(UIColor *)backgroundColor
|
||||
textColor:(UIColor *)textColor
|
||||
font:(UIFont *)font
|
||||
diameter:(NSUInteger)diameter
|
||||
{
|
||||
UIImage *avatarImage = [JSQMessagesAvatarImageFactory jsq_imageWitInitials:userInitials
|
||||
backgroundColor:backgroundColor
|
||||
textColor:textColor
|
||||
font:font
|
||||
diameter:diameter];
|
||||
|
||||
UIImage *avatarHighlightedImage = [JSQMessagesAvatarImageFactory jsq_circularImage:avatarImage
|
||||
withDiameter:diameter
|
||||
highlightedColor:[UIColor colorWithWhite:0.1f alpha:0.3f]];
|
||||
|
||||
return [[JSQMessagesAvatarImage alloc] initWithAvatarImage:avatarImage
|
||||
highlightedImage:avatarHighlightedImage
|
||||
placeholderImage:avatarImage];
|
||||
}
|
||||
|
||||
#pragma mark - Private
|
||||
|
||||
+ (UIImage *)jsq_imageWitInitials:(NSString *)initials
|
||||
backgroundColor:(UIColor *)backgroundColor
|
||||
textColor:(UIColor *)textColor
|
||||
font:(UIFont *)font
|
||||
diameter:(NSUInteger)diameter
|
||||
{
|
||||
NSParameterAssert(initials != nil);
|
||||
NSParameterAssert(backgroundColor != nil);
|
||||
NSParameterAssert(textColor != nil);
|
||||
NSParameterAssert(font != nil);
|
||||
NSParameterAssert(diameter > 0);
|
||||
|
||||
CGRect frame = CGRectMake(0.0f, 0.0f, diameter, diameter);
|
||||
|
||||
NSDictionary *attributes = @{ NSFontAttributeName : font,
|
||||
NSForegroundColorAttributeName : textColor };
|
||||
|
||||
CGRect textFrame = [initials boundingRectWithSize:frame.size
|
||||
options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading)
|
||||
attributes:attributes
|
||||
context:nil];
|
||||
|
||||
CGPoint frameMidPoint = CGPointMake(CGRectGetMidX(frame), CGRectGetMidY(frame));
|
||||
CGPoint textFrameMidPoint = CGPointMake(CGRectGetMidX(textFrame), CGRectGetMidY(textFrame));
|
||||
|
||||
CGFloat dx = frameMidPoint.x - textFrameMidPoint.x;
|
||||
CGFloat dy = frameMidPoint.y - textFrameMidPoint.y;
|
||||
CGPoint drawPoint = CGPointMake(dx, dy);
|
||||
UIImage *image = nil;
|
||||
|
||||
UIGraphicsBeginImageContextWithOptions(frame.size, NO, [UIScreen mainScreen].scale);
|
||||
{
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
|
||||
CGContextSetFillColorWithColor(context, backgroundColor.CGColor);
|
||||
CGContextFillRect(context, frame);
|
||||
[initials drawAtPoint:drawPoint withAttributes:attributes];
|
||||
|
||||
image = UIGraphicsGetImageFromCurrentImageContext();
|
||||
|
||||
}
|
||||
UIGraphicsEndImageContext();
|
||||
|
||||
return [JSQMessagesAvatarImageFactory jsq_circularImage:image withDiameter:diameter highlightedColor:nil];
|
||||
}
|
||||
|
||||
+ (UIImage *)jsq_circularImage:(UIImage *)image withDiameter:(NSUInteger)diameter highlightedColor:(UIColor *)highlightedColor
|
||||
{
|
||||
NSParameterAssert(image != nil);
|
||||
NSParameterAssert(diameter > 0);
|
||||
|
||||
CGRect frame = CGRectMake(0.0f, 0.0f, diameter, diameter);
|
||||
UIImage *newImage = nil;
|
||||
|
||||
UIGraphicsBeginImageContextWithOptions(frame.size, NO, [UIScreen mainScreen].scale);
|
||||
{
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
|
||||
UIBezierPath *imgPath = [UIBezierPath bezierPathWithOvalInRect:frame];
|
||||
[imgPath addClip];
|
||||
[image drawInRect:frame];
|
||||
|
||||
if (highlightedColor != nil) {
|
||||
CGContextSetFillColorWithColor(context, highlightedColor.CGColor);
|
||||
CGContextFillEllipseInRect(context, frame);
|
||||
}
|
||||
|
||||
newImage = UIGraphicsGetImageFromCurrentImageContext();
|
||||
|
||||
}
|
||||
UIGraphicsEndImageContext();
|
||||
|
||||
return newImage;
|
||||
}
|
||||
|
||||
@end
|
|
@ -1,56 +0,0 @@
|
|||
//
|
||||
// Created by Jesse Squires
|
||||
// http://www.jessesquires.com
|
||||
//
|
||||
//
|
||||
// Documentation
|
||||
// http://cocoadocs.org/docsets/JSQMessagesViewController
|
||||
//
|
||||
//
|
||||
// GitHub
|
||||
// https://github.com/jessesquires/JSQMessagesViewController
|
||||
//
|
||||
//
|
||||
// License
|
||||
// Copyright (c) 2014 Jesse Squires
|
||||
// Released under an MIT license: http://opensource.org/licenses/MIT
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface UIColor (JSQMessages)
|
||||
|
||||
#pragma mark - Message bubble colors
|
||||
|
||||
/**
|
||||
* @return A color object containing HSB values similar to the iOS 7 messages app green bubble color.
|
||||
*/
|
||||
+ (UIColor *)jsq_messageBubbleGreenColor;
|
||||
|
||||
/**
|
||||
* @return A color object containing HSB values similar to the iOS 7 messages app blue bubble color.
|
||||
*/
|
||||
+ (UIColor *)jsq_messageBubbleBlueColor;
|
||||
|
||||
/**
|
||||
* @return A color object containing HSB values similar to the iOS 7 red color.
|
||||
*/
|
||||
+ (UIColor *)jsq_messageBubbleRedColor;
|
||||
|
||||
/**
|
||||
* @return A color object containing HSB values similar to the iOS 7 messages app light gray bubble color.
|
||||
*/
|
||||
+ (UIColor *)jsq_messageBubbleLightGrayColor;
|
||||
|
||||
#pragma mark - Utilities
|
||||
|
||||
/**
|
||||
* Creates and returns a new color object whose brightness component is decreased by the given value, using the initial color values of the receiver.
|
||||
*
|
||||
* @param value A floating point value describing the amount by which to decrease the brightness of the receiver.
|
||||
*
|
||||
* @return A new color object whose brightness is decreased by the given values. The other color values remain the same as the receiver.
|
||||
*/
|
||||
- (UIColor *)jsq_colorByDarkeningColorWithValue:(CGFloat)value;
|
||||
|
||||
@end
|
|
@ -1,90 +0,0 @@
|
|||
//
|
||||
// Created by Jesse Squires
|
||||
// http://www.jessesquires.com
|
||||
//
|
||||
//
|
||||
// Documentation
|
||||
// http://cocoadocs.org/docsets/JSQMessagesViewController
|
||||
//
|
||||
//
|
||||
// GitHub
|
||||
// https://github.com/jessesquires/JSQMessagesViewController
|
||||
//
|
||||
//
|
||||
// License
|
||||
// Copyright (c) 2014 Jesse Squires
|
||||
// Released under an MIT license: http://opensource.org/licenses/MIT
|
||||
//
|
||||
|
||||
#import "UIColor+JSQMessages.h"
|
||||
|
||||
@implementation UIColor (JSQMessages)
|
||||
|
||||
#pragma mark - Message bubble colors
|
||||
|
||||
+ (UIColor *)jsq_messageBubbleGreenColor
|
||||
{
|
||||
return [UIColor colorWithHue:130.0f / 360.0f
|
||||
saturation:0.68f
|
||||
brightness:0.84f
|
||||
alpha:1.0f];
|
||||
}
|
||||
|
||||
+ (UIColor *)jsq_messageBubbleBlueColor
|
||||
{
|
||||
return [UIColor colorWithHue:210.0f / 360.0f
|
||||
saturation:0.94f
|
||||
brightness:1.0f
|
||||
alpha:1.0f];
|
||||
}
|
||||
|
||||
+ (UIColor *)jsq_messageBubbleRedColor
|
||||
{
|
||||
return [UIColor colorWithHue:0.0f / 360.0f
|
||||
saturation:0.79f
|
||||
brightness:1.0f
|
||||
alpha:1.0f];
|
||||
}
|
||||
|
||||
+ (UIColor *)jsq_messageBubbleLightGrayColor
|
||||
{
|
||||
return [UIColor colorWithHue:240.0f / 360.0f
|
||||
saturation:0.02f
|
||||
brightness:0.92f
|
||||
alpha:1.0f];
|
||||
}
|
||||
|
||||
#pragma mark - Utilities
|
||||
|
||||
- (UIColor *)jsq_colorByDarkeningColorWithValue:(CGFloat)value
|
||||
{
|
||||
NSUInteger totalComponents = CGColorGetNumberOfComponents(self.CGColor);
|
||||
BOOL isGreyscale = (totalComponents == 2) ? YES : NO;
|
||||
|
||||
CGFloat *oldComponents = (CGFloat *)CGColorGetComponents(self.CGColor);
|
||||
CGFloat newComponents[4];
|
||||
|
||||
if (isGreyscale) {
|
||||
newComponents[0] = oldComponents[0] - value < 0.0f ? 0.0f : oldComponents[0] - value;
|
||||
newComponents[1] = oldComponents[0] - value < 0.0f ? 0.0f : oldComponents[0] - value;
|
||||
newComponents[2] = oldComponents[0] - value < 0.0f ? 0.0f : oldComponents[0] - value;
|
||||
newComponents[3] = oldComponents[1];
|
||||
}
|
||||
else {
|
||||
newComponents[0] = oldComponents[0] - value < 0.0f ? 0.0f : oldComponents[0] - value;
|
||||
newComponents[1] = oldComponents[1] - value < 0.0f ? 0.0f : oldComponents[1] - value;
|
||||
newComponents[2] = oldComponents[2] - value < 0.0f ? 0.0f : oldComponents[2] - value;
|
||||
newComponents[3] = oldComponents[3];
|
||||
}
|
||||
|
||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
CGColorRef newColor = CGColorCreate(colorSpace, newComponents);
|
||||
CGColorSpaceRelease(colorSpace);
|
||||
|
||||
UIColor *retColor = [UIColor colorWithCGColor:newColor];
|
||||
CGColorRelease(newColor);
|
||||
|
||||
return retColor;
|
||||
}
|
||||
|
||||
@end
|
|
@ -49,7 +49,7 @@ public class ContactShareViewModel: NSObject {
|
|||
}
|
||||
|
||||
@objc
|
||||
public func getAvatarImage(diameter: CGFloat, contactsManager: OWSContactsManager) -> UIImage {
|
||||
public func getAvatarImage(diameter: CGFloat, contactsManager: OWSContactsManager) -> UIImage? {
|
||||
if let avatarImage = avatarImage {
|
||||
return avatarImage
|
||||
}
|
||||
|
|
|
@ -200,10 +200,9 @@ const CGFloat kContactCellAvatarTextMargin = 12;
|
|||
return [TSThread stableConversationColorNameForString:self.recipientId];
|
||||
}
|
||||
}();
|
||||
UIColor *color = [UIColor ows_conversationColorForColorName:colorName];
|
||||
|
||||
|
||||
self.avatarView.image = [[[OWSContactAvatarBuilder alloc] initWithSignalId:recipientId
|
||||
color:color
|
||||
colorName:colorName
|
||||
diameter:kContactCellAvatarSize
|
||||
contactsManager:contactsManager] build];
|
||||
}
|
||||
|
|
|
@ -31,12 +31,10 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
#pragma mark - ConversationColor
|
||||
|
||||
+ (nullable UIColor *)ows_conversationColorForColorName:(NSString *)colorName
|
||||
NS_SWIFT_NAME(ows_conversationColor(colorName:));
|
||||
+ (nullable NSString *)ows_conversationColorNameForColor:(UIColor *)color
|
||||
NS_SWIFT_NAME(ows_conversationColorName(color:));
|
||||
isShaded:(BOOL)isShaded
|
||||
NS_SWIFT_NAME(ows_conversationColor(colorName:isShaded:));
|
||||
|
||||
@property (class, readonly, nonatomic) NSArray<NSString *> *ows_conversationColorNames;
|
||||
@property (class, readonly, nonatomic) NSArray<UIColor *> *ows_conversationColors;
|
||||
|
||||
- (UIColor *)blendWithColor:(UIColor *)otherColor alpha:(CGFloat)alpha;
|
||||
|
||||
|
@ -73,6 +71,8 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
@property (class, readonly, nonatomic) UIColor *ows_grey600Color;
|
||||
@property (class, readonly, nonatomic) UIColor *ows_darkSkyBlueColor;
|
||||
|
||||
+ (NSString *)ows_defaultConversationColorName;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
|
@ -251,7 +251,29 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
return [UIColor colorWithRed:32.f / 255.f green:144.f / 255.f blue:234.f / 255.f alpha:1.f];
|
||||
}
|
||||
|
||||
+ (NSDictionary<NSString *, UIColor *> *)ows_conversationColorMap
|
||||
+ (NSDictionary<NSString *, UIColor *> *)ows_conversationColorMapLight
|
||||
{
|
||||
static NSDictionary<NSString *, UIColor *> *colorMap;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
colorMap = @{
|
||||
@"red" : self.ows_red700Color,
|
||||
@"pink" : self.ows_pink600Color,
|
||||
@"purple" : self.ows_purple600Color,
|
||||
@"indigo" : self.ows_indigo600Color,
|
||||
@"blue" : self.ows_blue700Color,
|
||||
@"cyan" : self.ows_cyan800Color,
|
||||
@"teal" : self.ows_teal700Color,
|
||||
@"green" : self.ows_green800Color,
|
||||
@"deep_orange" : self.ows_deepOrange900Color,
|
||||
@"grey" : self.ows_grey600Color
|
||||
};
|
||||
});
|
||||
|
||||
return colorMap;
|
||||
}
|
||||
|
||||
+ (NSDictionary<NSString *, UIColor *> *)ows_conversationColorMapDark
|
||||
{
|
||||
static NSDictionary<NSString *, UIColor *> *colorMap;
|
||||
static dispatch_once_t onceToken;
|
||||
|
@ -275,24 +297,22 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
+ (NSArray<NSString *> *)ows_conversationColorNames
|
||||
{
|
||||
return self.ows_conversationColorMap.allKeys;
|
||||
OWSAssertDebug(
|
||||
[self.ows_conversationColorMapLight.allKeys isEqualToArray:self.ows_conversationColorMapDark.allKeys]);
|
||||
|
||||
return self.ows_conversationColorMapLight.allKeys;
|
||||
}
|
||||
|
||||
+ (NSArray<UIColor *> *)ows_conversationColors
|
||||
{
|
||||
return self.ows_conversationColorMap.allValues;
|
||||
}
|
||||
|
||||
+ (nullable UIColor *)ows_conversationColorForColorName:(NSString *)colorName
|
||||
+ (nullable UIColor *)ows_conversationColorForColorName:(NSString *)colorName isShaded:(BOOL)isShaded
|
||||
{
|
||||
OWSAssertDebug(colorName.length > 0);
|
||||
|
||||
return [self.ows_conversationColorMap objectForKey:colorName];
|
||||
return (isShaded ? self.ows_conversationColorMapDark : self.ows_conversationColorMapLight)[colorName];
|
||||
}
|
||||
|
||||
+ (nullable NSString *)ows_conversationColorNameForColor:(UIColor *)color
|
||||
+ (NSString *)ows_defaultConversationColorName
|
||||
{
|
||||
return [self.ows_conversationColorMap allKeysForObject:color].firstObject;
|
||||
return @"teal";
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -136,7 +136,8 @@ public class ConversationStyle: NSObject {
|
|||
return self.defaultBubbleColorIncoming
|
||||
}
|
||||
|
||||
guard let color = UIColor.ows_conversationColor(colorName: colorName) else {
|
||||
guard let color = UIColor.ows_conversationColor(colorName: colorName,
|
||||
isShaded: Theme.isDarkThemeEnabled) else {
|
||||
return self.defaultBubbleColorIncoming
|
||||
}
|
||||
|
||||
|
|
|
@ -1,24 +1,33 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class TSThread;
|
||||
@class OWSContactsManager;
|
||||
@class TSThread;
|
||||
@class UIImage;
|
||||
|
||||
@interface OWSAvatarBuilder : NSObject
|
||||
|
||||
+ (UIImage *)buildImageForThread:(TSThread *)thread
|
||||
diameter:(NSUInteger)diameter
|
||||
contactsManager:(OWSContactsManager *)contactsManager NS_SWIFT_NAME(buildImage(thread:diameter:contactsManager:));
|
||||
+ (nullable UIImage *)buildImageForThread:(TSThread *)thread
|
||||
diameter:(NSUInteger)diameter
|
||||
contactsManager:(OWSContactsManager *)contactsManager
|
||||
NS_SWIFT_NAME(buildImage(thread:diameter:contactsManager:));
|
||||
|
||||
+ (UIImage *)buildRandomAvatarWithDiameter:(NSUInteger)diameter;
|
||||
+ (nullable UIImage *)buildRandomAvatarWithDiameter:(NSUInteger)diameter;
|
||||
|
||||
- (nullable UIImage *)buildSavedImage;
|
||||
- (UIImage *)buildDefaultImage;
|
||||
- (UIImage *)build;
|
||||
- (nullable UIImage *)buildDefaultImage;
|
||||
- (nullable UIImage *)build;
|
||||
|
||||
+ (nullable UIImage *)avatarImageWithInitials:(NSString *)initials
|
||||
backgroundColor:(UIColor *)backgroundColor
|
||||
diameter:(NSUInteger)diameter;
|
||||
|
||||
+ (nullable UIImage *)avatarImageWithIcon:(UIImage *)icon
|
||||
backgroundColor:(UIColor *)backgroundColor
|
||||
diameter:(NSUInteger)diameter;
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
@ -3,20 +3,22 @@
|
|||
//
|
||||
|
||||
#import "OWSAvatarBuilder.h"
|
||||
#import "JSQMessagesAvatarImageFactory.h"
|
||||
#import "OWSContactAvatarBuilder.h"
|
||||
#import "OWSGroupAvatarBuilder.h"
|
||||
#import "TSContactThread.h"
|
||||
#import "TSGroupThread.h"
|
||||
#import "UIColor+OWS.h"
|
||||
#import "UIFont+OWS.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
typedef void (^OWSAvatarDrawBlock)(CGContextRef context);
|
||||
|
||||
@implementation OWSAvatarBuilder
|
||||
|
||||
+ (UIImage *)buildImageForThread:(TSThread *)thread
|
||||
diameter:(NSUInteger)diameter
|
||||
contactsManager:(OWSContactsManager *)contactsManager
|
||||
+ (nullable UIImage *)buildImageForThread:(TSThread *)thread
|
||||
diameter:(NSUInteger)diameter
|
||||
contactsManager:(OWSContactsManager *)contactsManager
|
||||
{
|
||||
OWSAssertDebug(thread);
|
||||
OWSAssertDebug(contactsManager);
|
||||
|
@ -25,9 +27,8 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
if ([thread isKindOfClass:[TSContactThread class]]) {
|
||||
TSContactThread *contactThread = (TSContactThread *)thread;
|
||||
NSString *colorName = thread.conversationColorName;
|
||||
UIColor *color = [UIColor ows_conversationColorForColorName:colorName];
|
||||
avatarBuilder = [[OWSContactAvatarBuilder alloc] initWithSignalId:contactThread.contactIdentifier
|
||||
color:color
|
||||
colorName:colorName
|
||||
diameter:diameter
|
||||
contactsManager:contactsManager];
|
||||
} else if ([thread isKindOfClass:[TSGroupThread class]]) {
|
||||
|
@ -38,7 +39,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
return [avatarBuilder build];
|
||||
}
|
||||
|
||||
+ (UIImage *)buildRandomAvatarWithDiameter:(NSUInteger)diameter
|
||||
+ (nullable UIImage *)buildRandomAvatarWithDiameter:(NSUInteger)diameter
|
||||
{
|
||||
NSArray<NSString *> *eyes = @[ @":", @"=", @"8", @"B" ];
|
||||
NSArray<NSString *> *mouths = @[ @"3", @")", @"(", @"|", @"\\", @"P", @"D", @"o" ];
|
||||
|
@ -50,34 +51,194 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
NSString *randomEyebrow = eyebrows[arc4random_uniform((uint32_t)eyebrows.count)];
|
||||
NSString *face = [NSString stringWithFormat:@"%@%@%@", randomEyebrow, randomEye, randomMouth];
|
||||
|
||||
CGFloat fontSize = (CGFloat)(diameter / 2.4);
|
||||
UIColor *backgroundColor = [UIColor colorWithRGBHex:0xaca6633];
|
||||
|
||||
UIImage *srcImage =
|
||||
[[JSQMessagesAvatarImageFactory avatarImageWithUserInitials:face
|
||||
backgroundColor:[UIColor colorWithRGBHex:0xaca6633]
|
||||
textColor:[UIColor whiteColor]
|
||||
font:[UIFont boldSystemFontOfSize:fontSize]
|
||||
diameter:diameter] avatarImage];
|
||||
return [self avatarImageWithDiameter:diameter
|
||||
backgroundColor:backgroundColor
|
||||
drawBlock:^(CGContextRef context) {
|
||||
CGContextTranslateCTM(context, diameter / 2, diameter / 2);
|
||||
CGContextRotateCTM(context, (CGFloat)M_PI_2);
|
||||
CGContextTranslateCTM(context, -diameter / 2, -diameter / 2);
|
||||
|
||||
UIGraphicsBeginImageContext(srcImage.size);
|
||||
[self drawInitialsInAvatar:face
|
||||
textColor:self.avatarForegroundColor
|
||||
font:self.avatarTextFont
|
||||
diameter:diameter];
|
||||
}];
|
||||
}
|
||||
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
+ (UIColor *)avatarForegroundColor
|
||||
{
|
||||
return (Theme.isDarkThemeEnabled ? UIColor.ows_gray05Color : UIColor.ows_whiteColor);
|
||||
}
|
||||
|
||||
CGFloat width = srcImage.size.width;
|
||||
+ (UIFont *)avatarTextFont
|
||||
{
|
||||
return [UIFont ows_mediumFontWithSize:20.f];
|
||||
}
|
||||
|
||||
// Rotate
|
||||
CGContextTranslateCTM(context, width / 2, width / 2);
|
||||
CGContextRotateCTM(context, (CGFloat)M_PI_2);
|
||||
CGContextTranslateCTM(context, -width / 2, -width / 2);
|
||||
+ (nullable UIImage *)avatarImageWithInitials:(NSString *)initials
|
||||
backgroundColor:(UIColor *)backgroundColor
|
||||
diameter:(NSUInteger)diameter
|
||||
{
|
||||
return [self avatarImageWithInitials:initials
|
||||
backgroundColor:backgroundColor
|
||||
textColor:self.avatarForegroundColor
|
||||
font:self.avatarTextFont
|
||||
diameter:diameter];
|
||||
}
|
||||
|
||||
[srcImage drawAtPoint:CGPointMake(0, 0)];
|
||||
+ (nullable UIImage *)avatarImageWithInitials:(NSString *)initials
|
||||
backgroundColor:(UIColor *)backgroundColor
|
||||
textColor:(UIColor *)textColor
|
||||
font:(UIFont *)font
|
||||
diameter:(NSUInteger)diameter
|
||||
{
|
||||
OWSAssertDebug(initials);
|
||||
OWSAssertDebug(textColor);
|
||||
OWSAssertDebug(font);
|
||||
|
||||
return [self avatarImageWithDiameter:diameter
|
||||
backgroundColor:backgroundColor
|
||||
drawBlock:^(CGContextRef context) {
|
||||
[self drawInitialsInAvatar:initials textColor:textColor font:font diameter:diameter];
|
||||
}];
|
||||
}
|
||||
|
||||
+ (nullable UIImage *)avatarImageWithIcon:(UIImage *)icon
|
||||
backgroundColor:(UIColor *)backgroundColor
|
||||
diameter:(NSUInteger)diameter
|
||||
{
|
||||
return [self avatarImageWithIcon:icon
|
||||
iconColor:self.avatarForegroundColor
|
||||
backgroundColor:backgroundColor
|
||||
diameter:diameter];
|
||||
}
|
||||
|
||||
+ (nullable UIImage *)avatarImageWithIcon:(UIImage *)icon
|
||||
iconColor:(UIColor *)iconColor
|
||||
backgroundColor:(UIColor *)backgroundColor
|
||||
diameter:(NSUInteger)diameter
|
||||
{
|
||||
OWSAssertDebug(icon);
|
||||
OWSAssertDebug(iconColor);
|
||||
|
||||
return [self avatarImageWithDiameter:diameter
|
||||
backgroundColor:backgroundColor
|
||||
drawBlock:^(CGContextRef context) {
|
||||
[self drawIconInAvatar:icon iconColor:iconColor diameter:diameter];
|
||||
}];
|
||||
}
|
||||
|
||||
+ (nullable UIImage *)avatarImageWithDiameter:(NSUInteger)diameter
|
||||
backgroundColor:(UIColor *)backgroundColor
|
||||
drawBlock:(OWSAvatarDrawBlock)drawBlock
|
||||
{
|
||||
OWSAssertDebug(drawBlock);
|
||||
OWSAssertDebug(backgroundColor);
|
||||
OWSAssertDebug(diameter > 0);
|
||||
|
||||
CGRect frame = CGRectMake(0.0f, 0.0f, diameter, diameter);
|
||||
|
||||
UIGraphicsBeginImageContextWithOptions(frame.size, NO, [UIScreen mainScreen].scale);
|
||||
CGContextRef _Nullable context = UIGraphicsGetCurrentContext();
|
||||
if (!context) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
CGContextSetFillColorWithColor(context, backgroundColor.CGColor);
|
||||
CGContextFillRect(context, frame);
|
||||
|
||||
// Gradient
|
||||
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
|
||||
CGFloat gradientLocations[] = { 0.0, 1.0 };
|
||||
CGGradientRef _Nullable gradient = CGGradientCreateWithColors(colorspace,
|
||||
(__bridge CFArrayRef) @[
|
||||
(id)[UIColor colorWithWhite:0.f alpha:0.f].CGColor,
|
||||
(id)[UIColor colorWithWhite:0.f alpha:0.15f].CGColor,
|
||||
],
|
||||
gradientLocations);
|
||||
if (!gradient) {
|
||||
return nil;
|
||||
}
|
||||
CGPoint startPoint = CGPointMake(diameter * 0.5f, 0);
|
||||
CGPoint endPoint = CGPointMake(diameter * 0.5f, diameter);
|
||||
CGContextDrawLinearGradient(context,
|
||||
gradient,
|
||||
startPoint,
|
||||
endPoint,
|
||||
kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation);
|
||||
CFRelease(gradient);
|
||||
|
||||
CGContextSaveGState(context);
|
||||
drawBlock(context);
|
||||
CGContextRestoreGState(context);
|
||||
|
||||
UIImage *_Nullable image = UIGraphicsGetImageFromCurrentImageContext();
|
||||
|
||||
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
- (UIImage *)build
|
||||
+ (void)drawInitialsInAvatar:(NSString *)initials
|
||||
textColor:(UIColor *)textColor
|
||||
font:(UIFont *)font
|
||||
diameter:(NSUInteger)diameter
|
||||
{
|
||||
OWSAssertDebug(initials);
|
||||
OWSAssertDebug(textColor);
|
||||
OWSAssertDebug(font);
|
||||
OWSAssertDebug(diameter > 0);
|
||||
|
||||
CGRect frame = CGRectMake(0.0f, 0.0f, diameter, diameter);
|
||||
|
||||
NSDictionary *textAttributes = @{
|
||||
NSFontAttributeName : font,
|
||||
NSForegroundColorAttributeName : textColor,
|
||||
};
|
||||
CGSize textSize =
|
||||
[initials boundingRectWithSize:frame.size
|
||||
options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading)
|
||||
attributes:textAttributes
|
||||
context:nil]
|
||||
.size;
|
||||
// Ensure that the text fits within the avatar bounds, with a margin.
|
||||
if (textSize.width > 0 && textSize.height > 0) {
|
||||
CGFloat textDiameter = (CGFloat)sqrt(textSize.width * textSize.width + textSize.height * textSize.height);
|
||||
// Leave a 10% margin.
|
||||
CGFloat maxTextDiameter = diameter * 0.9f;
|
||||
if (textDiameter > maxTextDiameter) {
|
||||
font = [font fontWithSize:font.pointSize * maxTextDiameter / textDiameter];
|
||||
textAttributes = @{
|
||||
NSFontAttributeName : font,
|
||||
NSForegroundColorAttributeName : textColor,
|
||||
};
|
||||
textSize =
|
||||
[initials boundingRectWithSize:frame.size
|
||||
options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading)
|
||||
attributes:textAttributes
|
||||
context:nil]
|
||||
.size;
|
||||
}
|
||||
}
|
||||
|
||||
CGPoint drawPoint = CGPointMake((diameter - textSize.width) * 0.5f, (diameter - textSize.height) * 0.5f);
|
||||
|
||||
[initials drawAtPoint:drawPoint withAttributes:textAttributes];
|
||||
}
|
||||
|
||||
+ (void)drawIconInAvatar:(UIImage *)icon iconColor:(UIColor *)iconColor diameter:(NSUInteger)diameter
|
||||
{
|
||||
OWSAssertDebug(icon);
|
||||
OWSAssertDebug(iconColor);
|
||||
OWSAssertDebug(diameter > 0);
|
||||
|
||||
CGPoint drawPoint = CGPointMake((diameter - icon.size.width) * 0.5f, (diameter - icon.size.height) * 0.5f);
|
||||
[icon drawAtPoint:drawPoint];
|
||||
}
|
||||
|
||||
- (nullable UIImage *)build
|
||||
{
|
||||
UIImage *_Nullable savedImage = [self buildSavedImage];
|
||||
if (savedImage) {
|
||||
|
@ -93,10 +254,10 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
return nil;
|
||||
}
|
||||
|
||||
- (UIImage *)buildDefaultImage
|
||||
- (nullable UIImage *)buildDefaultImage
|
||||
{
|
||||
OWSAbstractMethod();
|
||||
return [UIImage new];
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -16,7 +16,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
*/
|
||||
|
||||
- (instancetype)initWithSignalId:(NSString *)signalId
|
||||
color:(UIColor *)color
|
||||
colorName:(NSString *)colorName
|
||||
diameter:(NSUInteger)diameter
|
||||
contactsManager:(OWSContactsManager *)contactsManager;
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
#import "UIColor+OWS.h"
|
||||
#import "UIFont+OWS.h"
|
||||
#import <SignalMessaging/SignalMessaging-Swift.h>
|
||||
#import "JSQMessagesAvatarImageFactory.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
|
@ -19,7 +18,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
@property (nonatomic, readonly) OWSContactsManager *contactsManager;
|
||||
@property (nonatomic, readonly) NSString *signalId;
|
||||
@property (nonatomic, readonly) NSString *contactName;
|
||||
@property (nonatomic, readonly) UIColor *color;
|
||||
@property (nonatomic, readonly) NSString *colorName;
|
||||
@property (nonatomic, readonly) NSUInteger diameter;
|
||||
|
||||
@end
|
||||
|
@ -30,7 +29,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
- (instancetype)initWithContactId:(NSString *)contactId
|
||||
name:(NSString *)name
|
||||
color:(UIColor *)color
|
||||
colorName:(NSString *)colorName
|
||||
diameter:(NSUInteger)diameter
|
||||
contactsManager:(OWSContactsManager *)contactsManager
|
||||
{
|
||||
|
@ -39,9 +38,11 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
return self;
|
||||
}
|
||||
|
||||
OWSAssertDebug(colorName.length > 0);
|
||||
|
||||
_signalId = contactId;
|
||||
_contactName = name;
|
||||
_color = color;
|
||||
_colorName = colorName;
|
||||
_diameter = diameter;
|
||||
_contactsManager = contactsManager;
|
||||
|
||||
|
@ -49,7 +50,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
}
|
||||
|
||||
- (instancetype)initWithSignalId:(NSString *)signalId
|
||||
color:(UIColor *)color
|
||||
colorName:(NSString *)colorName
|
||||
diameter:(NSUInteger)diameter
|
||||
contactsManager:(OWSContactsManager *)contactsManager
|
||||
{
|
||||
|
@ -61,7 +62,11 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
if (name.length == 0) {
|
||||
name = signalId;
|
||||
}
|
||||
return [self initWithContactId:signalId name:name color:color diameter:diameter contactsManager:contactsManager];
|
||||
return [self initWithContactId:signalId
|
||||
name:name
|
||||
colorName:colorName
|
||||
diameter:diameter
|
||||
contactsManager:contactsManager];
|
||||
}
|
||||
|
||||
- (instancetype)initWithNonSignalName:(NSString *)nonSignalName
|
||||
|
@ -71,11 +76,9 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
{
|
||||
|
||||
NSString *colorName = [TSThread stableConversationColorNameForString:colorSeed];
|
||||
UIColor *color = [UIColor ows_conversationColorForColorName:colorName];
|
||||
OWSAssertDebug(color);
|
||||
return [self initWithContactId:colorSeed
|
||||
name:nonSignalName
|
||||
color:color
|
||||
colorName:(NSString *)colorName
|
||||
diameter:diameter
|
||||
contactsManager:contactsManager];
|
||||
}
|
||||
|
@ -87,10 +90,15 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
return [self.contactsManager imageForPhoneIdentifier:self.signalId];
|
||||
}
|
||||
|
||||
- (UIImage *)buildDefaultImage
|
||||
- (id)cacheKey
|
||||
{
|
||||
return [NSString stringWithFormat:@"%@-%d", self.signalId, Theme.isDarkThemeEnabled];
|
||||
}
|
||||
|
||||
- (nullable UIImage *)buildDefaultImage
|
||||
{
|
||||
UIImage *cachedAvatar =
|
||||
[self.contactsManager.avatarCache imageForKey:self.signalId diameter:(CGFloat)self.diameter];
|
||||
[self.contactsManager.avatarCache imageForKey:self.cacheKey diameter:(CGFloat)self.diameter];
|
||||
if (cachedAvatar) {
|
||||
return cachedAvatar;
|
||||
}
|
||||
|
@ -121,19 +129,19 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
[initials appendString:@"#"];
|
||||
}
|
||||
|
||||
CGFloat fontSize = (CGFloat)self.diameter / 2.8f;
|
||||
|
||||
UIImage *image = [[JSQMessagesAvatarImageFactory avatarImageWithUserInitials:initials
|
||||
backgroundColor:self.color
|
||||
textColor:[UIColor whiteColor]
|
||||
font:[UIFont ows_boldFontWithSize:fontSize]
|
||||
diameter:self.diameter] avatarImage];
|
||||
UIColor *color = [UIColor ows_conversationColorForColorName:self.colorName isShaded:Theme.isDarkThemeEnabled];
|
||||
OWSAssertDebug(color);
|
||||
|
||||
[self.contactsManager.avatarCache setImage:image forKey:self.signalId diameter:self.diameter];
|
||||
UIImage *_Nullable image =
|
||||
[OWSAvatarBuilder avatarImageWithInitials:initials backgroundColor:color diameter:self.diameter];
|
||||
if (!image) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
[self.contactsManager.avatarCache setImage:image forKey:self.cacheKey diameter:self.diameter];
|
||||
return image;
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
|
@ -32,7 +32,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
return self.thread.groupModel.groupImage;
|
||||
}
|
||||
|
||||
- (UIImage *)buildDefaultImage
|
||||
- (nullable UIImage *)buildDefaultImage
|
||||
{
|
||||
return self.class.defaultGroupImage;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue