diff --git a/Signal/Images.xcassets/settings-avatar-camera.imageset/Contents.json b/Signal/Images.xcassets/settings-avatar-camera.imageset/Contents.json new file mode 100644 index 0000000000..c83f5f652a --- /dev/null +++ b/Signal/Images.xcassets/settings-avatar-camera.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "settings-avatar-camera@1x.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "settings-avatar-camera@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "settings-avatar-camera@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Signal/Images.xcassets/settings-avatar-camera.imageset/settings-avatar-camera@1x.png b/Signal/Images.xcassets/settings-avatar-camera.imageset/settings-avatar-camera@1x.png new file mode 100644 index 0000000000..65739dcc2d Binary files /dev/null and b/Signal/Images.xcassets/settings-avatar-camera.imageset/settings-avatar-camera@1x.png differ diff --git a/Signal/Images.xcassets/settings-avatar-camera.imageset/settings-avatar-camera@2x.png b/Signal/Images.xcassets/settings-avatar-camera.imageset/settings-avatar-camera@2x.png new file mode 100644 index 0000000000..9b500eb96e Binary files /dev/null and b/Signal/Images.xcassets/settings-avatar-camera.imageset/settings-avatar-camera@2x.png differ diff --git a/Signal/Images.xcassets/settings-avatar-camera.imageset/settings-avatar-camera@3x.png b/Signal/Images.xcassets/settings-avatar-camera.imageset/settings-avatar-camera@3x.png new file mode 100644 index 0000000000..414c97c745 Binary files /dev/null and b/Signal/Images.xcassets/settings-avatar-camera.imageset/settings-avatar-camera@3x.png differ diff --git a/Signal/src/Profiles/OWSProfileManager.m b/Signal/src/Profiles/OWSProfileManager.m index 6e7b2508fc..78c75a7233 100644 --- a/Signal/src/Profiles/OWSProfileManager.m +++ b/Signal/src/Profiles/OWSProfileManager.m @@ -1011,10 +1011,11 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640; - (nullable NSData *)encryptProfileNameWithUnpaddedName:(NSString *)name { - if (name.length == 0) { - return nil; - } - + // TODO: Should this be nil or a padded-out empty string? + // if (name.length == 0) { + // return nil; + // } + NSData *nameData = [name dataUsingEncoding:NSUTF8StringEncoding]; if (nameData.length > kOWSProfileManager_NameDataLength) { OWSFail(@"%@ name data is too long with length:%lu", self.tag, (unsigned long)nameData.length); diff --git a/Signal/src/ViewControllers/AppSettingsViewController.m b/Signal/src/ViewControllers/AppSettingsViewController.m index 5eeae8abcc..fd1b6366ce 100644 --- a/Signal/src/ViewControllers/AppSettingsViewController.m +++ b/Signal/src/ViewControllers/AppSettingsViewController.m @@ -97,41 +97,14 @@ OWSTableSection *section = [OWSTableSection new]; __weak AppSettingsViewController *weakSelf = self; + [section addItem:[OWSTableItem itemWithCustomCellBlock:^{ - UITableViewCell *cell = [UITableViewCell new]; - cell.preservesSuperviewLayoutMargins = YES; - cell.contentView.preservesSuperviewLayoutMargins = YES; - - UILabel *titleLabel = [UILabel new]; - titleLabel.font = [UIFont ows_mediumFontWithSize:20.f]; - titleLabel.textColor = [UIColor blackColor]; - titleLabel.text = NSLocalizedString(@"REGISTERED_NUMBER_TEXT", @""); - titleLabel.textAlignment = NSTextAlignmentCenter; - - UILabel *subtitleLabel = [UILabel new]; - subtitleLabel.font = [UIFont ows_mediumFontWithSize:15.f]; - subtitleLabel.textColor = [UIColor colorWithWhite:0.5f alpha:1.f]; - subtitleLabel.text = - [PhoneNumber bestEffortFormatPartialUserSpecifiedTextToLookLikeAPhoneNumber:[TSAccountManager localNumber]]; - subtitleLabel.textAlignment = NSTextAlignmentCenter; - - UIView *stack = [UIView new]; - [cell.contentView addSubview:stack]; - [stack autoCenterInSuperview]; - - [stack addSubview:titleLabel]; - [stack addSubview:subtitleLabel]; - [titleLabel autoPinWidthToSuperview]; - [subtitleLabel autoPinWidthToSuperview]; - [titleLabel autoPinEdgeToSuperviewEdge:ALEdgeTop]; - [subtitleLabel autoPinEdgeToSuperviewEdge:ALEdgeBottom]; - [subtitleLabel autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:titleLabel]; - - cell.selectionStyle = UITableViewCellSelectionStyleNone; - return cell; + return [weakSelf profileHeaderCell]; } - customRowHeight:96.f - actionBlock:nil]]; + customRowHeight:100.f + actionBlock:^{ + [weakSelf showProfile]; + }]]; if (OWSSignalService.sharedInstance.isCensorshipCircumventionActive) { [section @@ -171,12 +144,6 @@ actionBlock:nil]]; } - [section addItem:[OWSTableItem - disclosureItemWithText:NSLocalizedString(@"PROFILE_VIEW_TITLE", @"Title for the profile view.") - actionBlock:^{ - [weakSelf showProfile]; - }]]; - [section addItem:[OWSTableItem disclosureItemWithText:NSLocalizedString(@"SETTINGS_INVITE_TITLE", @"Settings table view cell label") actionBlock:^{ @@ -238,6 +205,89 @@ self.contents = contents; } +- (UITableViewCell *)profileHeaderCell +{ + UITableViewCell *cell = [UITableViewCell new]; + cell.preservesSuperviewLayoutMargins = YES; + cell.contentView.preservesSuperviewLayoutMargins = YES; + cell.selectionStyle = UITableViewCellSelectionStyleNone; + + const NSUInteger kAvatarSize = 68; + // TODO: Replace this icon. + UIImage *_Nullable localProfileAvatarImage = [OWSProfileManager.sharedManager localProfileAvatarImage]; + UIImage *avatarImage = (localProfileAvatarImage + ?: [[UIImage imageNamed:@"profile_avatar_default"] + imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]); + OWSAssert(avatarImage); + + AvatarImageView *avatarView = [[AvatarImageView alloc] initWithImage:avatarImage]; + if (!localProfileAvatarImage) { + avatarView.tintColor = [UIColor colorWithRGBHex:0x888888]; + } + [cell.contentView addSubview:avatarView]; + [avatarView autoVCenterInSuperview]; + [avatarView autoPinLeadingToSuperView]; + [avatarView autoSetDimension:ALDimensionWidth toSize:kAvatarSize]; + [avatarView autoSetDimension:ALDimensionHeight toSize:kAvatarSize]; + + if (!localProfileAvatarImage) { + UIImage *cameraImage = [UIImage imageNamed:@"settings-avatar-camera"]; + cameraImage = [cameraImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + UIImageView *cameraImageView = [[UIImageView alloc] initWithImage:cameraImage]; + cameraImageView.tintColor = [UIColor ows_materialBlueColor]; + [cell.contentView addSubview:cameraImageView]; + [cameraImageView autoPinTrailingToView:avatarView]; + [cameraImageView autoPinEdge:ALEdgeBottom toEdge:ALEdgeBottom ofView:avatarView]; + } + + UIView *nameView = [UIView containerView]; + [cell.contentView addSubview:nameView]; + [nameView autoVCenterInSuperview]; + [nameView autoPinLeadingToTrailingOfView:avatarView margin:16.f]; + + UILabel *titleLabel = [UILabel new]; + NSString *_Nullable localProfileName = [OWSProfileManager.sharedManager localProfileName]; + if (localProfileName.length > 0) { + titleLabel.text = localProfileName; + titleLabel.textColor = [UIColor blackColor]; + titleLabel.font = [UIFont ows_dynamicTypeTitle2Font]; + } else { + titleLabel.text = NSLocalizedString( + @"APP_SETTINGS_EDIT_PROFILE_NAME_PROMPT", @"Text prompting user to edit their profile name."); + titleLabel.textColor = [UIColor ows_materialBlueColor]; + titleLabel.font = [UIFont ows_dynamicTypeHeadlineFont]; + } + titleLabel.lineBreakMode = NSLineBreakByTruncatingTail; + [nameView addSubview:titleLabel]; + [titleLabel autoPinEdgeToSuperviewEdge:ALEdgeTop]; + [titleLabel autoPinWidthToSuperview]; + + const CGFloat kSubtitlePointSize = 12.f; + UILabel *subtitleLabel = [UILabel new]; + subtitleLabel.textColor = [UIColor ows_darkGrayColor]; + subtitleLabel.font = [UIFont ows_regularFontWithSize:kSubtitlePointSize]; + subtitleLabel.attributedText = [[NSAttributedString alloc] + initWithString:[PhoneNumber bestEffortFormatPartialUserSpecifiedTextToLookLikeAPhoneNumber:[TSAccountManager + localNumber]]]; + subtitleLabel.lineBreakMode = NSLineBreakByTruncatingTail; + [nameView addSubview:subtitleLabel]; + [subtitleLabel autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:titleLabel]; + [subtitleLabel autoPinLeadingToSuperView]; + [subtitleLabel autoPinEdgeToSuperviewEdge:ALEdgeBottom]; + + UIImage *disclosureImage = [UIImage imageNamed:(self.view.isRTL ? @"NavBarBack" : @"NavBarBackRTL")]; + OWSAssert(disclosureImage); + UIImageView *disclosureButton = + [[UIImageView alloc] initWithImage:[disclosureImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]]; + disclosureButton.tintColor = [UIColor colorWithRGBHex:0xcccccc]; + [cell.contentView addSubview:disclosureButton]; + [disclosureButton autoVCenterInSuperview]; + [disclosureButton autoPinTrailingToSuperView]; + [disclosureButton autoPinLeadingToTrailingOfView:nameView margin:16.f]; + + return cell; +} + - (void)showInviteFlow { OWSInviteFlow *inviteFlow = diff --git a/Signal/src/ViewControllers/ProfileViewController.m b/Signal/src/ViewControllers/ProfileViewController.m index d0b51a7b95..671b3f48bf 100644 --- a/Signal/src/ViewControllers/ProfileViewController.m +++ b/Signal/src/ViewControllers/ProfileViewController.m @@ -21,6 +21,8 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic) AvatarImageView *avatarView; +@property (nonatomic) UIImageView *cameraImageView; + @property (nonatomic) UILabel *avatarLabel; @property (nonatomic, nullable) UIImage *avatar; @@ -64,6 +66,11 @@ NS_ASSUME_NONNULL_BEGIN _avatarView = [AvatarImageView new]; + UIImage *cameraImage = [UIImage imageNamed:@"settings-avatar-camera"]; + cameraImage = [cameraImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + _cameraImageView = [[UIImageView alloc] initWithImage:cameraImage]; + _cameraImageView.tintColor = [UIColor ows_materialBlueColor]; + _avatarLabel = [UILabel new]; _avatarLabel.font = [UIFont ows_regularFontWithSize:14.f]; _avatarLabel.textColor = [UIColor ows_materialBlueColor]; @@ -99,12 +106,16 @@ NS_ASSUME_NONNULL_BEGIN cell.contentView.preservesSuperviewLayoutMargins = YES; AvatarImageView *avatarView = weakSelf.avatarView; - [weakSelf updateAvatarView]; + UIImageView *cameraImageView = weakSelf.cameraImageView; [cell.contentView addSubview:avatarView]; + [cell.contentView addSubview:cameraImageView]; + [weakSelf updateAvatarView]; [avatarView autoHCenterInSuperview]; [avatarView autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:kAvatarTopMargin]; [avatarView autoSetDimension:ALDimensionWidth toSize:kAvatarSizePoints]; [avatarView autoSetDimension:ALDimensionHeight toSize:kAvatarSizePoints]; + [cameraImageView autoPinTrailingToView:avatarView]; + [cameraImageView autoPinEdge:ALEdgeBottom toEdge:ALEdgeBottom ofView:avatarView]; UILabel *avatarLabel = weakSelf.avatarLabel; [cell.contentView addSubview:avatarLabel]; @@ -265,7 +276,11 @@ NS_ASSUME_NONNULL_BEGIN - (void)updateAvatarView { - self.avatarView.image = (self.avatar ?: [UIImage imageNamed:@"profile_avatar_default"]); + self.avatarView.image = (self.avatar + ?: [[UIImage imageNamed:@"profile_avatar_default"] + imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]); + self.avatarView.tintColor = (self.avatar ? nil : [UIColor colorWithRGBHex:0x888888]); + self.cameraImageView.hidden = self.avatar != nil; } #pragma mark - AvatarViewHelperDelegate diff --git a/Signal/src/util/UIFont+OWS.h b/Signal/src/util/UIFont+OWS.h index 9547bda51e..5eb182256c 100644 --- a/Signal/src/util/UIFont+OWS.h +++ b/Signal/src/util/UIFont+OWS.h @@ -26,6 +26,7 @@ + (UIFont *)ows_dynamicTypeBodyFont; + (UIFont *)ows_dynamicTypeTitle2Font; ++ (UIFont *)ows_dynamicTypeHeadlineFont; + (UIFont *)ows_infoMessageFont; + (UIFont *)ows_footnoteFont; diff --git a/Signal/src/util/UIFont+OWS.m b/Signal/src/util/UIFont+OWS.m index 228d8564f0..edf0ca36ae 100644 --- a/Signal/src/util/UIFont+OWS.m +++ b/Signal/src/util/UIFont+OWS.m @@ -87,4 +87,14 @@ } } ++ (UIFont *)ows_dynamicTypeHeadlineFont +{ + if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(9, 0)) { + return [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline]; + } else { + // See ows_dynamicTypeTitle2Font. + return [self ows_regularFontWithSize:17.0]; + } +} + @end diff --git a/Signal/translations/en.lproj/Localizable.strings b/Signal/translations/en.lproj/Localizable.strings index 1d4934e52b..2789571a43 100644 --- a/Signal/translations/en.lproj/Localizable.strings +++ b/Signal/translations/en.lproj/Localizable.strings @@ -61,6 +61,9 @@ /* No comment provided by engineer. */ "APN_MESSAGE_IN_GROUP_DETAILED" = "%@ in group %@: %@"; +/* Text prompting user to edit their profile name. */ +"APP_SETTINGS_EDIT_PROFILE_NAME_PROMPT" = "Enter your name"; + /* Message format for the 'new app version available' alert. Embeds: {{The latest app version number.}}. */ "APP_UPDATE_NAG_ALERT_MESSAGE_FORMAT" = "Version %@ is now available in the App Store."; @@ -1120,9 +1123,6 @@ /* No comment provided by engineer. */ "REGISTER_RATE_LIMITING_BODY" = "You have tried too often. Please wait a minute before trying again."; -/* No comment provided by engineer. */ -"REGISTERED_NUMBER_TEXT" = "Registered Number"; - /* Title of alert shown when push tokens sync job fails. */ "REGISTRATION_BODY" = "Failed to re-register for push notifications.";