Merge branch 'charlesmchen/onboardingHome'

pull/2/head
Matthew Chen 6 years ago
commit 8d4cea0c27

@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "human-1@3x.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "human-2@3x.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "human-3@3x.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "human-4@3x.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "human-5@3x.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

@ -56,7 +56,7 @@ NS_ASSUME_NONNULL_BEGIN
[self.qrScanningController.view autoPinEdgeToSuperviewEdge:ALEdgeLeading];
[self.qrScanningController.view autoPinEdgeToSuperviewEdge:ALEdgeTrailing];
[self.qrScanningController.view autoPinToTopLayoutGuideOfViewController:self withInset:0.f];
[self.qrScanningController.view autoPinToAspectRatio:1.f];
[self.qrScanningController.view autoPinToSquareAspectRatio];
UIView *bottomView = [UIView new];
[self.view addSubview:bottomView];

@ -7,6 +7,7 @@
#import "AppSettingsViewController.h"
#import "HomeViewCell.h"
#import "NewContactThreadViewController.h"
#import "OWS2FARegistrationViewController.h"
#import "OWSNavigationController.h"
#import "OWSPrimaryStorage.h"
#import "ProfileViewController.h"
@ -24,6 +25,7 @@
#import <SignalMessaging/OWSContactsManager.h>
#import <SignalMessaging/OWSFormat.h>
#import <SignalMessaging/SignalMessaging-Swift.h>
#import <SignalMessaging/Theme.h>
#import <SignalMessaging/UIUtil.h>
#import <SignalServiceKit/OWSMessageSender.h>
#import <SignalServiceKit/OWSMessageUtils.h>
@ -68,7 +70,10 @@ NSString *const kArchivedConversationsReuseIdentifier = @"kArchivedConversations
OWSBlockListCacheDelegate>
@property (nonatomic) UITableView *tableView;
@property (nonatomic) UILabel *emptyBoxLabel;
@property (nonatomic) UIView *emptyInboxView;
@property (nonatomic) UIView *firstConversationCueView;
@property (nonatomic) UILabel *firstConversationLabel;
@property (nonatomic) YapDatabaseConnection *editingDbConnection;
@property (nonatomic) YapDatabaseConnection *uiDatabaseConnection;
@ -215,6 +220,10 @@ NSString *const kArchivedConversationsReuseIdentifier = @"kArchivedConversations
OWSAssertIsOnMainThread();
[self reloadTableViewData];
if (!self.firstConversationCueView.isHidden) {
[self updateFirstConversationLabel];
}
}
- (void)registrationStateDidChange:(id)notification
@ -328,17 +337,20 @@ NSString *const kArchivedConversationsReuseIdentifier = @"kArchivedConversations
self.tableView.rowHeight = UITableViewAutomaticDimension;
self.tableView.estimatedRowHeight = 60;
UILabel *emptyBoxLabel = [UILabel new];
self.emptyBoxLabel = emptyBoxLabel;
[self.view addSubview:emptyBoxLabel];
// Let the label use as many lines as needed. It will very rarely be more than 2 but may happen for verbose locs.
[emptyBoxLabel setNumberOfLines:0];
emptyBoxLabel.lineBreakMode = NSLineBreakByWordWrapping;
[emptyBoxLabel autoPinLeadingToSuperviewMargin];
[emptyBoxLabel autoPinTrailingToSuperviewMargin];
[emptyBoxLabel autoAlignAxisToSuperviewAxis:ALAxisHorizontal];
self.emptyInboxView = [self createEmptyInboxView];
[self.view addSubview:self.emptyInboxView];
[self.emptyInboxView autoPinWidthToSuperviewMargins];
[self.emptyInboxView autoVCenterInSuperview];
[self createFirstConversationCueView];
[self.view addSubview:self.firstConversationCueView];
[self.firstConversationCueView autoPinToTopLayoutGuideOfViewController:self withInset:0.f];
[self.firstConversationCueView autoPinEdgeToSuperviewEdge:ALEdgeTrailing withInset:10];
[self.firstConversationCueView autoPinEdgeToSuperviewEdge:ALEdgeLeading
withInset:10
relation:NSLayoutRelationGreaterThanOrEqual];
[self.firstConversationCueView autoPinEdgeToSuperviewMargin:ALEdgeBottom
relation:NSLayoutRelationGreaterThanOrEqual];
UIRefreshControl *pullToRefreshView = [UIRefreshControl new];
pullToRefreshView.tintColor = [UIColor grayColor];
@ -348,6 +360,167 @@ NSString *const kArchivedConversationsReuseIdentifier = @"kArchivedConversations
[self.tableView insertSubview:pullToRefreshView atIndex:0];
}
- (UIView *)createEmptyInboxView
{
NSArray<NSString *> *emptyInboxImageNames = @[
@"home_empty_splash_1",
@"home_empty_splash_2",
@"home_empty_splash_3",
@"home_empty_splash_4",
@"home_empty_splash_5",
];
NSString *emptyInboxImageName = emptyInboxImageNames[arc4random_uniform((uint32_t) emptyInboxImageNames.count)];
UIImageView *emptyInboxImageView = [UIImageView new];
emptyInboxImageView.image = [UIImage imageNamed:emptyInboxImageName];
emptyInboxImageView.layer.minificationFilter = kCAFilterTrilinear;
emptyInboxImageView.layer.magnificationFilter = kCAFilterTrilinear;
[emptyInboxImageView autoPinToAspectRatioWithSize:emptyInboxImageView.image.size];
UILabel *emptyInboxLabel = [UILabel new];
emptyInboxLabel.text = NSLocalizedString(@"INBOX_VIEW_EMPTY_INBOX",
@"Message shown in the home view when the inbox is empty.");
emptyInboxLabel.font = UIFont.ows_dynamicTypeBodyClampedFont;
emptyInboxLabel.textColor = Theme.secondaryColor;
emptyInboxLabel.textAlignment = NSTextAlignmentCenter;
emptyInboxLabel.numberOfLines = 0;
emptyInboxLabel.lineBreakMode = NSLineBreakByWordWrapping;
UIStackView *emptyInboxStack = [[UIStackView alloc] initWithArrangedSubviews:@[
emptyInboxImageView,
emptyInboxLabel,
]];
emptyInboxStack.axis = UILayoutConstraintAxisVertical;
emptyInboxStack.alignment = UIStackViewAlignmentCenter;
emptyInboxStack.spacing = 12;
emptyInboxStack.layoutMargins = UIEdgeInsetsMake(50, 50, 50, 50);
emptyInboxStack.layoutMarginsRelativeArrangement = YES;
return emptyInboxStack;
}
- (void)createFirstConversationCueView
{
const CGFloat kTailWidth = 16.f;
const CGFloat kTailHeight = 8.f;
const CGFloat kTailHMargin = 12.f;
UILabel *label = [UILabel new];
label.textColor = UIColor.ows_whiteColor;
label.font = UIFont.ows_dynamicTypeBodyClampedFont;
label.numberOfLines = 0;
label.lineBreakMode = NSLineBreakByWordWrapping;
OWSLayerView *layerView = [OWSLayerView new];
layerView.layoutMargins = UIEdgeInsetsMake(11 + kTailHeight, 16, 7, 16);
CAShapeLayer *shapeLayer = [CAShapeLayer new];
shapeLayer.fillColor = [OWSConversationColor ows_wintergreenColor].CGColor;
[layerView.layer addSublayer:shapeLayer];
layerView.layoutCallback = ^(UIView *view) {
UIBezierPath *bezierPath = [UIBezierPath new];
// Bubble
CGRect bubbleBounds = view.bounds;
bubbleBounds.origin.y += kTailHeight;
bubbleBounds.size.height -= kTailHeight;
[bezierPath appendPath:[UIBezierPath bezierPathWithRoundedRect:bubbleBounds cornerRadius:8]];
// Tail
CGPoint tailTop = CGPointMake(kTailHMargin + kTailWidth * 0.5f, 0.f);
CGPoint tailLeft = CGPointMake(kTailHMargin, kTailHeight);
CGPoint tailRight = CGPointMake(kTailHMargin + kTailWidth, kTailHeight);
if (!CurrentAppContext().isRTL) {
tailTop.x = view.width - tailTop.x;
tailLeft.x = view.width - tailLeft.x;
tailRight.x = view.width - tailRight.x;
}
[bezierPath moveToPoint:tailTop];
[bezierPath addLineToPoint:tailLeft];
[bezierPath addLineToPoint:tailRight];
[bezierPath addLineToPoint:tailTop];
shapeLayer.path = bezierPath.CGPath;
shapeLayer.frame = view.bounds;
};
[layerView addSubview:label];
[label ows_autoPinToSuperviewMargins];
self.firstConversationCueView = layerView;
self.firstConversationLabel = label;
}
- (void)updateFirstConversationLabel
{
NSArray<SignalAccount *> *signalAccounts = self.contactsManager.signalAccounts;
NSString *formatString = @"";
NSMutableArray<NSString *> *contactNames = [NSMutableArray new];
if (signalAccounts.count >= 3) {
[contactNames addObject:[self.contactsManager displayNameForSignalAccount:signalAccounts[0]]];
[contactNames addObject:[self.contactsManager displayNameForSignalAccount:signalAccounts[1]]];
[contactNames addObject:[self.contactsManager displayNameForSignalAccount:signalAccounts[2]]];
formatString = NSLocalizedString(@"HOME_VIEW_FIRST_CONVERSATION_OFFER_3_CONTACTS_FORMAT",
@"Format string for a label offering to start a new conversation with your contacts, if you have at least "
@"3 Signal contacts. Embeds {{The names of 3 of your Signal contacts}}.");
} else if (signalAccounts.count == 2) {
[contactNames addObject:[self.contactsManager displayNameForSignalAccount:signalAccounts[0]]];
[contactNames addObject:[self.contactsManager displayNameForSignalAccount:signalAccounts[1]]];
formatString = NSLocalizedString(@"HOME_VIEW_FIRST_CONVERSATION_OFFER_2_CONTACTS_FORMAT",
@"Format string for a label offering to start a new conversation with your contacts, if you have 2 Signal "
@"contacts. Embeds {{The names of 2 of your Signal contacts}}.");
} else if (signalAccounts.count == 1) {
[contactNames addObject:[self.contactsManager displayNameForSignalAccount:signalAccounts[0]]];
formatString = NSLocalizedString(@"HOME_VIEW_FIRST_CONVERSATION_OFFER_1_CONTACT_FORMAT",
@"Format string for a label offering to start a new conversation with your contacts, if you have 1 Signal "
@"contact. Embeds {{The name of 1 of your Signal contacts}}.");
}
NSString *embedToken = @"%@";
NSArray<NSString *> *formatSplits = [formatString componentsSeparatedByString:embedToken];
// We need to use a complicated format string that possibly embeds multiple contact names.
// Translator error could easily lead to an invalid format string.
// We need to verify that it was translated properly.
BOOL isValidFormatString = (contactNames.count > 0 && formatSplits.count == contactNames.count + 1);
for (NSString *contactName in contactNames) {
if ([contactName containsString:embedToken]) {
isValidFormatString = NO;
}
}
NSMutableAttributedString *_Nullable attributedString = nil;
if (isValidFormatString) {
attributedString = [[NSMutableAttributedString alloc] initWithString:formatString];
while (contactNames.count > 0) {
NSString *contactName = contactNames.firstObject;
[contactNames removeObjectAtIndex:0];
NSRange range = [attributedString.string rangeOfString:embedToken];
if (range.location == NSNotFound) {
// Error
attributedString = nil;
break;
}
NSAttributedString *formattedName = [[NSAttributedString alloc]
initWithString:contactName
attributes:@{
NSFontAttributeName : self.firstConversationLabel.font.ows_mediumWeight,
}];
[attributedString replaceCharactersInRange:range withAttributedString:formattedName];
}
}
if (!attributedString) {
// The default case handles the no-contacts scenario and all error cases.
NSString *defaultText = NSLocalizedString(@"HOME_VIEW_FIRST_CONVERSATION_OFFER_NO_CONTACTS",
@"A label offering to start a new conversation with your contacts, if you have no Signal contacts.");
attributedString = [[NSMutableAttributedString alloc] initWithString:defaultText];
}
self.firstConversationLabel.attributedText = [attributedString copy];
}
- (void)updateReminderViews
{
self.archiveReminderView.hidden = self.homeViewMode != HomeViewMode_Archive;
@ -381,7 +554,7 @@ NSString *const kArchivedConversationsReuseIdentifier = @"kArchivedConversations
[self uiDatabaseConnection];
[self updateMappings];
[self checkIfEmptyView];
[self updateViewState];
[self updateReminderViews];
[self observeNotifications];
@ -637,7 +810,7 @@ NSString *const kArchivedConversationsReuseIdentifier = @"kArchivedConversations
}
}
[self checkIfEmptyView];
[self updateViewState];
[self applyDefaultBackButton];
if ([self updateHasArchivedThreadsRow]) {
[self.tableView reloadData];
@ -707,7 +880,7 @@ NSString *const kArchivedConversationsReuseIdentifier = @"kArchivedConversations
[self updateHasArchivedThreadsRow];
[self reloadTableViewData];
[self checkIfEmptyView];
[self updateViewState];
// If the user hasn't already granted contact access
// we don't want to request until they receive a message.
@ -722,7 +895,7 @@ NSString *const kArchivedConversationsReuseIdentifier = @"kArchivedConversations
- (void)applicationWillEnterForeground:(NSNotification *)notification
{
[self checkIfEmptyView];
[self updateViewState];
}
- (BOOL)hasAnyMessagesWithTransaction:(YapDatabaseReadTransaction *)transaction
@ -1149,7 +1322,7 @@ NSString *const kArchivedConversationsReuseIdentifier = @"kArchivedConversations
[thread removeWithTransaction:transaction];
}];
[self checkIfEmptyView];
[self updateViewState];
}
- (void)archiveIndexPath:(NSIndexPath *)indexPath
@ -1171,7 +1344,7 @@ NSString *const kArchivedConversationsReuseIdentifier = @"kArchivedConversations
break;
}
}];
[self checkIfEmptyView];
[self updateViewState];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
@ -1276,7 +1449,7 @@ NSString *const kArchivedConversationsReuseIdentifier = @"kArchivedConversations
[self resetMappings];
[self reloadTableViewData];
[self checkIfEmptyView];
[self updateViewState];
[self updateReminderViews];
}
@ -1327,7 +1500,7 @@ NSString *const kArchivedConversationsReuseIdentifier = @"kArchivedConversations
[self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
[self.threadMappings updateWithTransaction:transaction];
}];
[self checkIfEmptyView];
[self updateViewState];
return;
}
@ -1352,7 +1525,7 @@ NSString *const kArchivedConversationsReuseIdentifier = @"kArchivedConversations
// We want this regardless of if we're currently viewing the archive.
// So we run it before the early return
[self checkIfEmptyView];
[self updateViewState];
if ([sectionChanges count] == 0 && [rowChanges count] == 0) {
return;
@ -1439,73 +1612,21 @@ NSString *const kArchivedConversationsReuseIdentifier = @"kArchivedConversations
return [self numberOfThreadsInGroup:TSArchiveGroup];
}
- (void)checkIfEmptyView
- (void)updateViewState
{
NSUInteger inboxCount = self.numberOfInboxThreads;
NSUInteger archiveCount = self.numberOfArchivedThreads;
if (self.homeViewMode == HomeViewMode_Inbox && inboxCount == 0 && archiveCount == 0) {
[self updateEmptyBoxText];
[_tableView setHidden:YES];
[_emptyBoxLabel setHidden:NO];
} else if (self.homeViewMode == HomeViewMode_Archive && archiveCount == 0) {
[self updateEmptyBoxText];
[_tableView setHidden:YES];
[_emptyBoxLabel setHidden:NO];
[self.emptyInboxView setHidden:NO];
[self updateFirstConversationLabel];
} else {
[_emptyBoxLabel setHidden:YES];
[_tableView setHidden:NO];
[self.emptyInboxView setHidden:YES];
}
}
- (void)updateEmptyBoxText
{
// TODO: Theme, review with design.
_emptyBoxLabel.textColor = [UIColor grayColor];
_emptyBoxLabel.font = [UIFont ows_regularFontWithSize:18.f];
_emptyBoxLabel.textAlignment = NSTextAlignmentCenter;
NSString *firstLine = @"";
NSString *secondLine = @"";
if (self.homeViewMode == HomeViewMode_Inbox) {
if ([Environment.shared.preferences hasSentAMessage]) {
firstLine = NSLocalizedString(
@"EMPTY_INBOX_TITLE", @"Header text an existing user sees when viewing an empty inbox");
secondLine = NSLocalizedString(
@"EMPTY_INBOX_TEXT", @"Body text an existing user sees when viewing an empty inbox");
} else {
firstLine = NSLocalizedString(
@"EMPTY_INBOX_NEW_USER_TITLE", @"Header text a new user sees when viewing an empty inbox");
secondLine = NSLocalizedString(
@"EMPTY_INBOX_NEW_USER_TEXT", @"Body text a new user sees when viewing an empty inbox");
}
} else {
OWSAssertDebug(self.homeViewMode == HomeViewMode_Archive);
firstLine = NSLocalizedString(
@"EMPTY_ARCHIVE_TITLE", @"Header text an existing user sees when viewing an empty archive");
secondLine = NSLocalizedString(
@"EMPTY_ARCHIVE_TEXT", @"Body text an existing user sees when viewing an empty archive");
}
NSMutableAttributedString *fullLabelString =
[[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@"%@\n%@", firstLine, secondLine]];
[fullLabelString addAttribute:NSFontAttributeName
value:[UIFont ows_boldFontWithSize:15.f]
range:NSMakeRange(0, firstLine.length)];
[fullLabelString addAttribute:NSFontAttributeName
value:[UIFont ows_regularFontWithSize:14.f]
range:NSMakeRange(firstLine.length + 1, secondLine.length)];
[fullLabelString addAttribute:NSForegroundColorAttributeName
value:Theme.primaryColor
range:NSMakeRange(0, firstLine.length)];
// TODO: Theme, Review with design.
[fullLabelString addAttribute:NSForegroundColorAttributeName
value:Theme.secondaryColor
range:NSMakeRange(firstLine.length + 1, secondLine.length)];
_emptyBoxLabel.attributedText = fullLabelString;
}
// We want to delay asking for a review until an opportune time.
// If the user has *just* launched Signal they intend to do something, we don't want to interrupt them.
// If the user hasn't sent a message, we don't want to ask them for a review yet.

