conversation colors

// FREEBIE
This commit is contained in:
Michael Kirk 2018-06-28 11:28:14 -06:00
parent 7d1cf700be
commit 16df4f589e
25 changed files with 492 additions and 93 deletions

View File

@ -411,6 +411,7 @@
45FBC5C81DF8575700E9B410 /* CallKitCallManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45FBC59A1DF8575700E9B410 /* CallKitCallManager.swift */; };
45FBC5D11DF8592E00E9B410 /* SignalCall.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45FBC5D01DF8592E00E9B410 /* SignalCall.swift */; };
4AC4EA13C8A444455DAB351F /* Pods_SignalMessaging.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 264242150E87D10A357DB07B /* Pods_SignalMessaging.framework */; };
4C13C9F620E57BA30089A98B /* ColorPickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C13C9F520E57BA30089A98B /* ColorPickerViewController.swift */; };
4C20B2B720CA0034001BAC90 /* ThreadViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4542DF51208B82E9007B4E76 /* ThreadViewModel.swift */; };
4C20B2B920CA10DE001BAC90 /* ConversationSearchViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C20B2B820CA10DE001BAC90 /* ConversationSearchViewController.swift */; };
70377AAB1918450100CAF501 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 70377AAA1918450100CAF501 /* MobileCoreServices.framework */; };
@ -1066,6 +1067,7 @@
45FBC59A1DF8575700E9B410 /* CallKitCallManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallKitCallManager.swift; sourceTree = "<group>"; };
45FBC5D01DF8592E00E9B410 /* SignalCall.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SignalCall.swift; sourceTree = "<group>"; };
45FDA43420A4D22700396358 /* OWSNavigationBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OWSNavigationBar.swift; sourceTree = "<group>"; };
4C13C9F520E57BA30089A98B /* ColorPickerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorPickerViewController.swift; sourceTree = "<group>"; };
4C20B2B820CA10DE001BAC90 /* ConversationSearchViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationSearchViewController.swift; sourceTree = "<group>"; };
69349DE607F5BA6036C9AC60 /* Pods-SignalShareExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SignalShareExtension.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SignalShareExtension/Pods-SignalShareExtension.debug.xcconfig"; sourceTree = "<group>"; };
70377AAA1918450100CAF501 /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; };
@ -1690,6 +1692,7 @@
340FC897204DAC8D007AEB0F /* ThreadSettings */,
34D1F0BE1F8EC1760066283D /* Utils */,
452B998F20A34B6B006F2F9E /* AddContactShareToExistingContactViewController.swift */,
4C13C9F520E57BA30089A98B /* ColorPickerViewController.swift */,
);
path = ViewControllers;
sourceTree = "<group>";
@ -3272,6 +3275,7 @@
348BB25D20A0C5530047AEC2 /* ContactShareViewHelper.swift in Sources */,
34B3F8801E8DF1700035BE1A /* InviteFlow.swift in Sources */,
457C87B82032645C008D52D6 /* DebugUINotifications.swift in Sources */,
4C13C9F620E57BA30089A98B /* ColorPickerViewController.swift in Sources */,
340FC8D0205BF2FA007AEB0F /* OWSBackupIO.m in Sources */,
458E38371D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.m in Sources */,
4517642B1DE939FD00EDB8B9 /* ContactCell.swift in Sources */,

View File

@ -0,0 +1,145 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
import Foundation
let colorSwatchHeight: CGFloat = 60
class ColorView: UIView {
let color: UIColor
let swatchView: UIView
required init(color: UIColor) {
self.color = color
self.swatchView = UIView()
super.init(frame: .zero)
swatchView.backgroundColor = color
self.swatchView.layer.cornerRadius = colorSwatchHeight / 2
self.addSubview(swatchView)
swatchView.autoVCenterInSuperview()
swatchView.autoSetDimension(.height, toSize: colorSwatchHeight)
swatchView.autoPinEdge(toSuperviewMargin: .top, relation: .greaterThanOrEqual)
swatchView.autoPinEdge(toSuperviewMargin: .bottom, relation: .greaterThanOrEqual)
swatchView.autoPinLeadingToSuperviewMargin()
swatchView.autoPinTrailingToSuperviewMargin()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
@objc
protocol ColorPickerDelegate: class {
func colorPickerDidCancel(_ colorPicker: ColorPickerViewController)
func colorPicker(_ colorPicker: ColorPickerViewController, didPickColorName colorName: String)
}
@objc
class ColorPickerViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {
private let pickerView: UIPickerView
private let thread: TSThread
private let colors: [UIColor]
@objc public weak var delegate: ColorPickerDelegate?
@objc
required init(thread: TSThread) {
self.thread = thread
self.pickerView = UIPickerView()
self.colors = UIColor.ows_conversationColors
super.init(nibName: nil, bundle: nil)
self.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(didTapCancel))
self.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .save, target: self, action: #selector(didTapSave))
pickerView.dataSource = self
pickerView.delegate = self
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func loadView() {
self.view = UIView()
view.backgroundColor = .white
view.addSubview(pickerView)
pickerView.autoVCenterInSuperview()
pickerView.autoPinLeadingToSuperviewMargin()
pickerView.autoPinTrailingToSuperviewMargin()
}
override func viewDidLoad() {
super.viewDidLoad()
if let colorName = thread.conversationColorName,
let currentColor = UIColor.ows_conversationColor(colorName: colorName),
let index = colors.index(of: currentColor) {
pickerView.selectRow(index, inComponent: 0, animated: false)
}
}
// MARK: UIPickerViewDataSource
public func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
public func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return self.colors.count
}
// MARK: UIPickerViewDelegate
public func pickerView(_ pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat {
let vMargin: CGFloat = 2
return colorSwatchHeight + vMargin * 2
}
public func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
guard let color = colors[safe: row] else {
owsFail("\(logTag) in \(#function) color was unexpectedly nil")
return ColorView(color: .white)
}
return ColorView(color: color)
}
// MARK: Actions
var currentColor: UIColor {
let index = pickerView.selectedRow(inComponent: 0)
guard let color = self.colors[safe: index] else {
owsFail("\(self.logTag) in \(#function) index was unexpectedly nil")
return UIColor.white
}
return color
}
@objc
public func didTapSave() {
guard let colorName = UIColor.ows_conversationColorName(color: self.currentColor) else {
owsFail("\(self.logTag) in \(#function) colorName was unexpectedly nil")
self.delegate?.colorPickerDidCancel(self)
return
}
self.delegate?.colorPicker(self, didPickColorName: colorName)
}
@objc
public func didTapCancel() {
self.delegate?.colorPickerDidCancel(self)
}
}

View File

@ -277,6 +277,7 @@ NS_ASSUME_NONNULL_BEGIN
OWSQuotedMessageView *quotedMessageView =
[OWSQuotedMessageView quotedMessageViewForConversation:self.viewItem.quotedReply
displayableQuotedText:displayableQuotedText
conversationStyle:self.conversationStyle
isOutgoing:isOutgoing];
quotedMessageView.delegate = self;
@ -494,7 +495,7 @@ NS_ASSUME_NONNULL_BEGIN
OWSAssert([self.viewItem.interaction isKindOfClass:[TSMessage class]]);
TSMessage *message = (TSMessage *)self.viewItem.interaction;
return [ConversationStyle bubbleColorWithMessage:message];
return [self.conversationStyle bubbleColorWithMessage:message];
}
- (BOOL)hasBodyMediaWithThumbnail
@ -1084,6 +1085,7 @@ NS_ASSUME_NONNULL_BEGIN
OWSQuotedMessageView *quotedMessageView =
[OWSQuotedMessageView quotedMessageViewForConversation:self.viewItem.quotedReply
displayableQuotedText:displayableQuotedText
conversationStyle:self.conversationStyle
isOutgoing:isOutgoing];
CGSize result = [quotedMessageView sizeForMaxWidth:self.conversationStyle.maxMessageWidth];
return [NSValue valueWithCGSize:CGSizeCeil(result)];
@ -1214,7 +1216,7 @@ NS_ASSUME_NONNULL_BEGIN
OWSAssert([self.viewItem.interaction isKindOfClass:[TSMessage class]]);
TSMessage *message = (TSMessage *)self.viewItem.interaction;
return [ConversationStyle bubbleTextColorWithMessage:message];
return [self.conversationStyle bubbleTextColorWithMessage:message];
}
- (BOOL)isMediaBeingSent

