Show verification state banner. Show verification state in conversation settings view.
// FREEBIE
This commit is contained in:
parent
8db75e86a1
commit
11ca51c95f
|
@ -81,6 +81,7 @@
|
|||
34DFCB851E8E04B500053165 /* AddToBlockListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34DFCB841E8E04B500053165 /* AddToBlockListViewController.m */; };
|
||||
34E3E5681EC4B19400495BAC /* AudioProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34E3E5671EC4B19400495BAC /* AudioProgressView.swift */; };
|
||||
34E8BF381EE9E2FD00F5F4CA /* FingerprintViewScanController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34E8BF371EE9E2FD00F5F4CA /* FingerprintViewScanController.m */; };
|
||||
34E8BF3B1EEB208E00F5F4CA /* DebugUIVerification.m in Sources */ = {isa = PBXBuildFile; fileRef = 34E8BF3A1EEB208E00F5F4CA /* DebugUIVerification.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 */; };
|
||||
|
@ -494,6 +495,8 @@
|
|||
34E3E5671EC4B19400495BAC /* AudioProgressView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioProgressView.swift; 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>"; };
|
||||
34E8BF391EEB208E00F5F4CA /* DebugUIVerification.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DebugUIVerification.h; sourceTree = "<group>"; };
|
||||
34E8BF3A1EEB208E00F5F4CA /* DebugUIVerification.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DebugUIVerification.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; path = OWSUnreadIndicatorCell.h; sourceTree = "<group>"; };
|
||||
|
@ -1030,10 +1033,12 @@
|
|||
34D8C02A1ED3685800188D7C /* DebugUIContacts.m */,
|
||||
34D8C0231ED3673300188D7C /* DebugUIMessages.h */,
|
||||
34D8C0241ED3673300188D7C /* DebugUIMessages.m */,
|
||||
34D8C0251ED3673300188D7C /* DebugUITableViewController.h */,
|
||||
34D8C0261ED3673300188D7C /* DebugUITableViewController.m */,
|
||||
452037CF1EE84975004E4CDF /* DebugUISessionState.h */,
|
||||
452037D01EE84975004E4CDF /* DebugUISessionState.m */,
|
||||
34D8C0251ED3673300188D7C /* DebugUITableViewController.h */,
|
||||
34D8C0261ED3673300188D7C /* DebugUITableViewController.m */,
|
||||
34E8BF391EEB208E00F5F4CA /* DebugUIVerification.h */,
|
||||
34E8BF3A1EEB208E00F5F4CA /* DebugUIVerification.m */,
|
||||
);
|
||||
path = DebugUI;
|
||||
sourceTree = "<group>";
|
||||
|
@ -2099,6 +2104,7 @@
|
|||
34B3F8931E8DF1710035BE1A /* SignalsNavigationController.m in Sources */,
|
||||
76EB063A18170B33006006FC /* FunctionalUtil.m in Sources */,
|
||||
34F308A21ECB469700BB7697 /* OWSBezierPathView.m in Sources */,
|
||||
34E8BF3B1EEB208E00F5F4CA /* DebugUIVerification.m in Sources */,
|
||||
76EB058A18170B33006006FC /* Release.m in Sources */,
|
||||
45D231771DC7E8F10034FA89 /* SessionResetJob.swift in Sources */,
|
||||
450873C71D9D867B006B54F2 /* OWSIncomingMessageCollectionViewCell.m in Sources */,
|
||||
|
|
|
@ -79,18 +79,18 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
- (void)signalAccountsDidChange:(NSNotification *)notification
|
||||
{
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self updateContacts];
|
||||
});
|
||||
OWSAssert([NSThread isMainThread]);
|
||||
|
||||
[self updateContacts];
|
||||
}
|
||||
|
||||
- (void)blockedPhoneNumbersDidChange:(id)notification
|
||||
{
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
self.blockedPhoneNumbers = [_blockingManager blockedPhoneNumbers];
|
||||
OWSAssert([NSThread isMainThread]);
|
||||
|
||||
[self updateContacts];
|
||||
});
|
||||
self.blockedPhoneNumbers = [_blockingManager blockedPhoneNumbers];
|
||||
|
||||
[self updateContacts];
|
||||
}
|
||||
|
||||
#pragma mark - Contacts
|
||||
|
|
|
@ -182,7 +182,7 @@ typedef enum : NSUInteger {
|
|||
@property (nonatomic) UILabel *navigationBarTitleLabel;
|
||||
@property (nonatomic) UILabel *navigationBarSubtitleLabel;
|
||||
@property (nonatomic) UIButton *attachButton;
|
||||
@property (nonatomic) UIView *blockStateIndicator;
|
||||
@property (nonatomic) UIView *bannerView;
|
||||
|
||||
// Back Button Unread Count
|
||||
@property (nonatomic, readonly) UIView *backButtonUnreadCountView;
|
||||
|
@ -294,9 +294,9 @@ typedef enum : NSUInteger {
|
|||
|
||||
- (void)blockedPhoneNumbersDidChange:(id)notification
|
||||
{
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self ensureBlockStateIndicator];
|
||||
});
|
||||
OWSAssert([NSThread isMainThread]);
|
||||
|
||||
[self ensureBannerState];
|
||||
}
|
||||
|
||||
- (void)identityStateDidChange:(NSNotification *)notification
|
||||
|
@ -304,6 +304,7 @@ typedef enum : NSUInteger {
|
|||
OWSAssert([NSThread isMainThread]);
|
||||
|
||||
[self updateNavigationBarSubtitleLabel];
|
||||
[self ensureBannerState];
|
||||
}
|
||||
|
||||
- (void)peekSetup
|
||||
|
@ -543,7 +544,7 @@ typedef enum : NSUInteger {
|
|||
// Triggering modified notification renders "call notification" when leaving full screen call view
|
||||
[self.thread touch];
|
||||
|
||||
[self ensureBlockStateIndicator];
|
||||
[self ensureBannerState];
|
||||
|
||||
[self resetContentAndLayout];
|
||||
|
||||
|
@ -671,20 +672,52 @@ typedef enum : NSUInteger {
|
|||
{
|
||||
_userHasScrolled = userHasScrolled;
|
||||
|
||||
[self ensureBlockStateIndicator];
|
||||
[self ensureBannerState];
|
||||
}
|
||||
|
||||
- (void)ensureBlockStateIndicator
|
||||
- (void)ensureBannerState
|
||||
{
|
||||
// This method should be called rarely, so it's simplest to discard and
|
||||
// rebuild the indicator view every time.
|
||||
[self.blockStateIndicator removeFromSuperview];
|
||||
self.blockStateIndicator = nil;
|
||||
[self.bannerView removeFromSuperview];
|
||||
self.bannerView = nil;
|
||||
|
||||
if (self.userHasScrolled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// A collection of the group members who are "no longer verified".
|
||||
NSMutableArray<NSString *> *noLongerVerifiedRecipientIds = [NSMutableArray new];
|
||||
for (NSString *recipientId in self.thread.recipientIdentifiers) {
|
||||
if ([[OWSIdentityManager sharedManager] verificationStateForRecipientId:recipientId]
|
||||
== OWSVerificationStateNoLongerVerified) {
|
||||
[noLongerVerifiedRecipientIds addObject:recipientId];
|
||||
}
|
||||
}
|
||||
if (noLongerVerifiedRecipientIds.count > 0) {
|
||||
NSString *message;
|
||||
if (noLongerVerifiedRecipientIds.count > 1) {
|
||||
message = NSLocalizedString(@"MESSAGES_VIEW_N_MEMBERS_NO_LONGER_VERIFIED",
|
||||
@"Indicates that more than one member of this group conversation is no longer verified.");
|
||||
} else {
|
||||
NSString *recipientId = [noLongerVerifiedRecipientIds firstObject];
|
||||
NSString *displayName = [self.contactsManager displayNameForPhoneIdentifier:recipientId];
|
||||
NSString *format
|
||||
= (self.isGroupConversation ? NSLocalizedString(@"MESSAGES_VIEW_1_MEMBER_NO_LONGER_VERIFIED_FORMAT",
|
||||
@"Indicates that one member of this group conversation is no longer "
|
||||
@"verified. Embeds {{user's name or phone number}}.")
|
||||
: NSLocalizedString(@"MESSAGES_VIEW_CONTACT_NO_LONGER_VERIFIED_FORMAT",
|
||||
@"Indicates that this 1:1 conversation is no longer verified. Embeds "
|
||||
@"{{user's name or phone number}}."));
|
||||
message = [NSString stringWithFormat:format, displayName];
|
||||
}
|
||||
|
||||
[self createBannerWithTitle:message
|
||||
bannerColor:[UIColor ows_destructiveRedColor]
|
||||
tapSelector:@selector(noLongerVerifiedBannerViewWasTapped:)];
|
||||
return;
|
||||
}
|
||||
|
||||
NSString *blockStateMessage = nil;
|
||||
if ([self isBlockedContactConversation]) {
|
||||
blockStateMessage = NSLocalizedString(
|
||||
|
@ -704,41 +737,61 @@ typedef enum : NSUInteger {
|
|||
}
|
||||
|
||||
if (blockStateMessage) {
|
||||
UILabel *label = [UILabel new];
|
||||
label.font = [UIFont ows_mediumFontWithSize:14.f];
|
||||
label.text = blockStateMessage;
|
||||
label.textColor = [UIColor whiteColor];
|
||||
|
||||
UIView *blockStateIndicator = [UIView new];
|
||||
blockStateIndicator.backgroundColor = [UIColor ows_redColor];
|
||||
blockStateIndicator.layer.cornerRadius = 2.5f;
|
||||
|
||||
// Use a shadow to "pop" the indicator above the other views.
|
||||
blockStateIndicator.layer.shadowColor = [UIColor blackColor].CGColor;
|
||||
blockStateIndicator.layer.shadowOffset = CGSizeMake(2, 3);
|
||||
blockStateIndicator.layer.shadowRadius = 2.f;
|
||||
blockStateIndicator.layer.shadowOpacity = 0.35f;
|
||||
|
||||
[blockStateIndicator addSubview:label];
|
||||
[label autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:5];
|
||||
[label autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:5];
|
||||
[label autoPinEdgeToSuperviewEdge:ALEdgeLeft withInset:15];
|
||||
[label autoPinEdgeToSuperviewEdge:ALEdgeRight withInset:15];
|
||||
|
||||
[blockStateIndicator addGestureRecognizer:[[UITapGestureRecognizer alloc]
|
||||
initWithTarget:self
|
||||
action:@selector(blockStateIndicatorWasTapped:)]];
|
||||
|
||||
[self.view addSubview:blockStateIndicator];
|
||||
[blockStateIndicator autoHCenterInSuperview];
|
||||
[blockStateIndicator autoPinToTopLayoutGuideOfViewController:self withInset:10];
|
||||
[self.view layoutSubviews];
|
||||
|
||||
self.blockStateIndicator = blockStateIndicator;
|
||||
[self createBannerWithTitle:blockStateMessage
|
||||
bannerColor:[UIColor ows_destructiveRedColor]
|
||||
tapSelector:@selector(blockBannerViewWasTapped:)];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)blockStateIndicatorWasTapped:(UIGestureRecognizer *)sender
|
||||
- (void)createBannerWithTitle:(NSString *)title bannerColor:(UIColor *)bannerColor tapSelector:(SEL)tapSelector
|
||||
{
|
||||
OWSAssert(title.length > 0);
|
||||
OWSAssert(bannerColor);
|
||||
|
||||
UILabel *label = [UILabel new];
|
||||
label.font = [UIFont ows_mediumFontWithSize:14.f];
|
||||
label.text = title;
|
||||
label.textColor = [UIColor whiteColor];
|
||||
label.numberOfLines = 0;
|
||||
label.lineBreakMode = NSLineBreakByWordWrapping;
|
||||
label.textAlignment = NSTextAlignmentCenter;
|
||||
|
||||
UIView *bannerView = [UIView new];
|
||||
bannerView.backgroundColor = bannerColor;
|
||||
bannerView.layer.cornerRadius = 2.5f;
|
||||
|
||||
// Use a shadow to "pop" the indicator above the other views.
|
||||
bannerView.layer.shadowColor = [UIColor blackColor].CGColor;
|
||||
bannerView.layer.shadowOffset = CGSizeMake(2, 3);
|
||||
bannerView.layer.shadowRadius = 2.f;
|
||||
bannerView.layer.shadowOpacity = 0.35f;
|
||||
|
||||
[bannerView addSubview:label];
|
||||
[label autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:5];
|
||||
[label autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:5];
|
||||
const CGFloat kBannerHPadding = 15.f;
|
||||
[label autoPinEdgeToSuperviewEdge:ALEdgeLeft withInset:kBannerHPadding];
|
||||
[label autoPinEdgeToSuperviewEdge:ALEdgeRight withInset:kBannerHPadding];
|
||||
|
||||
[bannerView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:tapSelector]];
|
||||
|
||||
[self.view addSubview:bannerView];
|
||||
[bannerView autoPinToTopLayoutGuideOfViewController:self withInset:10];
|
||||
[bannerView autoHCenterInSuperview];
|
||||
|
||||
CGFloat labelDesiredWidth = [label sizeThatFits:CGSizeZero].width;
|
||||
CGFloat bannerDesiredWidth = labelDesiredWidth + kBannerHPadding * 2.f;
|
||||
const CGFloat kMinBannerHMargin = 20.f;
|
||||
if (bannerDesiredWidth + kMinBannerHMargin * 2.f >= self.view.width) {
|
||||
[bannerView autoPinWidthToSuperviewWithMargin:kMinBannerHMargin];
|
||||
}
|
||||
|
||||
[self.view layoutSubviews];
|
||||
|
||||
self.bannerView = bannerView;
|
||||
}
|
||||
|
||||
- (void)blockBannerViewWasTapped:(UIGestureRecognizer *)sender
|
||||
{
|
||||
if (sender.state != UIGestureRecognizerStateRecognized) {
|
||||
return;
|
||||
|
@ -758,6 +811,13 @@ typedef enum : NSUInteger {
|
|||
}
|
||||
}
|
||||
|
||||
- (void)noLongerVerifiedBannerViewWasTapped:(UIGestureRecognizer *)sender
|
||||
{
|
||||
if (sender.state == UIGestureRecognizerStateRecognized) {
|
||||
[self showConversationSettingsAndShowVerification:YES];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)showUnblockContactUI:(BlockActionCompletionBlock)completionBlock
|
||||
{
|
||||
OWSAssert([self.thread isKindOfClass:[TSContactThread class]]);
|
||||
|
@ -1792,6 +1852,11 @@ typedef enum : NSUInteger {
|
|||
#pragma mark - Actions
|
||||
|
||||
- (void)showConversationSettings
|
||||
{
|
||||
[self showConversationSettingsAndShowVerification:NO];
|
||||
}
|
||||
|
||||
- (void)showConversationSettingsAndShowVerification:(BOOL)showVerification
|
||||
{
|
||||
if (self.userLeftGroup) {
|
||||
DDLogDebug(@"%@ Ignoring request to show conversation settings, since user left group", self.tag);
|
||||
|
@ -1801,6 +1866,7 @@ typedef enum : NSUInteger {
|
|||
OWSConversationSettingsTableViewController *settingsVC = [OWSConversationSettingsTableViewController new];
|
||||
settingsVC.conversationSettingsViewDelegate = self;
|
||||
[settingsVC configureWithThread:self.thread];
|
||||
settingsVC.showVerificationOnAppear = showVerification;
|
||||
[self.navigationController pushViewController:settingsVC animated:YES];
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#import "DebugUIContacts.h"
|
||||
#import "DebugUIMessages.h"
|
||||
#import "DebugUISessionState.h"
|
||||
#import "DebugUIVerification.h"
|
||||
#import "Signal-Swift.h"
|
||||
#import <SignalServiceKit/TSContactThread.h>
|
||||
#import <SignalServiceKit/TSThread.h>
|
||||
|
@ -38,41 +39,43 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
[self.navigationController pushViewController:viewController animated:YES];
|
||||
}
|
||||
|
||||
+ (OWSTableItem *)itemForSubsection:(OWSTableSection *)section
|
||||
viewController:(DebugUITableViewController *)viewController
|
||||
{
|
||||
OWSAssert(section);
|
||||
|
||||
__weak DebugUITableViewController *weakSelf = viewController;
|
||||
return [OWSTableItem disclosureItemWithText:section.headerTitle
|
||||
actionBlock:^{
|
||||
[weakSelf pushPageWithSection:section];
|
||||
}];
|
||||
}
|
||||
|
||||
+ (void)presentDebugUIForThread:(TSThread *)thread fromViewController:(UIViewController *)fromViewController
|
||||
{
|
||||
OWSAssert(thread);
|
||||
OWSAssert(fromViewController);
|
||||
|
||||
DebugUITableViewController *viewController = [DebugUITableViewController new];
|
||||
__weak DebugUITableViewController *weakSelf = viewController;
|
||||
|
||||
OWSTableContents *contents = [OWSTableContents new];
|
||||
contents.title = @"Debug: Conversation";
|
||||
|
||||
OWSTableSection *messagesSection = [DebugUIMessages sectionForThread:thread];
|
||||
[contents addSection:[OWSTableSection
|
||||
sectionWithTitle:messagesSection.headerTitle
|
||||
items:@[
|
||||
[OWSTableItem disclosureItemWithText:messagesSection.headerTitle
|
||||
actionBlock:^{
|
||||
[weakSelf pushPageWithSection:messagesSection];
|
||||
}],
|
||||
]]];
|
||||
|
||||
NSMutableArray<OWSTableItem *> *subsectionItems = [NSMutableArray new];
|
||||
[subsectionItems
|
||||
addObject:[self itemForSubsection:[DebugUIMessages sectionForThread:thread] viewController:viewController]];
|
||||
[subsectionItems addObject:[self itemForSubsection:[DebugUIContacts section] viewController:viewController]];
|
||||
if ([thread isKindOfClass:[TSContactThread class]]) {
|
||||
TSContactThread *contactThread = (TSContactThread *)thread;
|
||||
|
||||
OWSTableSection *sessionSection = [DebugUISessionState sectionForContactThread:contactThread];
|
||||
[contents addSection:[OWSTableSection
|
||||
sectionWithTitle:sessionSection.headerTitle
|
||||
items:@[
|
||||
[OWSTableItem disclosureItemWithText:sessionSection.headerTitle
|
||||
actionBlock:^{
|
||||
[weakSelf
|
||||
pushPageWithSection:sessionSection];
|
||||
}],
|
||||
]]];
|
||||
[subsectionItems addObject:[self itemForSubsection:[DebugUISessionState sectionForContactThread:contactThread]
|
||||
viewController:viewController]];
|
||||
[subsectionItems addObject:[self itemForSubsection:[DebugUIVerification sectionForThread:contactThread]
|
||||
viewController:viewController]];
|
||||
}
|
||||
[contents addSection:[OWSTableSection sectionWithTitle:@"Sections" items:subsectionItems]];
|
||||
|
||||
if ([thread isKindOfClass:[TSContactThread class]]) {
|
||||
// After enqueing the notification you may want to background the app or lock the screen before it triggers, so
|
||||
// we give a little delay.
|
||||
uint64_t notificationDelay = 5;
|
||||
|
@ -138,8 +141,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
]]];
|
||||
} // end contact thread section
|
||||
|
||||
[contents addSection:[DebugUIContacts section]];
|
||||
|
||||
viewController.contents = contents;
|
||||
[viewController presentFromViewController:fromViewController];
|
||||
}
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "OWSTableViewController.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class TSContactThread;
|
||||
|
||||
@interface DebugUIVerification : NSObject
|
||||
|
||||
+ (OWSTableSection *)sectionForThread:(TSContactThread *)thread;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -0,0 +1,77 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "DebugUIVerification.h"
|
||||
#import "DebugUIMessages.h"
|
||||
#import "Signal-Swift.h"
|
||||
#import <SignalServiceKit/OWSIdentityManager.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@implementation DebugUIVerification
|
||||
|
||||
#pragma mark - Logging
|
||||
|
||||
+ (NSString *)tag
|
||||
{
|
||||
return [NSString stringWithFormat:@"[%@]", self.class];
|
||||
}
|
||||
|
||||
- (NSString *)tag
|
||||
{
|
||||
return self.class.tag;
|
||||
}
|
||||
|
||||
#pragma mark - Factory Methods
|
||||
|
||||
+ (OWSTableSection *)sectionForThread:(TSContactThread *)thread
|
||||
{
|
||||
OWSAssert(thread);
|
||||
|
||||
NSString *recipientId = thread.contactIdentifier;
|
||||
OWSAssert(recipientId.length > 0);
|
||||
|
||||
return [OWSTableSection
|
||||
sectionWithTitle:@"Verification"
|
||||
items:@[
|
||||
[OWSTableItem itemWithTitle:@"Default"
|
||||
actionBlock:^{
|
||||
[DebugUIVerification setVerificationState:OWSVerificationStateDefault
|
||||
recipientId:recipientId];
|
||||
}],
|
||||
[OWSTableItem itemWithTitle:@"Verified"
|
||||
actionBlock:^{
|
||||
[DebugUIVerification setVerificationState:OWSVerificationStateVerified
|
||||
recipientId:recipientId];
|
||||
}],
|
||||
[OWSTableItem itemWithTitle:@"No Longer Verified"
|
||||
actionBlock:^{
|
||||
[DebugUIVerification
|
||||
setVerificationState:OWSVerificationStateNoLongerVerified
|
||||
recipientId:recipientId];
|
||||
}],
|
||||
]];
|
||||
}
|
||||
|
||||
+ (void)setVerificationState:(OWSVerificationState)verificationState recipientId:(NSString *)recipientId
|
||||
{
|
||||
OWSAssert(recipientId.length > 0);
|
||||
|
||||
OWSRecipientIdentity *_Nullable recipientIdentity =
|
||||
[[OWSIdentityManager sharedManager] recipientIdentityForRecipientId:recipientId];
|
||||
OWSAssert(recipientIdentity);
|
||||
// By capturing the identity key when we enter these views, we prevent the edge case
|
||||
// where the user verifies a key that we learned about while this view was open.
|
||||
NSData *identityKey = recipientIdentity.identityKey;
|
||||
OWSAssert(identityKey.length > 0);
|
||||
|
||||
[OWSIdentityManager.sharedManager setVerificationState:verificationState
|
||||
identityKey:identityKey
|
||||
recipientId:recipientId
|
||||
sendSyncMessage:verificationState != OWSVerificationStateNoLongerVerified];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -14,6 +14,8 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
@property (nonatomic, weak) id<OWSConversationSettingsViewDelegate> conversationSettingsViewDelegate;
|
||||
|
||||
@property (nonatomic) BOOL showVerificationOnAppear;
|
||||
|
||||
- (void)configureWithThread:(TSThread *)thread;
|
||||
|
||||
@end
|
||||
|
|
|
@ -95,6 +95,21 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
_messageSender = [Environment getCurrent].messageSender;
|
||||
_blockingManager = [OWSBlockingManager sharedManager];
|
||||
_contactsViewHelper = [[ContactsViewHelper alloc] initWithDelegate:self];
|
||||
|
||||
[self observeNotifications];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
}
|
||||
|
||||
- (void)observeNotifications
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(identityStateDidChange:)
|
||||
name:kNSNotificationName_IdentityStateDidChange
|
||||
object:nil];
|
||||
}
|
||||
|
||||
- (NSString *)threadName
|
||||
|
@ -196,6 +211,20 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
[self updateTableContents];
|
||||
}
|
||||
|
||||
- (void)viewDidAppear:(BOOL)animated
|
||||
{
|
||||
[super viewDidAppear:animated];
|
||||
|
||||
if (self.showVerificationOnAppear) {
|
||||
self.showVerificationOnAppear = NO;
|
||||
if (self.isGroupThread) {
|
||||
[self showGroupMembersView];
|
||||
} else {
|
||||
[self showVerificationView];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)updateTableContents
|
||||
{
|
||||
OWSTableContents *contents = [OWSTableContents new];
|
||||
|
@ -218,15 +247,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
iconName:@"table_ic_verify"];
|
||||
}
|
||||
actionBlock:^{
|
||||
OWSConversationSettingsTableViewController *strongSelf = weakSelf;
|
||||
if (!strongSelf) {
|
||||
return;
|
||||
}
|
||||
FingerprintViewController *fingerprintViewController = [FingerprintViewController new];
|
||||
[fingerprintViewController configureWithRecipientId:strongSelf.thread.contactIdentifier];
|
||||
UINavigationController *navigationController =
|
||||
[[UINavigationController alloc] initWithRootViewController:fingerprintViewController];
|
||||
[strongSelf presentViewController:navigationController animated:YES completion:nil];
|
||||
[weakSelf showVerificationView];
|
||||
}]];
|
||||
}
|
||||
|
||||
|
@ -349,14 +370,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
iconName:@"table_ic_group_members"];
|
||||
}
|
||||
actionBlock:^{
|
||||
OWSConversationSettingsTableViewController *strongSelf = weakSelf;
|
||||
if (!strongSelf) {
|
||||
return;
|
||||
}
|
||||
ShowGroupMembersViewController *showGroupMembersViewController =
|
||||
[ShowGroupMembersViewController new];
|
||||
[showGroupMembersViewController configWithThread:(TSGroupThread *)strongSelf.thread];
|
||||
[strongSelf.navigationController pushViewController:showGroupMembersViewController animated:YES];
|
||||
[weakSelf showGroupMembersView];
|
||||
}],
|
||||
[OWSTableItem itemWithCustomCellBlock:^{
|
||||
return [weakSelf disclosureCellWithName:NSLocalizedString(@"LEAVE_GROUP_ACTION",
|
||||
|
@ -535,15 +549,47 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
[threadTitleLabel autoPinEdgeToSuperviewEdge:ALEdgeLeft];
|
||||
[threadTitleLabel autoPinEdgeToSuperviewEdge:ALEdgeRight];
|
||||
|
||||
if (![self isGroupThread] && ![self.thread.name isEqualToString:self.thread.contactIdentifier]) {
|
||||
NSString *subtitle =
|
||||
[PhoneNumber bestEffortFormatPartialUserSpecifiedTextToLookLikeAPhoneNumber:self.thread.contactIdentifier];
|
||||
const CGFloat kSubtitlePointSize = 12.f;
|
||||
NSMutableAttributedString *subtitle = nil;
|
||||
if (![self isGroupThread]) {
|
||||
NSString *recipientId = self.thread.contactIdentifier;
|
||||
BOOL isVerified = [[OWSIdentityManager sharedManager] verificationStateForRecipientId:recipientId]
|
||||
== OWSVerificationStateVerified;
|
||||
BOOL hasName = ![self.thread.name isEqualToString:recipientId];
|
||||
|
||||
if (isVerified || hasName) {
|
||||
subtitle = [NSMutableAttributedString new];
|
||||
|
||||
if (isVerified) {
|
||||
// "checkmark"
|
||||
[subtitle appendAttributedString:[[NSAttributedString alloc]
|
||||
initWithString:@"\uf00c "
|
||||
attributes:@{
|
||||
NSFontAttributeName :
|
||||
[UIFont ows_fontAwesomeFont:kSubtitlePointSize],
|
||||
}]];
|
||||
}
|
||||
|
||||
if (hasName) {
|
||||
[subtitle
|
||||
appendAttributedString:
|
||||
[[NSAttributedString alloc]
|
||||
initWithString:[PhoneNumber bestEffortFormatPartialUserSpecifiedTextToLookLikeAPhoneNumber:
|
||||
recipientId]]];
|
||||
} else {
|
||||
[subtitle
|
||||
appendAttributedString:[[NSAttributedString alloc]
|
||||
initWithString:NSLocalizedString(@"PRIVACY_IDENTITY_IS_VERIFIED_BADGE",
|
||||
@"Badge indicating that the user is verified.")]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (subtitle) {
|
||||
UILabel *threadSubtitleLabel = [UILabel new];
|
||||
threadSubtitleLabel.text = subtitle;
|
||||
threadSubtitleLabel.textColor = [UIColor blackColor];
|
||||
// TODO:
|
||||
threadSubtitleLabel.font = [UIFont ows_regularFontWithSize:12.f];
|
||||
threadSubtitleLabel.textColor = [UIColor ows_darkGrayColor];
|
||||
threadSubtitleLabel.font = [UIFont ows_regularFontWithSize:kSubtitlePointSize];
|
||||
threadSubtitleLabel.attributedText = subtitle;
|
||||
threadSubtitleLabel.lineBreakMode = NSLineBreakByTruncatingTail;
|
||||
[threadNameView addSubview:threadSubtitleLabel];
|
||||
[threadSubtitleLabel autoPinEdgeToSuperviewEdge:ALEdgeBottom];
|
||||
|
@ -631,6 +677,22 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
#pragma mark - Actions
|
||||
|
||||
- (void)showVerificationView
|
||||
{
|
||||
FingerprintViewController *fingerprintViewController = [FingerprintViewController new];
|
||||
[fingerprintViewController configureWithRecipientId:self.thread.contactIdentifier];
|
||||
UINavigationController *navigationController =
|
||||
[[UINavigationController alloc] initWithRootViewController:fingerprintViewController];
|
||||
[self presentViewController:navigationController animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (void)showGroupMembersView
|
||||
{
|
||||
ShowGroupMembersViewController *showGroupMembersViewController = [ShowGroupMembersViewController new];
|
||||
[showGroupMembersViewController configWithThread:(TSGroupThread *)self.thread];
|
||||
[self.navigationController pushViewController:showGroupMembersViewController animated:YES];
|
||||
}
|
||||
|
||||
- (void)showUpdateGroupView:(UpdateGroupMode)mode
|
||||
{
|
||||
OWSAssert(self.conversationSettingsViewDelegate);
|
||||
|
@ -927,6 +989,15 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
[self.tableView reloadData];
|
||||
}
|
||||
|
||||
#pragma mark - Notifications
|
||||
|
||||
- (void)identityStateDidChange:(NSNotification *)notification
|
||||
{
|
||||
OWSAssert([NSThread isMainThread]);
|
||||
|
||||
[self updateTableContents];
|
||||
}
|
||||
|
||||
#pragma mark - Logging
|
||||
|
||||
+ (NSString *)tag
|
||||
|
|
|
@ -63,6 +63,21 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
- (void)commonInit
|
||||
{
|
||||
_contactsViewHelper = [[ContactsViewHelper alloc] initWithDelegate:self];
|
||||
|
||||
[self observeNotifications];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
}
|
||||
|
||||
- (void)observeNotifications
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(identityStateDidChange:)
|
||||
name:kNSNotificationName_IdentityStateDidChange
|
||||
object:nil];
|
||||
}
|
||||
|
||||
- (void)configWithThread:(TSGroupThread *)thread
|
||||
|
@ -134,6 +149,12 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
[cell configureWithRecipientId:recipientId contactsManager:helper.contactsManager];
|
||||
}
|
||||
|
||||
BOOL isVerified = [[OWSIdentityManager sharedManager] verificationStateForRecipientId:recipientId]
|
||||
== OWSVerificationStateVerified;
|
||||
if (isVerified) {
|
||||
[cell addVerifiedSubtitle];
|
||||
}
|
||||
|
||||
return cell;
|
||||
}
|
||||
customRowHeight:[ContactTableViewCell rowHeight]
|
||||
|
@ -313,6 +334,15 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
[self dismissViewControllerAnimated:YES completion:nil];
|
||||
}
|
||||
|
||||
#pragma mark - Notifications
|
||||
|
||||
- (void)identityStateDidChange:(NSNotification *)notification
|
||||
{
|
||||
OWSAssert([NSThread isMainThread]);
|
||||
|
||||
[self updateTableContents];
|
||||
}
|
||||
|
||||
#pragma mark - Logging
|
||||
|
||||
+ (NSString *)tag
|
||||
|
|
|
@ -132,18 +132,18 @@ NSString *const SignalsViewControllerSegueShowIncomingCall = @"ShowIncomingCallS
|
|||
|
||||
- (void)blockedPhoneNumbersDidChange:(id)notification
|
||||
{
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
_blockedPhoneNumberSet = [NSSet setWithArray:[_blockingManager blockedPhoneNumbers]];
|
||||
|
||||
[self.tableView reloadData];
|
||||
});
|
||||
OWSAssert([NSThread isMainThread]);
|
||||
|
||||
_blockedPhoneNumberSet = [NSSet setWithArray:[_blockingManager blockedPhoneNumbers]];
|
||||
|
||||
[self.tableView reloadData];
|
||||
}
|
||||
|
||||
- (void)signalAccountsDidChange:(id)notification
|
||||
{
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self.tableView reloadData];
|
||||
});
|
||||
OWSAssert([NSThread isMainThread]);
|
||||
|
||||
[self.tableView reloadData];
|
||||
}
|
||||
|
||||
#pragma mark - View Life Cycle
|
||||
|
|
|
@ -61,9 +61,9 @@ NSString *const kTSStorageManagerOWSContactsSyncingLastMessageKey =
|
|||
|
||||
- (void)signalAccountsDidChange:(id)notification
|
||||
{
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self sendSyncContactsMessageIfPossible];
|
||||
});
|
||||
OWSAssert([NSThread isMainThread]);
|
||||
|
||||
[self sendSyncContactsMessageIfPossible];
|
||||
}
|
||||
|
||||
#pragma mark - Methods
|
||||
|
|
|
@ -33,6 +33,8 @@ extern NSString *const kContactsTable_CellReuseIdentifier;
|
|||
|
||||
- (void)configureWithThread:(TSThread *)thread contactsManager:(OWSContactsManager *)contactsManager;
|
||||
|
||||
- (void)addVerifiedSubtitle;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
|
@ -23,6 +23,7 @@ const NSUInteger kContactTableViewCellAvatarSize = 40;
|
|||
|
||||
@property (nonatomic) IBOutlet UILabel *nameLabel;
|
||||
@property (nonatomic) IBOutlet UIImageView *avatarView;
|
||||
@property (nonatomic, nullable) UILabel *subtitle;
|
||||
|
||||
@end
|
||||
|
||||
|
@ -144,11 +145,67 @@ const NSUInteger kContactTableViewCellAvatarSize = 40;
|
|||
[self layoutSubviews];
|
||||
}
|
||||
|
||||
- (void)addVerifiedSubtitle
|
||||
{
|
||||
[self.subtitle removeFromSuperview];
|
||||
|
||||
const CGFloat kSubtitlePointSize = 10.f;
|
||||
NSMutableAttributedString *text = [NSMutableAttributedString new];
|
||||
// "checkmark"
|
||||
[text appendAttributedString:[[NSAttributedString alloc]
|
||||
initWithString:@"\uf00c "
|
||||
attributes:@{
|
||||
NSFontAttributeName : [UIFont ows_fontAwesomeFont:kSubtitlePointSize],
|
||||
}]];
|
||||
[text appendAttributedString:[[NSAttributedString alloc]
|
||||
initWithString:NSLocalizedString(@"PRIVACY_IDENTITY_IS_VERIFIED_BADGE",
|
||||
@"Badge indicating that the user is verified.")]];
|
||||
self.subtitle = [UILabel new];
|
||||
self.subtitle.font = [UIFont ows_regularFontWithSize:kSubtitlePointSize];
|
||||
self.subtitle.textColor = [UIColor ows_darkGrayColor];
|
||||
self.subtitle.attributedText = text;
|
||||
[self.subtitle sizeToFit];
|
||||
[self.contentView addSubview:self.subtitle];
|
||||
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
- (void)setFrame:(CGRect)frame
|
||||
{
|
||||
[super setFrame:frame];
|
||||
|
||||
[self layoutSubviews];
|
||||
}
|
||||
|
||||
- (void)setBounds:(CGRect)bounds
|
||||
{
|
||||
[super setBounds:bounds];
|
||||
|
||||
[self layoutSubviews];
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
[super layoutSubviews];
|
||||
|
||||
if (self.subtitle) {
|
||||
OWSAssert(self.nameLabel.superview == self.contentView);
|
||||
const CGFloat kSubtitleVMargin
|
||||
= ((self.contentView.height - self.nameLabel.font.lineHeight) * 0.5f - self.subtitle.height) * 0.5f;
|
||||
self.subtitle.frame = CGRectMake(self.nameLabel.left,
|
||||
round((self.contentView.height - self.subtitle.height) - kSubtitleVMargin),
|
||||
self.subtitle.width,
|
||||
self.subtitle.height);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)prepareForReuse
|
||||
{
|
||||
self.accessoryMessage = nil;
|
||||
self.accessoryView = nil;
|
||||
self.accessoryType = UITableViewCellAccessoryNone;
|
||||
[self.subtitle removeFromSuperview];
|
||||
self.subtitle = nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -715,9 +715,15 @@
|
|||
/* message footer while attachment is uploading */
|
||||
"MESSAGE_STATUS_UPLOADING" = "Uploading…";
|
||||
|
||||
/* Indicates that one member of this group conversation is no longer verified. Embeds {{user's name or phone number}}. */
|
||||
"MESSAGES_VIEW_1_MEMBER_NO_LONGER_VERIFIED_FORMAT" = "%@ is no longer verified.";
|
||||
|
||||
/* Indicates that this 1:1 conversation has been blocked. */
|
||||
"MESSAGES_VIEW_CONTACT_BLOCKED" = "You Blocked this User";
|
||||
|
||||
/* Indicates that this 1:1 conversation is no longer verified. Embeds {{user's name or phone number}}. */
|
||||
"MESSAGES_VIEW_CONTACT_NO_LONGER_VERIFIED_FORMAT" = "%@ is no longer verified.";
|
||||
|
||||
/* Action sheet title after tapping on failed download. */
|
||||
"MESSAGES_VIEW_FAILED_DOWNLOAD_ACTIONSHEET_TITLE" = "Download Failed.";
|
||||
|
||||
|
@ -730,6 +736,9 @@
|
|||
/* Indicates that some members of this group has been blocked. Embeds {{the number of blocked users in this group}}. */
|
||||
"MESSAGES_VIEW_GROUP_N_MEMBERS_BLOCKED_FORMAT" = "You Blocked %d Members of this Group";
|
||||
|
||||
/* Indicates that more than one member of this group conversation is no longer verified. */
|
||||
"MESSAGES_VIEW_N_MEMBERS_NO_LONGER_VERIFIED" = "More than one member of this group is no longer verified.";
|
||||
|
||||
/* The subtitle for the messages view title indicates that the title can be tapped to access settings for this conversation. */
|
||||
"MESSAGES_VIEW_TITLE_SUBTITLE" = "Tap here for settings";
|
||||
|
||||
|
@ -943,6 +952,9 @@
|
|||
/* Label indicating that the user is not verified. Embeds {{the user's name or phone number}}. */
|
||||
"PRIVACY_IDENTITY_IS_NOT_VERIFIED_FORMAT" = "%@ is not verified.";
|
||||
|
||||
/* Badge indicating that the user is verified. */
|
||||
"PRIVACY_IDENTITY_IS_VERIFIED_BADGE" = "Verified";
|
||||
|
||||
/* Label indicating that the user is verified. Embeds {{the user's name or phone number}}. */
|
||||
"PRIVACY_IDENTITY_IS_VERIFIED_FORMAT" = "%@ is verified.";
|
||||
|
||||
|
|
Loading…
Reference in New Issue