@ -1,5 +1,5 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
//
#import "RemoteVideoView.h"
@ -104,7 +104,6 @@ NS_ASSUME_NONNULL_BEGIN
}
CGFloat aspectRatio = remoteVideoSize.width / remoteVideoSize.height;
OWSLogVerbose(@"Remote video size: width: %f height: %f ratio: %f",
remoteVideoSize.width,
remoteVideoSize.height,
@ -125,7 +124,7 @@ NS_ASSUME_NONNULL_BEGIN
// to approximate "scale to fill" contentMode
// - Pin aspect ratio
// - Width and height is *at least* as wide as superview
[constraints addObject:[videoView autoPinToAspectRatio:aspectRatio]];
[constraints addObject:[videoView autoPinToAspectRatioWithSize:remoteVideoSize]];
[constraints addObject:[videoView autoSetDimension:ALDimensionWidth
toSize:containingView.width
relation:NSLayoutRelationGreaterThanOrEqual]];

@ -819,30 +819,12 @@
/* subject of email sent to contacts when inviting to install Signal */
"EMAIL_INVITE_SUBJECT" = "Let's switch to Signal";
/* Body text an existing user sees when viewing an empty archive */
"EMPTY_ARCHIVE_TEXT" = "You can archive inactive conversations from your Inbox.";
/* Header text an existing user sees when viewing an empty archive */
"EMPTY_ARCHIVE_TITLE" = "Clean Up Your Conversation List";
/* Full width label displayed when attempting to compose message */
"EMPTY_CONTACTS_LABEL_LINE1" = "None of your contacts have Signal.";
/* Full width label displayed when attempting to compose message */
"EMPTY_CONTACTS_LABEL_LINE2" = "Why don't you invite someone?";
/* Body text a new user sees when viewing an empty inbox */
"EMPTY_INBOX_NEW_USER_TEXT" = "Tap on the compose button";
/* Header text a new user sees when viewing an empty inbox */
"EMPTY_INBOX_NEW_USER_TITLE" = "Start your first Signal conversation!";
/* Body text an existing user sees when viewing an empty inbox */
"EMPTY_INBOX_TEXT" = "None. Zip. Zilch. Nada.";
/* Header text an existing user sees when viewing an empty inbox */
"EMPTY_INBOX_TITLE" = "Inbox Zero";
/* Indicates that user should confirm their 'two factor auth pin'. */
"ENABLE_2FA_VIEW_CONFIRM_PIN_INSTRUCTIONS" = "Confirm your PIN.";
@ -1074,6 +1056,18 @@
/* Placeholder text for search bar which filters conversations. */
"HOME_VIEW_CONVERSATION_SEARCHBAR_PLACEHOLDER" = "Search";
/* Format string for a label offering to start a new conversation with your contacts, if you have 1 Signal contact. Embeds: {{The name of 1 of your Signal contacts}}. */
"HOME_VIEW_FIRST_CONVERSATION_OFFER_1_CONTACT_FORMAT" = "Some of your contacts are already on Signal, including %@.";
/* Format string for a label offering to start a new conversation with your contacts, if you have 2 Signal contacts. Embeds: {{The names of 2 of your Signal contacts}}. */
"HOME_VIEW_FIRST_CONVERSATION_OFFER_2_CONTACTS_FORMAT" = "Some of your contacts are already on Signal, including %@ and %@";
/* Format string for a label offering to start a new conversation with your contacts, if you have at least 3 Signal contacts. Embeds: {{The names of 3 of your Signal contacts}}. */
"HOME_VIEW_FIRST_CONVERSATION_OFFER_3_CONTACTS_FORMAT" = "Some of your contacts are already on Signal, including %@, %@ and %@";
/* A label offering to start a new conversation with your contacts, if you have no Signal contacts. */
"HOME_VIEW_FIRST_CONVERSATION_OFFER_NO_CONTACTS" = "Start your first conversation here.";
/* Format string when search returns no results. Embeds {{search term}} */
"HOME_VIEW_SEARCH_NO_RESULTS_FORMAT" = "No results found for '%@'";
@ -1122,6 +1116,9 @@
/* Label reminding the user that they are in archive mode. */
"INBOX_VIEW_ARCHIVE_MODE_REMINDER" = "These conversations are archived and will only appear in the Inbox if new messages are received.";
/* Message shown in the home view when the inbox is empty. */
"INBOX_VIEW_EMPTY_INBOX" = "Give your inbox something to write home about. Get started by messaging a friend.";
/* Multi-line label explaining how to show names instead of phone numbers in your inbox */
"INBOX_VIEW_MISSING_CONTACTS_PERMISSION" = "You can enable contacts access in the iOS Settings app to see contact names in your Signal conversation list.";

@ -41,6 +41,7 @@ CGFloat ScaleFromIPhone5(CGFloat iPhone5Value);
- (void)autoPinHeightToHeightOfView:(UIView *)view;
- (NSLayoutConstraint *)autoPinToSquareAspectRatio;
- (NSLayoutConstraint *)autoPinToAspectRatioWithSize:(CGSize)size;
- (NSLayoutConstraint *)autoPinToAspectRatio:(CGFloat)ratio;
#pragma mark - Content Hugging and Compression Resistance

@ -142,6 +142,10 @@ CGFloat ScaleFromIPhone5(CGFloat iPhone5Value)
return [self autoPinToAspectRatio:1.0];
}
- (NSLayoutConstraint *)autoPinToAspectRatioWithSize:(CGSize)size {
return [self autoPinToAspectRatio:size.width / size.height];
}
- (NSLayoutConstraint *)autoPinToAspectRatio:(CGFloat)ratio
{
// Clamp to ensure view has reasonable aspect ratio.

Loading…
Cancel
Save