View File

@ -296,6 +296,7 @@ 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];

View File

@ -4,6 +4,7 @@
NS_ASSUME_NONNULL_BEGIN
@class ConversationStyle;
@class DisplayableText;
@class OWSBubbleShapeView;
@class OWSQuotedReplyModel;
@ -33,10 +34,12 @@ NS_ASSUME_NONNULL_BEGIN
// Factory method for "message bubble" views.
+ (OWSQuotedMessageView *)quotedMessageViewForConversation:(OWSQuotedReplyModel *)quotedMessage
displayableQuotedText:(nullable DisplayableText *)displayableQuotedText
conversationStyle:(ConversationStyle *)conversationStyle
isOutgoing:(BOOL)isOutgoing;
// Factory method for "message compose" views.
+ (OWSQuotedMessageView *)quotedMessageViewForPreview:(OWSQuotedReplyModel *)quotedMessage;
+ (OWSQuotedMessageView *)quotedMessageViewForPreview:(OWSQuotedReplyModel *)quotedMessage
conversationStyle:(ConversationStyle *)conversationStyle;
@end

View File

@ -21,6 +21,7 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, readonly) OWSQuotedReplyModel *quotedMessage;
@property (nonatomic, nullable, readonly) DisplayableText *displayableQuotedText;
@property (nonatomic, readonly) ConversationStyle *conversationStyle;
@property (nonatomic, nullable) OWSBubbleShapeView *boundsStrokeView;
@property (nonatomic, readonly) BOOL isForPreview;
@ -37,17 +38,20 @@ NS_ASSUME_NONNULL_BEGIN
+ (OWSQuotedMessageView *)quotedMessageViewForConversation:(OWSQuotedReplyModel *)quotedMessage
displayableQuotedText:(nullable DisplayableText *)displayableQuotedText
conversationStyle:(ConversationStyle *)conversationStyle
isOutgoing:(BOOL)isOutgoing
{
OWSAssert(quotedMessage);
return [[OWSQuotedMessageView alloc] initWithQuotedMessage:quotedMessage
displayableQuotedText:displayableQuotedText
conversationStyle:conversationStyle
isForPreview:NO
isOutgoing:isOutgoing];
}
+ (OWSQuotedMessageView *)quotedMessageViewForPreview:(OWSQuotedReplyModel *)quotedMessage
conversationStyle:(ConversationStyle *)conversationStyle
{
OWSAssert(quotedMessage);
@ -58,6 +62,7 @@ NS_ASSUME_NONNULL_BEGIN
OWSQuotedMessageView *instance = [[OWSQuotedMessageView alloc] initWithQuotedMessage:quotedMessage
displayableQuotedText:displayableQuotedText
conversationStyle:conversationStyle
isForPreview:YES
isOutgoing:YES];
[instance createContents];
@ -66,6 +71,7 @@ NS_ASSUME_NONNULL_BEGIN
- (instancetype)initWithQuotedMessage:(OWSQuotedReplyModel *)quotedMessage
displayableQuotedText:(nullable DisplayableText *)displayableQuotedText
conversationStyle:(ConversationStyle *)conversationStyle
isForPreview:(BOOL)isForPreview
isOutgoing:(BOOL)isOutgoing
{
@ -80,6 +86,7 @@ NS_ASSUME_NONNULL_BEGIN
_quotedMessage = quotedMessage;
_displayableQuotedText = displayableQuotedText;
_isForPreview = isForPreview;
_conversationStyle = conversationStyle;
_isOutgoing = isOutgoing;
_quotedAuthorLabel = [UILabel new];
@ -104,7 +111,7 @@ NS_ASSUME_NONNULL_BEGIN
- (UIColor *)highlightColor
{
BOOL isQuotingSelf = [NSObject isNullableObject:self.quotedMessage.authorId equalTo:TSAccountManager.localNumber];
return (isQuotingSelf ? ConversationStyle.bubbleColorOutgoingSent : [UIColor colorWithRGBHex:0xB5B5B5]);
return (isQuotingSelf ? self.conversationStyle.bubbleColorOutgoingSent : [UIColor colorWithRGBHex:0xB5B5B5]);
}
#pragma mark -
@ -120,7 +127,7 @@ NS_ASSUME_NONNULL_BEGIN
self.clipsToBounds = YES;
self.boundsStrokeView = [OWSBubbleShapeView new];
self.boundsStrokeView.strokeColor = ConversationStyle.bubbleColorIncoming;
self.boundsStrokeView.strokeColor = [self.conversationStyle primaryColor];
self.boundsStrokeView.strokeThickness = 1.f;
[self addSubview:self.boundsStrokeView];
[self.boundsStrokeView autoPinToSuperviewEdges];

View File

@ -53,7 +53,7 @@ public class ConversationHeaderView: UIStackView {
private let titleLabel: UILabel
private let subtitleLabel: UILabel
private let avatarView: AvatarImageView
private let avatarView: ConversationAvatarImageView
@objc
public required init(thread: TSThread, contactsManager: OWSContactsManager) {
@ -115,6 +115,11 @@ public class ConversationHeaderView: UIStackView {
return UILayoutFittingExpandedSize
}
@objc
public func updateAvatar() {
self.avatarView.updateImage()
}
// MARK: Delegate Methods
@objc func didTapView(tapGesture: UITapGestureRecognizer) {

View File

@ -4,6 +4,7 @@
NS_ASSUME_NONNULL_BEGIN
@class ConversationStyle;
@class OWSQuotedReplyModel;
@class SignalAttachment;
@ -33,6 +34,8 @@ NS_ASSUME_NONNULL_BEGIN
@interface ConversationInputToolbar : UIView
- (instancetype)initWithConversationStyle:(ConversationStyle *)conversationStyle NS_DESIGNATED_INITIALIZER;
@property (nonatomic, weak) id<ConversationInputToolbarDelegate> inputToolbarDelegate;
- (void)beginEditingTextMessage;

View File

@ -27,6 +27,8 @@ static const CGFloat ConversationInputToolbarBorderViewHeight = 0.5;
ConversationTextViewToolbarDelegate,
QuotedReplyPreviewDelegate>
@property (nonatomic, readonly) ConversationStyle *conversationStyle;
@property (nonatomic, readonly) UIView *composeContainer;
@property (nonatomic, readonly) ConversationInputTextView *inputTextView;
@property (nonatomic, readonly) UIStackView *contentStackView;
@ -66,12 +68,16 @@ static const CGFloat ConversationInputToolbarBorderViewHeight = 0.5;
@implementation ConversationInputToolbar
- (instancetype)init
- (instancetype)initWithConversationStyle:(ConversationStyle *)conversationStyle
{
self = [super init];
_conversationStyle = conversationStyle;
if (self) {
[self createContents];
}
return self;
}
@ -268,7 +274,7 @@ static const CGFloat ConversationInputToolbarBorderViewHeight = 0.5;
return;
}
self.quotedMessagePreview = [[QuotedReplyPreview alloc] initWithQuotedReply:quotedReply];
self.quotedMessagePreview = [[QuotedReplyPreview alloc] initWithQuotedReply:quotedReply conversationStyle:self.conversationStyle];
self.quotedMessagePreview.delegate = self;
// TODO animate

View File

@ -564,7 +564,7 @@ typedef enum : NSUInteger {
[self.collectionView applyScrollViewInsetsFix];
_inputToolbar = [ConversationInputToolbar new];
_inputToolbar = [[ConversationInputToolbar alloc] initWithConversationStyle:self.conversationStyle];
self.inputToolbar.inputToolbarDelegate = self;
self.inputToolbar.inputTextViewDelegate = self;
[self.collectionView autoPinToBottomLayoutGuideOfViewController:self withInset:0];
@ -4326,6 +4326,13 @@ typedef enum : NSUInteger {
}];
}
- (void)conversationColorWasUpdated
{
[self.conversationStyle updateProperties];
[self.headerView updateAvatar];
[self.collectionView reloadData];
}
- (void)groupWasUpdated:(TSGroupModel *)groupModel
{
OWSAssert(groupModel);

View File

@ -1297,6 +1297,8 @@ NS_ASSUME_NONNULL_BEGIN
messageState:TSOutgoingMessageStateSent
text:@"⚠️ Outgoing Reserved Color Png ⚠️"]];
}
ConversationStyle *conversationStyle = [[ConversationStyle alloc] initWithThread:thread];
[actions addObjectsFromArray:@[
[self fakeOutgoingPngAction:thread
actionLabel:@"Fake Outgoing White Png"
@ -1326,7 +1328,7 @@ NS_ASSUME_NONNULL_BEGIN
[self fakeOutgoingPngAction:thread
actionLabel:@"Fake Outgoing 'Outgoing Unsent' Png"
imageSize:CGSizeMake(200.f, 200.f)
backgroundColor:[ConversationStyle bubbleColorOutgoingUnsent]
backgroundColor:[conversationStyle bubbleColorOutgoingUnsent]
textColor:[UIColor whiteColor]
imageLabel:@"W"
messageState:TSOutgoingMessageStateFailed
@ -1334,7 +1336,7 @@ NS_ASSUME_NONNULL_BEGIN
[self fakeOutgoingPngAction:thread
actionLabel:@"Fake Outgoing 'Outgoing Unsent' Png"
imageSize:CGSizeMake(200.f, 200.f)
backgroundColor:[ConversationStyle bubbleColorOutgoingUnsent]
backgroundColor:[conversationStyle bubbleColorOutgoingUnsent]
textColor:[UIColor whiteColor]
imageLabel:@"W"
messageState:TSOutgoingMessageStateSending
@ -1342,7 +1344,7 @@ NS_ASSUME_NONNULL_BEGIN
[self fakeOutgoingPngAction:thread
actionLabel:@"Fake Outgoing 'Outgoing Unsent' Png"
imageSize:CGSizeMake(200.f, 200.f)
backgroundColor:[ConversationStyle bubbleColorOutgoingUnsent]
backgroundColor:[conversationStyle bubbleColorOutgoingUnsent]
textColor:[UIColor whiteColor]
imageLabel:@"W"
messageState:TSOutgoingMessageStateSent
@ -1351,7 +1353,7 @@ NS_ASSUME_NONNULL_BEGIN
[self fakeOutgoingPngAction:thread
actionLabel:@"Fake Outgoing 'Outgoing Sending' Png"
imageSize:CGSizeMake(200.f, 200.f)
backgroundColor:[ConversationStyle bubbleColorOutgoingSending]
backgroundColor:[conversationStyle bubbleColorOutgoingSending]
textColor:[UIColor whiteColor]
imageLabel:@"W"
messageState:TSOutgoingMessageStateFailed
@ -1359,7 +1361,7 @@ NS_ASSUME_NONNULL_BEGIN
[self fakeOutgoingPngAction:thread
actionLabel:@"Fake Outgoing 'Outgoing Sending' Png"
imageSize:CGSizeMake(200.f, 200.f)
backgroundColor:[ConversationStyle bubbleColorOutgoingSending]
backgroundColor:[conversationStyle bubbleColorOutgoingSending]
textColor:[UIColor whiteColor]
imageLabel:@"W"
messageState:TSOutgoingMessageStateSending
@ -1367,7 +1369,7 @@ NS_ASSUME_NONNULL_BEGIN
[self fakeOutgoingPngAction:thread
actionLabel:@"Fake Outgoing 'Outgoing Sending' Png"
imageSize:CGSizeMake(200.f, 200.f)
backgroundColor:[ConversationStyle bubbleColorOutgoingSending]
backgroundColor:[conversationStyle bubbleColorOutgoingSending]
textColor:[UIColor whiteColor]
imageLabel:@"W"
messageState:TSOutgoingMessageStateSent
@ -1376,7 +1378,7 @@ NS_ASSUME_NONNULL_BEGIN
[self fakeOutgoingPngAction:thread
actionLabel:@"Fake Outgoing 'Outgoing Sent' Png"
imageSize:CGSizeMake(200.f, 200.f)
backgroundColor:[ConversationStyle bubbleColorOutgoingSent]
backgroundColor:[conversationStyle bubbleColorOutgoingSent]
textColor:[UIColor whiteColor]
imageLabel:@"W"
messageState:TSOutgoingMessageStateFailed
@ -1384,7 +1386,7 @@ NS_ASSUME_NONNULL_BEGIN
[self fakeOutgoingPngAction:thread
actionLabel:@"Fake Outgoing 'Outgoing Sent' Png"
imageSize:CGSizeMake(200.f, 200.f)
backgroundColor:[ConversationStyle bubbleColorOutgoingSent]
backgroundColor:[conversationStyle bubbleColorOutgoingSent]
textColor:[UIColor whiteColor]
imageLabel:@"W"
messageState:TSOutgoingMessageStateSending
@ -1392,7 +1394,7 @@ NS_ASSUME_NONNULL_BEGIN
[self fakeOutgoingPngAction:thread
actionLabel:@"Fake Outgoing 'Outgoing Sent' Png"
imageSize:CGSizeMake(200.f, 200.f)
backgroundColor:[ConversationStyle bubbleColorOutgoingSent]
backgroundColor:[conversationStyle bubbleColorOutgoingSent]
textColor:[UIColor whiteColor]
imageLabel:@"W"
messageState:TSOutgoingMessageStateSent
@ -1560,7 +1562,7 @@ NS_ASSUME_NONNULL_BEGIN
[self fakeIncomingPngAction:thread
actionLabel:@"Fake Incoming 'Incoming' Png"
imageSize:CGSizeMake(200.f, 200.f)
backgroundColor:[ConversationStyle bubbleColorIncoming]
backgroundColor:[conversationStyle primaryColor]
textColor:[UIColor whiteColor]
imageLabel:@"W"
isAttachmentDownloaded:YES
@ -1568,7 +1570,7 @@ NS_ASSUME_NONNULL_BEGIN
[self fakeIncomingPngAction:thread
actionLabel:@"Fake Incoming 'Incoming' Png"
imageSize:CGSizeMake(200.f, 200.f)
backgroundColor:[ConversationStyle bubbleColorIncoming]
backgroundColor:[conversationStyle primaryColor]
textColor:[UIColor whiteColor]
imageLabel:@"W"
isAttachmentDownloaded:NO

View File

@ -37,10 +37,13 @@
NS_ASSUME_NONNULL_BEGIN
@interface OWSConversationSettingsViewController () <ContactEditingDelegate, ContactsViewHelperDelegate>
@interface OWSConversationSettingsViewController () <ContactEditingDelegate,
ContactsViewHelperDelegate,
ColorPickerDelegate>
@property (nonatomic) TSThread *thread;
@property (nonatomic) YapDatabaseConnection *uiDatabaseConnection;
@property (nonatomic, readonly) YapDatabaseConnection *editingDatabaseConnection;
@property (nonatomic) NSArray<NSNumber *> *disappearingMessagesDurations;
@property (nonatomic) OWSDisappearingMessagesConfiguration *disappearingMessagesConfiguration;
@ -123,6 +126,11 @@ NS_ASSUME_NONNULL_BEGIN
object:nil];
}
- (YapDatabaseConnection *)editingDatabaseConnection
{
return [OWSPrimaryStorage sharedManager].dbReadWriteConnection;
}
- (NSString *)threadName
{
NSString *threadName = self.thread.name;
@ -271,6 +279,19 @@ NS_ASSUME_NONNULL_BEGIN
[weakSelf showMediaGallery];
}]];
[mainSection addItem:[OWSTableItem
itemWithCustomCellBlock:^{
NSString *colorName = self.thread.conversationColorName;
UIColor *currentColor = [UIColor ows_conversationColorForColorName:colorName];
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];
}
actionBlock:^{
[weakSelf showColorPicker];
}]];
if ([self.thread isKindOfClass:[TSContactThread class]] && self.contactsManager.supportsContactEditing
&& !self.hasExistingContact) {
[mainSection addItem:[OWSTableItem itemWithCustomCellBlock:^{
@ -623,6 +644,39 @@ NS_ASSUME_NONNULL_BEGIN
return 12.f;
}
- (UITableViewCell *)disclosureCellWithName:(NSString *)name iconColor:(UIColor *)iconColor
{
OWSAssert(name.length > 0);
UITableViewCell *cell = [UITableViewCell new];
cell.preservesSuperviewLayoutMargins = YES;
cell.contentView.preservesSuperviewLayoutMargins = YES;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
UIView *swatchView = [NeverClearView new];
const CGFloat kSwatchWidth = 24;
[swatchView autoSetDimension:ALDimensionWidth toSize:kSwatchWidth];
[swatchView autoSetDimension:ALDimensionHeight toSize:kSwatchWidth];
swatchView.layer.cornerRadius = kSwatchWidth / 2;
swatchView.backgroundColor = iconColor;
[cell.contentView addSubview:swatchView];
[swatchView autoVCenterInSuperview];
[swatchView autoPinLeadingToSuperviewMargin];
UILabel *rowLabel = [UILabel new];
rowLabel.text = name;
rowLabel.textColor = [UIColor blackColor];
rowLabel.font = [UIFont ows_regularFontWithSize:17.f];
rowLabel.lineBreakMode = NSLineBreakByTruncatingTail;
[cell.contentView addSubview:rowLabel];
[rowLabel autoVCenterInSuperview];
[rowLabel autoPinLeadingToTrailingEdgeOfView:swatchView offset:self.iconSpacing];
[rowLabel autoPinTrailingToSuperviewMargin];
return cell;
}
- (UITableViewCell *)cellWithName:(NSString *)name iconName:(NSString *)iconName
{
OWSAssert(name.length > 0);
@ -1158,7 +1212,10 @@ NS_ASSUME_NONNULL_BEGIN
- (void)setThreadMutedUntilDate:(nullable NSDate *)value
{
[self.thread updateWithMutedUntilDate:value];
[self.editingDatabaseConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction * _Nonnull transaction) {
[self.thread updateWithMutedUntilDate:value transaction:transaction];
}];
[self updateTableContents];
}
@ -1200,6 +1257,36 @@ NS_ASSUME_NONNULL_BEGIN
}
}
#pragma mark - ColorPickerDelegate
- (void)showColorPicker
{
ColorPickerViewController *pickerController = [[ColorPickerViewController alloc] initWithThread:self.thread];
pickerController.delegate = self;
OWSNavigationController *modal = [[OWSNavigationController alloc] initWithRootViewController:pickerController];
[self presentViewController:modal animated:YES completion:nil];
}
- (void)colorPicker:(ColorPickerViewController *)colorPicker didPickColorName:(NSString *)colorName
{
DDLogDebug(@"%@ in %s picked color: %@", self.logTag, __PRETTY_FUNCTION__, colorName);
[self.editingDatabaseConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
[self.thread updateConversationColorName:colorName transaction:transaction];
[self.contactsManager.avatarCache removeAllImages];
[self updateTableContents];
[self.conversationSettingsViewDelegate conversationColorWasUpdated];
[self dismissViewControllerAnimated:YES completion:nil];
}];
}
- (void)colorPickerDidCancel:(ColorPickerViewController *)colorPicker
{
[self dismissViewControllerAnimated:YES completion:nil];
}
@end
NS_ASSUME_NONNULL_END

View File

@ -8,6 +8,7 @@ NS_ASSUME_NONNULL_BEGIN
@protocol OWSConversationSettingsViewDelegate <NSObject>
- (void)conversationColorWasUpdated;
- (void)groupWasUpdated:(TSGroupModel *)groupModel;
- (void)popAllConversationSettingsViews;

View File

@ -15,6 +15,7 @@ class QuotedReplyPreview: UIView {
public weak var delegate: QuotedReplyPreviewDelegate?
private let quotedReply: OWSQuotedReplyModel
private let conversationStyle: ConversationStyle
private var quotedMessageView: OWSQuotedMessageView?
private var heightConstraint: NSLayoutConstraint!
@ -24,8 +25,9 @@ class QuotedReplyPreview: UIView {
}
@objc
init(quotedReply: OWSQuotedReplyModel) {
init(quotedReply: OWSQuotedReplyModel, conversationStyle: ConversationStyle) {
self.quotedReply = quotedReply
self.conversationStyle = conversationStyle
super.init(frame: .zero)
@ -42,7 +44,7 @@ class QuotedReplyPreview: UIView {
// We instantiate quotedMessageView late to ensure that it is updated
// every time contentSizeCategoryDidChange (i.e. when dynamic type
// sizes changes).
let quotedMessageView = OWSQuotedMessageView(forPreview: quotedReply)
let quotedMessageView = OWSQuotedMessageView(forPreview: quotedReply, conversationStyle: conversationStyle)
self.quotedMessageView = quotedMessageView
quotedMessageView.backgroundColor = .clear

View File

@ -511,6 +511,9 @@
/* Navbar title when viewing settings for a 1-on-1 thread */
"CONVERSATION_SETTINGS_CONTACT_INFO_TITLE" = "Contact Info";
/* Indicates that user's profile has been shared with a group. */
"CONVERSATION_SETTINGS_CONVERSATION_COLOR" = "Color";
/* Navbar title when viewing settings for a group thread */
"CONVERSATION_SETTINGS_GROUP_INFO_TITLE" = "Group Info";

View File

@ -150,7 +150,7 @@ public class ConversationAvatarImageView: AvatarImageView {
self.updateImage()
}
func updateImage() {
public func updateImage() {
Logger.debug("\(self.logTag) in \(#function) updateImage")
self.image = OWSAvatarBuilder.buildImage(thread: thread, diameter: diameter, contactsManager: contactsManager)

View File

@ -29,6 +29,7 @@ const CGFloat kContactCellAvatarTextMargin = 12;
@property (nonatomic) UIView *accessoryViewContainer;
@property (nonatomic) OWSContactsManager *contactsManager;
@property (nonatomic) TSThread *thread;
@property (nonatomic) NSString *recipientId;
@end
@ -139,7 +140,8 @@ const CGFloat kContactCellAvatarTextMargin = 12;
- (void)configureWithThread:(TSThread *)thread contactsManager:(OWSContactsManager *)contactsManager
{
OWSAssert(thread);
self.thread = thread;
// Update fonts to reflect changes to dynamic type.
[self configureFonts];
@ -194,7 +196,11 @@ const CGFloat kContactCellAvatarTextMargin = 12;
return;
}
NSString *colorName = self.thread.conversationColorName;
UIColor *color = [UIColor ows_conversationColorForColorName:colorName];
self.avatarView.image = [[[OWSContactAvatarBuilder alloc] initWithSignalId:recipientId
color:color
diameter:kContactCellAvatarSize
contactsManager:contactsManager] build];
}
@ -230,6 +236,7 @@ const CGFloat kContactCellAvatarTextMargin = 12;
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
self.thread = nil;
self.accessoryMessage = nil;
self.nameLabel.text = nil;
self.subtitleLabel.text = nil;

View File

@ -24,9 +24,17 @@ NS_ASSUME_NONNULL_BEGIN
@property (class, readonly, nonatomic) UIColor *ows_toolbarBackgroundColor;
@property (class, readonly, nonatomic) UIColor *ows_messageBubbleLightGrayColor;
+ (UIColor *)backgroundColorForContact:(NSString *)contactIdentifier;
+ (UIColor *)colorWithRGBHex:(unsigned long)value;
#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:));
@property (class, readonly, nonatomic) NSArray<NSString *> *ows_conversationColorNames;
@property (class, readonly, nonatomic) NSArray<UIColor *> *ows_conversationColors;
- (UIColor *)blendWithColor:(UIColor *)otherColor alpha:(CGFloat)alpha;
#pragma mark -

View File

@ -2,8 +2,8 @@
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
#import "OWSMath.h"
#import "UIColor+OWS.h"
#import "OWSMath.h"
#import <SignalServiceKit/Cryptography.h>
NS_ASSUME_NONNULL_BEGIN
@ -98,40 +98,6 @@ NS_ASSUME_NONNULL_BEGIN
return [UIColor colorWithHue:240.0f / 360.0f saturation:0.02f brightness:0.92f alpha:1.0f];
}
+ (UIColor *)backgroundColorForContact:(NSString *)contactIdentifier
{
NSArray *colors = @[
[UIColor colorWithRed:204.f / 255.f green:148.f / 255.f blue:102.f / 255.f alpha:1.f],
[UIColor colorWithRed:187.f / 255.f green:104.f / 255.f blue:62.f / 255.f alpha:1.f],
[UIColor colorWithRed:145.f / 255.f green:78.f / 255.f blue:48.f / 255.f alpha:1.f],
[UIColor colorWithRed:122.f / 255.f green:63.f / 255.f blue:41.f / 255.f alpha:1.f],
[UIColor colorWithRed:80.f / 255.f green:46.f / 255.f blue:27.f / 255.f alpha:1.f],
[UIColor colorWithRed:57.f / 255.f green:45.f / 255.f blue:19.f / 255.f alpha:1.f],
[UIColor colorWithRed:37.f / 255.f green:38.f / 255.f blue:13.f / 255.f alpha:1.f],
[UIColor colorWithRed:23.f / 255.f green:31.f / 255.f blue:10.f / 255.f alpha:1.f],
[UIColor colorWithRed:6.f / 255.f green:19.f / 255.f blue:10.f / 255.f alpha:1.f],
[UIColor colorWithRed:13.f / 255.f green:4.f / 255.f blue:16.f / 255.f alpha:1.f],
[UIColor colorWithRed:27.f / 255.f green:12.f / 255.f blue:44.f / 255.f alpha:1.f],
[UIColor colorWithRed:18.f / 255.f green:17.f / 255.f blue:64.f / 255.f alpha:1.f],
[UIColor colorWithRed:20.f / 255.f green:42.f / 255.f blue:77.f / 255.f alpha:1.f],
[UIColor colorWithRed:18.f / 255.f green:55.f / 255.f blue:68.f / 255.f alpha:1.f],
[UIColor colorWithRed:18.f / 255.f green:68.f / 255.f blue:61.f / 255.f alpha:1.f],
[UIColor colorWithRed:19.f / 255.f green:73.f / 255.f blue:26.f / 255.f alpha:1.f],
[UIColor colorWithRed:13.f / 255.f green:48.f / 255.f blue:15.f / 255.f alpha:1.f],
[UIColor colorWithRed:44.f / 255.f green:165.f / 255.f blue:137.f / 255.f alpha:1.f],
[UIColor colorWithRed:137.f / 255.f green:181.f / 255.f blue:48.f / 255.f alpha:1.f],
[UIColor colorWithRed:208.f / 255.f green:204.f / 255.f blue:78.f / 255.f alpha:1.f],
[UIColor colorWithRed:227.f / 255.f green:162.f / 255.f blue:150.f / 255.f alpha:1.f]
];
NSData *contactData = [contactIdentifier dataUsingEncoding:NSUTF8StringEncoding];
NSUInteger hashingLength = 8;
unsigned long long choose;
NSData *hashData = [Cryptography computeSHA256Digest:contactData truncatedToBytes:hashingLength];
[hashData getBytes:&choose length:hashingLength];
return [colors objectAtIndex:(choose % [colors count])];
}
+ (UIColor *)colorWithRGBHex:(unsigned long)value
{
CGFloat red = ((value >> 16) & 0xff) / 255.f;
@ -304,6 +270,50 @@ NS_ASSUME_NONNULL_BEGIN
return [UIColor colorWithRGBHex:0x757575];
}
+ (NSDictionary<NSString *, UIColor *> *)ows_conversationColorMap
{
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;
}
+ (NSArray<NSString *> *)ows_conversationColorNames
{
return self.ows_conversationColorMap.allKeys;
}
+ (NSArray<UIColor *> *)ows_conversationColors
{
return self.ows_conversationColorMap.allValues;
}
+ (nullable UIColor *)ows_conversationColorForColorName:(NSString *)colorName
{
OWSAssert(colorName.length > 0);
return [self.ows_conversationColorMap objectForKey:colorName];
}
+ (nullable NSString *)ows_conversationColorNameForColor:(UIColor *)color
{
return [self.ows_conversationColorMap allKeysForObject:color].firstObject;
}
@end
NS_ASSUME_NONNULL_END

View File

@ -55,6 +55,7 @@ public class ConversationStyle: NSObject {
self.thread = thread
self.isRTL = CurrentAppContext().isRTL
self.primaryColor = ConversationStyle.primaryColor(thread: thread)
super.init()
@ -78,7 +79,8 @@ public class ConversationStyle: NSObject {
// MARK: -
private func updateProperties() {
@objc
public func updateProperties() {
if thread.isGroupThread() {
gutterLeading = 40
gutterTrailing = 20
@ -106,37 +108,52 @@ public class ConversationStyle: NSObject {
textInsetHorizontal = 12
lastTextLineAxis = CGFloat(round(12 + messageTextFont.capHeight * 0.5))
self.primaryColor = ConversationStyle.primaryColor(thread: thread)
}
// MARK: Colors
// TODO: Remove this! Incoming bubble colors are now dynamic.
@objc
public static let bubbleColorIncoming = UIColor.ows_messageBubbleLightGray
private class func primaryColor(thread: TSThread) -> UIColor {
guard let colorName = thread.conversationColorName else {
return self.defaultBubbleColorIncoming
}
guard let color = UIColor.ows_conversationColor(colorName: colorName) else {
return self.defaultBubbleColorIncoming
}
return color
}
private static let defaultBubbleColorIncoming = UIColor.ows_messageBubbleLightGray
// TODO:
@objc
public static let bubbleColorOutgoingUnsent = UIColor.ows_red
public let bubbleColorOutgoingUnsent = UIColor.ows_red
// TODO:
@objc
public static let bubbleColorOutgoingSending = UIColor.ows_light35
public let bubbleColorOutgoingSending = UIColor.ows_light35
@objc
public static let bubbleColorOutgoingSent = UIColor.ows_light10
public let bubbleColorOutgoingSent = UIColor.ows_light10
@objc
public static func bubbleColor(message: TSMessage) -> UIColor {
public var primaryColor: UIColor
@objc
public func bubbleColor(message: TSMessage) -> UIColor {
if message is TSIncomingMessage {
return ConversationStyle.bubbleColorIncoming
return primaryColor
} else if let outgoingMessage = message as? TSOutgoingMessage {
switch outgoingMessage.messageState {
case .failed:
return ConversationStyle.bubbleColorOutgoingUnsent
return self.bubbleColorOutgoingUnsent
case .sending:
return ConversationStyle.bubbleColorOutgoingSending
return self.bubbleColorOutgoingSending
default:
return ConversationStyle.bubbleColorOutgoingSent
return self.bubbleColorOutgoingSent
}
} else {
owsFail("Unexpected message type: \(message)")
@ -145,7 +162,7 @@ public class ConversationStyle: NSObject {
}
@objc
public static func bubbleTextColor(message: TSMessage) -> UIColor {
public func bubbleTextColor(message: TSMessage) -> UIColor {
if message is TSIncomingMessage {
return UIColor.ows_white
} else if let outgoingMessage = message as? TSOutgoingMessage {

View File

@ -27,7 +27,10 @@ NS_ASSUME_NONNULL_BEGIN
OWSAvatarBuilder *avatarBuilder;
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
diameter:diameter
contactsManager:contactsManager];
} else if ([thread isKindOfClass:[TSGroupThread class]]) {

View File

@ -14,7 +14,9 @@ NS_ASSUME_NONNULL_BEGIN
/**
* Build an avatar for a Signal recipient
*/
- (instancetype)initWithSignalId:(NSString *)signalId
color:(UIColor *)color
diameter:(NSUInteger)diameter
contactsManager:(OWSContactsManager *)contactsManager;
@ -26,7 +28,6 @@ NS_ASSUME_NONNULL_BEGIN
diameter:(NSUInteger)diameter
contactsManager:(OWSContactsManager *)contactsManager;
@end
NS_ASSUME_NONNULL_END

View File

@ -22,6 +22,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) NSUInteger diameter;
@end
@ -32,6 +33,7 @@ NS_ASSUME_NONNULL_BEGIN
- (instancetype)initWithContactId:(NSString *)contactId
name:(NSString *)name
color:(UIColor *)color
diameter:(NSUInteger)diameter
contactsManager:(OWSContactsManager *)contactsManager
{
@ -42,6 +44,7 @@ NS_ASSUME_NONNULL_BEGIN
_signalId = contactId;
_contactName = name;
_color = color;
_diameter = diameter;
_contactsManager = contactsManager;
@ -49,6 +52,7 @@ NS_ASSUME_NONNULL_BEGIN
}
- (instancetype)initWithSignalId:(NSString *)signalId
color:(UIColor *)color
diameter:(NSUInteger)diameter
contactsManager:(OWSContactsManager *)contactsManager
{
@ -60,7 +64,7 @@ NS_ASSUME_NONNULL_BEGIN
if (name.length == 0) {
name = signalId;
}
return [self initWithContactId:signalId name:name diameter:diameter contactsManager:contactsManager];
return [self initWithContactId:signalId name:name color:color diameter:diameter contactsManager:contactsManager];
}
- (instancetype)initWithNonSignalName:(NSString *)nonSignalName
@ -68,7 +72,15 @@ NS_ASSUME_NONNULL_BEGIN
diameter:(NSUInteger)diameter
contactsManager:(OWSContactsManager *)contactsManager
{
return [self initWithContactId:colorSeed name:nonSignalName diameter:diameter contactsManager:contactsManager];
NSString *colorName = [TSThread stableConversationColorNameForString:colorSeed];
UIColor *color = [UIColor ows_conversationColorForColorName:colorName];
OWSAssert(color);
return [self initWithContactId:colorSeed
name:nonSignalName
color:color
diameter:diameter
contactsManager:contactsManager];
}
#pragma mark - Instance methods
@ -113,9 +125,9 @@ NS_ASSUME_NONNULL_BEGIN
}
CGFloat fontSize = (CGFloat)self.diameter / 2.8;
UIColor *backgroundColor = [UIColor backgroundColorForContact:self.signalId];
UIImage *image = [[JSQMessagesAvatarImageFactory avatarImageWithUserInitials:initials
backgroundColor:backgroundColor
backgroundColor:self.color
textColor:[UIColor whiteColor]
font:[UIFont ows_boldFontWithSize:fontSize]
diameter:self.diameter] avatarImage];

View File

@ -33,6 +33,10 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (NSString *)name;
@property (readonly, nullable) NSString *conversationColorName;
- (void)updateConversationColorName:(NSString *)colorName transaction:(YapDatabaseReadWriteTransaction *)transaction;
+ (NSString *)stableConversationColorNameForString:(NSString *)colorSeed;
/**
* @returns
* Signal Id (e164) of the contact if it's a contact thread.
@ -154,7 +158,7 @@ NS_ASSUME_NONNULL_BEGIN
#pragma mark - Update With... Methods
- (void)updateWithMutedUntilDate:(NSDate *)mutedUntilDate;
- (void)updateWithMutedUntilDate:(NSDate *)mutedUntilDate transaction:(YapDatabaseReadWriteTransaction *)transaction;
@end

View File

@ -3,6 +3,7 @@
//
#import "TSThread.h"
#import "Cryptography.h"
#import "NSDate+OWS.h"
#import "NSString+SSK.h"
#import "OWSDisappearingMessagesConfiguration.h"
@ -21,9 +22,10 @@ NS_ASSUME_NONNULL_BEGIN
@interface TSThread ()
@property (nonatomic) NSDate *creationDate;
@property (nonatomic, copy) NSDate *archivalDate;
@property (nonatomic) NSDate *lastMessageDate;
@property (nonatomic, copy) NSString *messageDraft;
@property (nonatomic, copy, nullable) NSDate *archivalDate;
@property (nonatomic, nullable) NSString *conversationColorName;
@property (nonatomic, nullable) NSDate *lastMessageDate;
@property (nonatomic, copy, nullable) NSString *messageDraft;
@property (atomic, nullable) NSDate *mutedUntilDate;
@end
@ -45,11 +47,26 @@ NS_ASSUME_NONNULL_BEGIN
_lastMessageDate = nil;
_creationDate = [NSDate date];
_messageDraft = nil;
_conversationColorName = [self.class randomConversationColorName];
}
return self;
}
- (nullable instancetype)initWithCoder:(NSCoder *)coder
{
self = [super initWithCoder:coder];
if (!self) {
return self;
}
if (!_conversationColorName) {
_conversationColorName = [self.class stableConversationColorNameForString:self.uniqueId];
}
return self;
}
- (void)removeWithTransaction:(YapDatabaseReadWriteTransaction *)transaction
{
[self removeAllThreadInteractionsWithTransaction:transaction];
@ -395,16 +412,58 @@ NS_ASSUME_NONNULL_BEGIN
[mutedUntilDate timeIntervalSinceDate:now] > 0);
}
#pragma mark - Update With... Methods
- (void)updateWithMutedUntilDate:(NSDate *)mutedUntilDate
- (void)updateWithMutedUntilDate:(NSDate *)mutedUntilDate transaction:(YapDatabaseReadWriteTransaction *)transaction
{
[self.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
[self applyChangeToSelfAndLatestCopy:transaction
changeBlock:^(TSThread *thread) {
[thread setMutedUntilDate:mutedUntilDate];
}];
}];
[self applyChangeToSelfAndLatestCopy:transaction
changeBlock:^(TSThread *thread) {
[thread setMutedUntilDate:mutedUntilDate];
}];
}
#pragma mark - Conversation Color
+ (NSString *)randomConversationColorName
{
NSUInteger count = self.conversationColorNames.count;
NSUInteger index = arc4random_uniform((uint32_t)count);
return [self.conversationColorNames objectAtIndex:index];
}
+ (NSString *)stableConversationColorNameForString:(NSString *)colorSeed
{
NSData *contactData = [colorSeed dataUsingEncoding:NSUTF8StringEncoding];
NSUInteger hashingLength = sizeof(unsigned long long);
unsigned long long choose;
NSData *hashData = [Cryptography computeSHA256Digest:contactData truncatedToBytes:hashingLength];
[hashData getBytes:&choose length:hashingLength];
NSUInteger index = (choose % [self.conversationColorNames count]);
return [self.conversationColorNames objectAtIndex:index];
}
+ (NSArray<NSString *> *)conversationColorNames
{
return @[
@"red",
@"pink",
@"purple",
@"indigo",
@"blue",
@"cyan",
@"teal",
@"green",
@"deep_orange",
@"grey"
];
}
- (void)updateConversationColorName:(NSString *)colorName transaction:(YapDatabaseReadWriteTransaction *)transaction
{
[self applyChangeToSelfAndLatestCopy:transaction
changeBlock:^(TSThread *thread) {
thread.conversationColorName = colorName;
}];
}
@end