Start reworking the contact offers.

// FREEBIE
This commit is contained in:
Matthew Chen 2017-08-18 10:48:48 -04:00
parent 7ede899a74
commit 5f2f8ec6d8
14 changed files with 423 additions and 9 deletions

View File

@ -75,6 +75,9 @@
34B3F89F1E8DF5490035BE1A /* OWSTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34B3F89E1E8DF5490035BE1A /* OWSTableViewController.m */; };
34B3F8A21E8EA6040035BE1A /* ViewControllerUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 34B3F8A11E8EA6040035BE1A /* ViewControllerUtils.m */; };
34C42D5B1F45F7A80072EC04 /* OWSNavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34C42D5A1F45F7A80072EC04 /* OWSNavigationController.m */; };
34C42D611F4734CA0072EC04 /* OWSContactOffersCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 34C42D601F4734CA0072EC04 /* OWSContactOffersCell.m */; };
34C42D661F4734ED0072EC04 /* OWSContactOffersInteraction.m in Sources */ = {isa = PBXBuildFile; fileRef = 34C42D631F4734ED0072EC04 /* OWSContactOffersInteraction.m */; };
34C42D671F4734ED0072EC04 /* TSUnreadIndicatorInteraction.m in Sources */ = {isa = PBXBuildFile; fileRef = 34C42D651F4734ED0072EC04 /* TSUnreadIndicatorInteraction.m */; };
34CCAF381F0C0599004084F4 /* AppUpdateNag.m in Sources */ = {isa = PBXBuildFile; fileRef = 34CCAF371F0C0599004084F4 /* AppUpdateNag.m */; };
34CCAF3B1F0C2748004084F4 /* OWSAddToContactViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34CCAF3A1F0C2748004084F4 /* OWSAddToContactViewController.m */; };
34CE88E71F2FB9A10098030F /* ProfileViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34CE88E61F2FB9A10098030F /* ProfileViewController.m */; };
@ -94,7 +97,6 @@
34E3EF0D1EFC235B007F6822 /* DebugUIDiskUsage.m in Sources */ = {isa = PBXBuildFile; fileRef = 34E3EF0C1EFC235B007F6822 /* DebugUIDiskUsage.m */; };
34E3EF101EFC2684007F6822 /* DebugUIPage.m in Sources */ = {isa = PBXBuildFile; fileRef = 34E3EF0F1EFC2684007F6822 /* DebugUIPage.m */; };
34E8BF381EE9E2FD00F5F4CA /* FingerprintViewScanController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34E8BF371EE9E2FD00F5F4CA /* FingerprintViewScanController.m */; };
34F3089C1ECA4CDB00BB7697 /* TSUnreadIndicatorInteraction.m in Sources */ = {isa = PBXBuildFile; fileRef = 34F3089B1ECA4CDB00BB7697 /* TSUnreadIndicatorInteraction.m */; };
34F3089F1ECA580B00BB7697 /* OWSUnreadIndicatorCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 34F3089E1ECA580B00BB7697 /* OWSUnreadIndicatorCell.m */; };
34F308A21ECB469700BB7697 /* OWSBezierPathView.m in Sources */ = {isa = PBXBuildFile; fileRef = 34F308A11ECB469700BB7697 /* OWSBezierPathView.m */; };
34FD93701E3BD43A00109093 /* OWSAnyTouchGestureRecognizer.m in Sources */ = {isa = PBXBuildFile; fileRef = 34FD936F1E3BD43A00109093 /* OWSAnyTouchGestureRecognizer.m */; };
@ -508,6 +510,12 @@
34B3F8A11E8EA6040035BE1A /* ViewControllerUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ViewControllerUtils.m; sourceTree = "<group>"; };
34C42D591F45F7A80072EC04 /* OWSNavigationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSNavigationController.h; sourceTree = "<group>"; };
34C42D5A1F45F7A80072EC04 /* OWSNavigationController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSNavigationController.m; sourceTree = "<group>"; };
34C42D5F1F4734CA0072EC04 /* OWSContactOffersCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSContactOffersCell.h; sourceTree = "<group>"; };
34C42D601F4734CA0072EC04 /* OWSContactOffersCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSContactOffersCell.m; sourceTree = "<group>"; };
34C42D621F4734ED0072EC04 /* OWSContactOffersInteraction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSContactOffersInteraction.h; sourceTree = "<group>"; };
34C42D631F4734ED0072EC04 /* OWSContactOffersInteraction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSContactOffersInteraction.m; sourceTree = "<group>"; };
34C42D641F4734ED0072EC04 /* TSUnreadIndicatorInteraction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSUnreadIndicatorInteraction.h; sourceTree = "<group>"; };
34C42D651F4734ED0072EC04 /* TSUnreadIndicatorInteraction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSUnreadIndicatorInteraction.m; sourceTree = "<group>"; };
34CCAF361F0C0599004084F4 /* AppUpdateNag.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppUpdateNag.h; sourceTree = "<group>"; };
34CCAF371F0C0599004084F4 /* AppUpdateNag.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppUpdateNag.m; sourceTree = "<group>"; };
34CCAF391F0C2748004084F4 /* OWSAddToContactViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSAddToContactViewController.h; sourceTree = "<group>"; };
@ -545,8 +553,6 @@
34E3EF0F1EFC2684007F6822 /* DebugUIPage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DebugUIPage.m; sourceTree = "<group>"; };
34E8BF361EE9E2FD00F5F4CA /* FingerprintViewScanController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FingerprintViewScanController.h; sourceTree = "<group>"; };
34E8BF371EE9E2FD00F5F4CA /* FingerprintViewScanController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FingerprintViewScanController.m; sourceTree = "<group>"; };
34F3089A1ECA4CDB00BB7697 /* TSUnreadIndicatorInteraction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSUnreadIndicatorInteraction.h; sourceTree = "<group>"; };
34F3089B1ECA4CDB00BB7697 /* TSUnreadIndicatorInteraction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSUnreadIndicatorInteraction.m; sourceTree = "<group>"; };
34F3089D1ECA580B00BB7697 /* OWSUnreadIndicatorCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = OWSUnreadIndicatorCell.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
34F3089E1ECA580B00BB7697 /* OWSUnreadIndicatorCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = OWSUnreadIndicatorCell.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
34F308A01ECB469700BB7697 /* OWSBezierPathView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSBezierPathView.h; sourceTree = "<group>"; };
@ -1212,6 +1218,8 @@
45C681B61D305A580050903A /* OWSCall.m */,
45855F351D9498A40084F340 /* OWSContactAvatarBuilder.h */,
45855F361D9498A40084F340 /* OWSContactAvatarBuilder.m */,
34C42D621F4734ED0072EC04 /* OWSContactOffersInteraction.h */,
34C42D631F4734ED0072EC04 /* OWSContactOffersInteraction.m */,
458E38351D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.h */,
458E38361D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.m */,
45666EC71D994C0D008FE134 /* OWSGroupAvatarBuilder.h */,
@ -1219,6 +1227,8 @@
453D28B81D332DB100D523F0 /* OWSMessagesBubblesSizeCalculator.h */,
453D28B91D332DB100D523F0 /* OWSMessagesBubblesSizeCalculator.m */,
B62D53F41A23CC8B009AAF82 /* TSMessageAdapters */,
34C42D641F4734ED0072EC04 /* TSUnreadIndicatorInteraction.h */,
34C42D651F4734ED0072EC04 /* TSUnreadIndicatorInteraction.m */,
);
path = Models;
sourceTree = "<group>";
@ -1457,6 +1467,8 @@
3453D8E91EC0D4ED003F9E6F /* OWSAlerts.swift */,
34F308A01ECB469700BB7697 /* OWSBezierPathView.h */,
34F308A11ECB469700BB7697 /* OWSBezierPathView.m */,
34C42D5F1F4734CA0072EC04 /* OWSContactOffersCell.h */,
34C42D601F4734CA0072EC04 /* OWSContactOffersCell.m */,
459311FA1D75C948008DD4F0 /* OWSDeviceTableViewCell.h */,
459311FB1D75C948008DD4F0 /* OWSDeviceTableViewCell.m */,
450873C91D9D86F4006B54F2 /* OWSExpirableMessageView.h */,
@ -1476,8 +1488,6 @@
34F3089D1ECA580B00BB7697 /* OWSUnreadIndicatorCell.h */,
34F3089E1ECA580B00BB7697 /* OWSUnreadIndicatorCell.m */,
45A6DAD51EBBF85500893231 /* ReminderView.swift */,
34F3089A1ECA4CDB00BB7697 /* TSUnreadIndicatorInteraction.h */,
34F3089B1ECA4CDB00BB7697 /* TSUnreadIndicatorInteraction.m */,
);
name = Views;
path = views;
@ -2269,6 +2279,7 @@
45A6DAD61EBBF85500893231 /* ReminderView.swift in Sources */,
45666EC61D99483D008FE134 /* OWSAvatarBuilder.m in Sources */,
45E615161E8C590B0018AD52 /* DisplayableTextFilter.swift in Sources */,
34C42D611F4734CA0072EC04 /* OWSContactOffersCell.m in Sources */,
34B3F88A1E8DF1700035BE1A /* OWSLinkDeviceViewController.m in Sources */,
76EB068618170B34006006FC /* ContactTableViewCell.m in Sources */,
3497DBEF1ECE2E4700DB2605 /* DomainFrontingCountryViewController.m in Sources */,
@ -2339,6 +2350,7 @@
34B3F8721E8DF1700035BE1A /* AdvancedSettingsTableViewController.m in Sources */,
45F170D61E315310003FC1F2 /* Weak.swift in Sources */,
34B3F8891E8DF1700035BE1A /* OWSConversationSettingsViewController.m in Sources */,
34C42D671F4734ED0072EC04 /* TSUnreadIndicatorInteraction.m in Sources */,
34B3F87E1E8DF1700035BE1A /* InboxTableViewCell.m in Sources */,
34B3F8731E8DF1700035BE1A /* AttachmentApprovalViewController.swift in Sources */,
B6B1013C196D213F007E3930 /* SignalKeyingStorage.m in Sources */,
@ -2349,6 +2361,7 @@
45666F7E1D9C0814008FE134 /* OWSDatabaseMigrationRunner.m in Sources */,
4579431E1E7C8CE9008ED0C0 /* Pastelog.m in Sources */,
34D99C941F2937CC00D284D6 /* OWSSwiftUtils.swift in Sources */,
34C42D661F4734ED0072EC04 /* OWSContactOffersInteraction.m in Sources */,
34B3F8941E8DF1710035BE1A /* SignalsViewController.m in Sources */,
34E8BF381EE9E2FD00F5F4CA /* FingerprintViewScanController.m in Sources */,
76EB058818170B33006006FC /* PropertyListPreferences.m in Sources */,
@ -2356,7 +2369,6 @@
34B3F87D1E8DF1700035BE1A /* FullImageViewController.m in Sources */,
45666F7B1D9C0533008FE134 /* OWSDatabaseMigration.m in Sources */,
B90418E6183E9DD40038554A /* DateUtil.m in Sources */,
34F3089C1ECA4CDB00BB7697 /* TSUnreadIndicatorInteraction.m in Sources */,
459311FC1D75C948008DD4F0 /* OWSDeviceTableViewCell.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;

View File

@ -0,0 +1,25 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
#import <SignalServiceKit/TSInteraction.h>
NS_ASSUME_NONNULL_BEGIN
@interface OWSContactOffersInteraction : TSInteraction
//@property (atomic, readonly) BOOL hasMoreUnseenMessages;
//
//@property (atomic, readonly) NSUInteger missingUnseenSafetyNumberChangeCount;
- (instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithTimestamp:(uint64_t)timestamp
thread:(TSThread *)thread
// hasMoreUnseenMessages:(BOOL)hasMoreUnseenMessages
// missingUnseenSafetyNumberChangeCount:(NSUInteger)missingUnseenSafetyNumberChangeCount
NS_DESIGNATED_INITIALIZER;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,54 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
#import "OWSContactOffersInteraction.h"
NS_ASSUME_NONNULL_BEGIN
@interface OWSContactOffersInteraction ()
//@property (atomic) BOOL hasMoreUnseenMessages;
@end
#pragma mark -
@implementation OWSContactOffersInteraction
- (instancetype)initWithCoder:(NSCoder *)coder
{
return [super initWithCoder:coder];
}
- (instancetype)initWithTimestamp:(uint64_t)timestamp thread:(TSThread *)thread
// hasMoreUnseenMessages:(BOOL)hasMoreUnseenMessages
// missingUnseenSafetyNumberChangeCount:(NSUInteger)missingUnseenSafetyNumberChangeCount
{
self = [super initWithTimestamp:timestamp inThread:thread];
if (!self) {
return self;
}
// _hasMoreUnseenMessages = hasMoreUnseenMessages;
// _missingUnseenSafetyNumberChangeCount = missingUnseenSafetyNumberChangeCount;
return self;
}
- (BOOL)shouldUseReceiptDateForSorting
{
// Use the timestamp, not the "received at" timestamp to sort,
// since we're creating these interactions after the fact and back-dating them.
return NO;
}
- (BOOL)isDynamicInteraction
{
return YES;
}
@end
NS_ASSUME_NONNULL_END

View File

@ -4,6 +4,8 @@
#import "OWSMessagesBubblesSizeCalculator.h"
#import "OWSCall.h"
#import "OWSContactOffersCell.h"
#import "OWSContactOffersInteraction.h"
#import "OWSSystemMessageCell.h"
#import "OWSUnreadIndicatorCell.h"
#import "TSGenericAttachmentAdapter.h"
@ -40,6 +42,7 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, readonly) OWSSystemMessageCell *referenceSystemMessageCell;
@property (nonatomic, readonly) OWSUnreadIndicatorCell *referenceUnreadIndicatorCell;
@property (nonatomic, readonly) OWSContactOffersCell *referenceContactOffersCell;
@end
@ -52,6 +55,7 @@ NS_ASSUME_NONNULL_BEGIN
if (self = [super init]) {
_referenceSystemMessageCell = [OWSSystemMessageCell new];
_referenceUnreadIndicatorCell = [OWSUnreadIndicatorCell new];
_referenceContactOffersCell = [OWSContactOffersCell new];
}
return self;
}
@ -88,6 +92,12 @@ NS_ASSUME_NONNULL_BEGIN
= (TSUnreadIndicatorInteraction *)((TSMessageAdapter *)messageData).interaction;
return [self sizeForUnreadIndicator:interaction cacheKey:cacheKey layout:layout];
}
case OWSContactOffersAdapter: {
id cacheKey = [self cacheKeyForMessageData:messageData];
OWSContactOffersInteraction *interaction
= (OWSContactOffersInteraction *)((TSMessageAdapter *)messageData).interaction;
return [self sizeForContactOffers:interaction cacheKey:cacheKey layout:layout];
}
case TSIncomingMessageAdapter:
case TSOutgoingMessageAdapter:
break;
@ -148,6 +158,26 @@ NS_ASSUME_NONNULL_BEGIN
return [cachedSize CGSizeValue];
}
CGSize result = [self.referenceContactOffersCell bubbleSizeForInteraction:interaction
collectionViewWidth:layout.collectionView.width];
[self.cache setObject:[NSValue valueWithCGSize:result] forKey:cacheKey];
return result;
}
- (CGSize)sizeForContactOffers:(OWSContactOffersInteraction *)interaction
cacheKey:(id)cacheKey
layout:(JSQMessagesCollectionViewFlowLayout *)layout
{
OWSAssert(interaction);
OWSAssert(cacheKey);
NSValue *cachedSize = [self.cache objectForKey:cacheKey];
if (cachedSize != nil) {
return [cachedSize CGSizeValue];
}
CGSize result = [self.referenceUnreadIndicatorCell bubbleSizeForInteraction:interaction
collectionViewWidth:layout.collectionView.width];

View File

@ -16,6 +16,7 @@ typedef NS_ENUM(NSInteger, TSMessageAdapterType) {
TSMediaAttachmentAdapter,
TSGenericTextMessageAdapter, // Used when message direction is unknown (outgoing or incoming)
TSUnreadIndicatorAdapter,
OWSContactOffersAdapter,
};
@protocol OWSMessageData <JSQMessageData, OWSMessageEditing>

View File

@ -5,6 +5,7 @@
#import "TSMessageAdapter.h"
#import "AttachmentSharing.h"
#import "OWSCall.h"
#import "OWSContactOffersInteraction.h"
#import "Signal-Swift.h"
#import "TSAttachmentPointer.h"
#import "TSAttachmentStream.h"
@ -226,6 +227,8 @@ NS_ASSUME_NONNULL_BEGIN
adapter.messageType = TSInfoMessageAdapter;
} else if ([interaction isKindOfClass:[TSUnreadIndicatorInteraction class]]) {
adapter.messageType = TSUnreadIndicatorAdapter;
} else if ([interaction isKindOfClass:[OWSContactOffersInteraction class]]) {
adapter.messageType = OWSContactOffersAdapter;
} else if ([interaction isKindOfClass:[TSErrorMessage class]]) {
TSErrorMessage *errorMessage = (TSErrorMessage *)interaction;
adapter.errorMessageType = errorMessage.errorType;

View File

@ -16,6 +16,8 @@
#import "NewGroupViewController.h"
#import "OWSAudioAttachmentPlayer.h"
#import "OWSCall.h"
#import "OWSContactOffersCell.h"
#import "OWSContactOffersInteraction.h"
#import "OWSContactsManager.h"
#import "OWSConversationSettingsViewController.h"
#import "OWSConversationSettingsViewDelegate.h"
@ -1649,6 +1651,10 @@ typedef enum : NSUInteger {
cell = [self loadUnreadIndicatorCell:indexPath interaction:message.interaction];
break;
}
case OWSContactOffersAdapter: {
cell = [self loadContactOffersCell:indexPath interaction:message.interaction];
break;
}
default: {
OWSFail(@"using default cell constructor for message: %@", message);
cell = (JSQMessagesCollectionViewCell *)[super collectionView:collectionView
@ -1737,6 +1743,23 @@ typedef enum : NSUInteger {
return cell;
}
- (JSQMessagesCollectionViewCell *)loadContactOffersCell:(NSIndexPath *)indexPath
interaction:(TSInteraction *)interaction
{
OWSAssert(indexPath);
OWSAssert(interaction);
OWSAssert([interaction isKindOfClass:[OWSContactOffersInteraction class]]);
OWSContactOffersInteraction *offersInteraction = (OWSContactOffersInteraction *)interaction;
OWSContactOffersCell *cell =
[self.collectionView dequeueReusableCellWithReuseIdentifier:[OWSContactOffersCell cellReuseIdentifier]
forIndexPath:indexPath];
[cell configureWithInteraction:offersInteraction];
return cell;
}
- (OWSSystemMessageCell *)loadSystemMessageCell:(NSIndexPath *)indexPath interaction:(TSInteraction *)interaction
{
OWSAssert(indexPath);
@ -1822,6 +1845,7 @@ typedef enum : NSUInteger {
id<OWSMessageData> previousMessage =
[self messageAtIndexPath:[NSIndexPath indexPathForItem:indexPath.row - 1 inSection:indexPath.section]];
// TODO: What about the contact offers?
if ([previousMessage.interaction isKindOfClass:[TSUnreadIndicatorInteraction class]]) {
// Always show timestamp between unread indicator and the following interaction
return YES;
@ -2165,6 +2189,9 @@ typedef enum : NSUInteger {
case TSUnreadIndicatorAdapter:
OWSFail(@"Unexpected tap for system message.");
break;
case OWSContactOffersAdapter:
// TODO:
break;
default:
DDLogDebug(@"Unhandled bubble touch for interaction: %@.", interaction);
break;
@ -4198,8 +4225,10 @@ typedef enum : NSUInteger {
- (BOOL)shouldShowCellDecorationsAtIndexPath:(NSIndexPath *)indexPath
{
TSInteraction *interaction = [self interactionAtIndexPath:indexPath];
// Show any top/bottom labels for all but the unread indicator
//
// TODO: What about the contact offers?
return ![interaction isKindOfClass:[TSUnreadIndicatorInteraction class]];
}

View File

@ -12,7 +12,6 @@ NS_ASSUME_NONNULL_BEGIN
@class TSInteraction;
@class YapDatabaseConnection;
@class TSThread;
@class TSUnreadIndicatorInteraction;
@interface ThreadDynamicInteractions : NSObject

View File

@ -3,6 +3,7 @@
//
#import "ThreadUtil.h"
#import "OWSContactOffersInteraction.h"
#import "OWSContactsManager.h"
#import "OWSProfileManager.h"
#import "Signal-Swift.h"

View File

@ -0,0 +1,23 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
#import <JSQMessagesViewController/JSQMessagesCollectionViewCell.h>
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@class OWSContactOffersInteraction;
@interface OWSContactOffersCell : JSQMessagesCollectionViewCell
@property (nonatomic, nullable, readonly) OWSContactOffersInteraction *interaction;
- (void)configureWithInteraction:(OWSContactOffersInteraction *)interaction;
- (CGSize)bubbleSizeForInteraction:(OWSContactOffersInteraction *)interaction
collectionViewWidth:(CGFloat)collectionViewWidth;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,238 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
#import "OWSContactOffersCell.h"
#import "NSBundle+JSQMessages.h"
#import "OWSContactOffersInteraction.h"
#import "UIColor+OWS.h"
#import "UIFont+OWS.h"
#import "UIView+OWS.h"
#import <JSQMessagesViewController/UIView+JSQMessages.h>
NS_ASSUME_NONNULL_BEGIN
@interface OWSContactOffersCell ()
@property (nonatomic, nullable) OWSContactOffersInteraction *interaction;
@property (nonatomic) UIView *bannerView;
@property (nonatomic) UIView *bannerTopHighlightView;
@property (nonatomic) UIView *bannerBottomHighlightView1;
@property (nonatomic) UIView *bannerBottomHighlightView2;
@property (nonatomic) UILabel *titleLabel;
@property (nonatomic) UILabel *subtitleLabel;
@end
#pragma mark -
@implementation OWSContactOffersCell
// `[UIView init]` invokes `[self initWithFrame:...]`.
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
[self commontInit];
}
return self;
}
- (void)commontInit
{
OWSAssert(!self.bannerView);
[self setTranslatesAutoresizingMaskIntoConstraints:NO];
self.backgroundColor = [UIColor whiteColor];
self.bannerView = [UIView new];
self.bannerView.backgroundColor = [UIColor colorWithRGBHex:0xf6eee3];
[self.contentView addSubview:self.bannerView];
self.bannerTopHighlightView = [UIView new];
self.bannerTopHighlightView.backgroundColor = [UIColor colorWithRGBHex:0xf9f3eb];
[self.bannerView addSubview:self.bannerTopHighlightView];
self.bannerBottomHighlightView1 = [UIView new];
self.bannerBottomHighlightView1.backgroundColor = [UIColor colorWithRGBHex:0xd1c6b8];
[self.bannerView addSubview:self.bannerBottomHighlightView1];
self.bannerBottomHighlightView2 = [UIView new];
self.bannerBottomHighlightView2.backgroundColor = [UIColor colorWithRGBHex:0xdbcfc0];
[self.bannerView addSubview:self.bannerBottomHighlightView2];
self.titleLabel = [UILabel new];
self.titleLabel.textColor = [UIColor colorWithRGBHex:0x403e3b];
self.titleLabel.font = [self titleFont];
[self.bannerView addSubview:self.titleLabel];
self.subtitleLabel = [UILabel new];
self.subtitleLabel.textColor = [UIColor ows_infoMessageBorderColor];
self.subtitleLabel.font = [self subtitleFont];
// The subtitle may wrap to a second line.
self.subtitleLabel.numberOfLines = 0;
self.subtitleLabel.lineBreakMode = NSLineBreakByWordWrapping;
self.subtitleLabel.textAlignment = NSTextAlignmentCenter;
[self.contentView addSubview:self.subtitleLabel];
}
+ (NSString *)cellReuseIdentifier
{
return NSStringFromClass([self class]);
}
- (void)configureWithInteraction:(OWSContactOffersInteraction *)interaction;
{
OWSAssert(interaction);
_interaction = interaction;
self.titleLabel.text = [self titleForInteraction:self.interaction];
self.subtitleLabel.text = [self subtitleForInteraction:self.interaction];
self.backgroundColor = [UIColor whiteColor];
[self setNeedsLayout];
}
- (UIFont *)titleFont
{
return [UIFont ows_regularFontWithSize:16.f];
}
- (UIFont *)subtitleFont
{
return [UIFont ows_regularFontWithSize:12.f];
}
- (NSString *)titleForInteraction:(OWSContactOffersInteraction *)interaction
{
return NSLocalizedString(@"MESSAGES_VIEW_UNREAD_INDICATOR", @"Indicator that separates read from unread messages.")
.uppercaseString;
}
- (NSString *)subtitleForInteraction:(OWSContactOffersInteraction *)interaction
{
if (!interaction.hasMoreUnseenMessages) {
return nil;
}
NSString *subtitleFormat = (interaction.missingUnseenSafetyNumberChangeCount > 0
? NSLocalizedString(@"MESSAGES_VIEW_UNREAD_INDICATOR_HAS_MORE_UNSEEN_MESSAGES_FORMAT",
@"Messages that indicates that there are more unseen messages that be revealed by tapping the 'load "
@"earlier messages' button. Embeds {{the name of the 'load earlier messages' button}}")
: NSLocalizedString(
@"MESSAGES_VIEW_UNREAD_INDICATOR_HAS_MORE_UNSEEN_MESSAGES_AND_SAFETY_NUMBER_CHANGES_FORMAT",
@"Messages that indicates that there are more unseen messages including safety number changes that "
@"be revealed by tapping the 'load earlier messages' button. Embeds {{the name of the 'load earlier "
@"messages' button}}."));
NSString *loadMoreButtonName = [NSBundle jsq_localizedStringForKey:@"load_earlier_messages"];
return [NSString stringWithFormat:subtitleFormat, loadMoreButtonName];
}
- (CGFloat)subtitleHMargin
{
return 20.f;
}
- (CGFloat)subtitleVSpacing
{
return 3.f;
}
- (CGFloat)titleInnerHMargin
{
return 10.f;
}
- (CGFloat)titleVMargin
{
return 5.5f;
}
- (CGFloat)topVMargin
{
return 5.f;
}
- (CGFloat)bottomVMargin
{
return 5.f;
}
- (void)layoutSubviews
{
[super layoutSubviews];
[self.titleLabel sizeToFit];
// It's a bit of a hack, but we use a view that extends _outside_ the cell's bounds
// to draw its background, since we want the background to extend to the edges of the
// collection view.
//
// This layout logic assumes that the cell insets are symmetrical and can be deduced
// from the cell frame.
CGRect bannerViewFrame = CGRectMake(-self.left,
round(self.topVMargin),
round(self.width + self.left * 2.f),
round(self.titleLabel.height + self.titleVMargin * 2.f));
self.bannerView.frame = [self convertRect:bannerViewFrame toView:self.contentView];
// The highlights should be 1px (not 1pt), so adapt their thickness to
// the device resolution.
CGFloat kHighlightThickness = 1.f / [UIScreen mainScreen].scale;
self.bannerTopHighlightView.frame = CGRectMake(0, 0, self.bannerView.width, kHighlightThickness);
self.bannerBottomHighlightView1.frame
= CGRectMake(0, self.bannerView.height - kHighlightThickness * 2.f, self.bannerView.width, kHighlightThickness);
self.bannerBottomHighlightView2.frame
= CGRectMake(0, self.bannerView.height - kHighlightThickness * 1.f, self.bannerView.width, kHighlightThickness);
[self.titleLabel centerOnSuperview];
if (self.subtitleLabel.text.length > 0) {
CGSize subtitleSize = [self.subtitleLabel
sizeThatFits:CGSizeMake(self.contentView.width - [self subtitleHMargin] * 2.f, CGFLOAT_MAX)];
self.subtitleLabel.frame = CGRectMake(round((self.contentView.width - subtitleSize.width) * 0.5f),
round(self.bannerView.bottom + self.subtitleVSpacing),
ceil(subtitleSize.width),
ceil(subtitleSize.height));
}
}
- (CGSize)bubbleSizeForInteraction:(OWSContactOffersInteraction *)interaction
collectionViewWidth:(CGFloat)collectionViewWidth
{
CGSize result = CGSizeMake(collectionViewWidth, 0);
result.height += self.titleVMargin * 2.f;
result.height += self.topVMargin;
result.height += self.bottomVMargin;
NSString *title = [self titleForInteraction:interaction];
NSString *subtitle = [self subtitleForInteraction:interaction];
self.titleLabel.text = title;
result.height += ceil([self.titleLabel sizeThatFits:CGSizeZero].height);
if (subtitle.length > 0) {
result.height += self.subtitleVSpacing;
self.subtitleLabel.text = subtitle;
result.height += ceil(
[self.subtitleLabel sizeThatFits:CGSizeMake(collectionViewWidth - self.subtitleHMargin * 2.f, CGFLOAT_MAX)]
.height);
}
return result;
}
- (void)prepareForReuse
{
[super prepareForReuse];
self.interaction = nil;
}
@end
NS_ASSUME_NONNULL_END

View File

@ -6,7 +6,6 @@
#import "Environment.h"
#import "NSBundle+JSQMessages.h"
#import "OWSContactsManager.h"
#import "TSUnreadIndicatorInteraction.h"
#import "UIColor+OWS.h"
#import "UIFont+OWS.h"
#import "UIView+OWS.h"