Rework the profile view.

// FREEBIE
pull/1/head
Matthew Chen 8 years ago
parent 3181ee7882
commit 020d2c567a

@ -2,13 +2,11 @@
// Copyright (c) 2017 Open Whisper Systems. All rights reserved. // Copyright (c) 2017 Open Whisper Systems. All rights reserved.
// //
#import "OWSTableViewController.h"
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
@class SignalsViewController; @class SignalsViewController;
@interface ProfileViewController : OWSTableViewController @interface ProfileViewController : UIViewController
- (instancetype)init NS_UNAVAILABLE; - (instancetype)init NS_UNAVAILABLE;

@ -38,6 +38,8 @@ NSString *const kProfileView_LastPresentedDate = @"kProfileView_LastPresentedDat
@property (nonatomic) UIImageView *cameraImageView; @property (nonatomic) UIImageView *cameraImageView;
@property (nonatomic) UIButton *skipOrSaveButton;
@property (nonatomic, nullable) UIImage *avatar; @property (nonatomic, nullable) UIImage *avatar;
@property (nonatomic) BOOL hasUnsavedChanges; @property (nonatomic) BOOL hasUnsavedChanges;
@ -72,7 +74,6 @@ NSString *const kProfileView_LastPresentedDate = @"kProfileView_LastPresentedDat
{ {
[super loadView]; [super loadView];
self.view.backgroundColor = [UIColor whiteColor];
[self.navigationController.navigationBar setTranslucent:NO]; [self.navigationController.navigationBar setTranslucent:NO];
self.title = NSLocalizedString(@"PROFILE_VIEW_TITLE", @"Title for the profile view."); self.title = NSLocalizedString(@"PROFILE_VIEW_TITLE", @"Title for the profile view.");
@ -87,145 +88,175 @@ NSString *const kProfileView_LastPresentedDate = @"kProfileView_LastPresentedDat
- (void)createViews - (void)createViews
{ {
_nameTextField = [UITextField new]; self.view.backgroundColor = [UIColor colorWithRGBHex:0xefeff4];
_nameTextField.font = [UIFont ows_mediumFontWithSize:18.f];
_nameTextField.textColor = [UIColor ows_materialBlueColor]; UIView *contentView = [UIView containerView];
_nameTextField.placeholder = NSLocalizedString( contentView.backgroundColor = [UIColor whiteColor];
@"PROFILE_VIEW_NAME_DEFAULT_TEXT", @"Default text for the profile name field of the profile view."); [self.view addSubview:contentView];
_nameTextField.delegate = self; [contentView autoPinEdgeToSuperviewEdge:ALEdgeTop];
_nameTextField.text = [OWSProfileManager.sharedManager localProfileName]; [contentView autoPinWidthToSuperview];
[_nameTextField addTarget:self action:@selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];
_avatarView = [AvatarImageView new]; const CGFloat fontSizePoints = ScaleFromIPhone5To7Plus(16.f, 20.f);
NSMutableArray<UIView *> *rows = [NSMutableArray new];
// Name
UIView *nameRow = [UIView containerView];
nameRow.userInteractionEnabled = YES;
[nameRow
addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(nameRowTapped:)]];
[rows addObject:nameRow];
UILabel *nameLabel = [UILabel new];
nameLabel.text = NSLocalizedString(
@"PROFILE_VIEW_PROFILE_NAME_FIELD", @"Label for the profile name field of the profile view.");
nameLabel.textColor = [UIColor blackColor];
nameLabel.font = [UIFont ows_mediumFontWithSize:fontSizePoints];
[nameRow addSubview:nameLabel];
[nameLabel autoPinLeadingToSuperView];
[nameLabel autoPinHeightToSuperviewWithMargin:5.f];
UITextField *nameTextField = [UITextField new];
_nameTextField = nameTextField;
nameTextField.font = [UIFont ows_mediumFontWithSize:18.f];
nameTextField.textColor = [UIColor ows_materialBlueColor];
nameTextField.placeholder = NSLocalizedString(
@"PROFILE_VIEW_NAME_DEFAULT_TEXT", @"Default text for the profile name field of the profile view.");
nameTextField.delegate = self;
nameTextField.text = [OWSProfileManager.sharedManager localProfileName];
nameTextField.textAlignment = NSTextAlignmentRight;
nameTextField.font = [UIFont ows_mediumFontWithSize:fontSizePoints];
[nameTextField addTarget:self action:@selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];
[nameRow addSubview:nameTextField];
[nameTextField autoPinLeadingToTrailingOfView:nameLabel margin:10.f];
[nameTextField autoPinTrailingToSuperView];
[nameTextField autoVCenterInSuperview];
// Avatar
UIView *avatarRow = [UIView containerView];
[rows addObject:avatarRow];
UILabel *avatarLabel = [UILabel new];
avatarLabel.text = NSLocalizedString(
@"PROFILE_VIEW_PROFILE_AVATAR_FIELD", @"Label for the profile avatar field of the profile view.");
avatarLabel.textColor = [UIColor blackColor];
avatarLabel.font = [UIFont ows_mediumFontWithSize:fontSizePoints];
[avatarRow addSubview:avatarLabel];
[avatarLabel autoPinLeadingToSuperView];
[avatarLabel autoVCenterInSuperview];
self.avatarView = [AvatarImageView new];
UIImage *cameraImage = [UIImage imageNamed:@"settings-avatar-camera"]; UIImage *cameraImage = [UIImage imageNamed:@"settings-avatar-camera"];
cameraImage = [cameraImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; cameraImage = [cameraImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
_cameraImageView = [[UIImageView alloc] initWithImage:cameraImage]; self.cameraImageView = [[UIImageView alloc] initWithImage:cameraImage];
_cameraImageView.tintColor = [UIColor ows_materialBlueColor]; self.cameraImageView.tintColor = [UIColor ows_materialBlueColor];
[self updateTableContents];
}
#pragma mark - Table Contents
- (void)updateTableContents
{
OWSTableContents *contents = [OWSTableContents new];
__weak ProfileViewController *weakSelf = self;
// Profile Avatar
OWSTableSection *section = [OWSTableSection new];
const CGFloat fontSizePoints = ScaleFromIPhone5To7Plus(16.f, 20.f);
[section addItem:[OWSTableItem itemWithCustomCellBlock:^{
UITableViewCell *cell = [UITableViewCell new];
cell.preservesSuperviewLayoutMargins = YES;
cell.contentView.preservesSuperviewLayoutMargins = YES;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
UILabel *fieldLabel = [UILabel new];
fieldLabel.text = NSLocalizedString(
@"PROFILE_VIEW_PROFILE_NAME_FIELD", @"Label for the profile name field of the profile view.");
fieldLabel.textColor = [UIColor blackColor];
fieldLabel.font = [UIFont ows_mediumFontWithSize:fontSizePoints];
[cell.contentView addSubview:fieldLabel];
[fieldLabel autoPinLeadingToSuperView];
[fieldLabel autoVCenterInSuperview];
UITextField *nameTextField = weakSelf.nameTextField;
nameTextField.textAlignment = NSTextAlignmentRight;
nameTextField.font = [UIFont ows_mediumFontWithSize:fontSizePoints];
[cell.contentView addSubview:nameTextField];
[nameTextField autoPinLeadingToTrailingOfView:fieldLabel margin:10.f];
[nameTextField autoPinTrailingToSuperView];
[nameTextField autoVCenterInSuperview];
return cell;
}
actionBlock:^{
[weakSelf.nameTextField becomeFirstResponder];
}]];
[avatarRow addSubview:self.avatarView];
[avatarRow addSubview:self.cameraImageView];
[self updateAvatarView];
[self.avatarView autoPinTrailingToSuperView];
[self.avatarView autoPinLeadingToTrailingOfView:avatarLabel margin:10.f];
const CGFloat kAvatarSizePoints = 50.f; const CGFloat kAvatarSizePoints = 50.f;
const CGFloat kAvatarVMargin = 4.f; const CGFloat kAvatarVMargin = 4.f;
CGFloat avatarCellHeight = round(kAvatarSizePoints + kAvatarVMargin * 2); [self.avatarView autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:kAvatarVMargin];
[section addItem:[OWSTableItem itemWithCustomCellBlock:^{ [self.avatarView autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:kAvatarVMargin];
UITableViewCell *cell = [UITableViewCell new]; [self.avatarView autoSetDimension:ALDimensionWidth toSize:kAvatarSizePoints];
cell.preservesSuperviewLayoutMargins = YES; [self.avatarView autoSetDimension:ALDimensionHeight toSize:kAvatarSizePoints];
cell.contentView.preservesSuperviewLayoutMargins = YES; [self.cameraImageView autoPinTrailingToView:self.avatarView];
cell.selectionStyle = UITableViewCellSelectionStyleNone; [self.cameraImageView autoPinEdge:ALEdgeBottom toEdge:ALEdgeBottom ofView:self.avatarView];
UILabel *fieldLabel = [UILabel new]; // Information
fieldLabel.text = NSLocalizedString(
@"PROFILE_VIEW_PROFILE_AVATAR_FIELD", @"Label for the profile avatar field of the profile view."); UIView *infoRow = [UIView containerView];
fieldLabel.textColor = [UIColor blackColor]; infoRow.userInteractionEnabled = YES;
fieldLabel.font = [UIFont ows_mediumFontWithSize:fontSizePoints]; [infoRow
[cell.contentView addSubview:fieldLabel]; addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(infoRowTapped:)]];
[fieldLabel autoPinLeadingToSuperView]; [rows addObject:infoRow];
[fieldLabel autoVCenterInSuperview];
UILabel *infoLabel = [UILabel new];
AvatarImageView *avatarView = weakSelf.avatarView; infoLabel.textColor = [UIColor ows_darkGrayColor];
UIImageView *cameraImageView = weakSelf.cameraImageView; infoLabel.font = [UIFont ows_footnoteFont];
[cell.contentView addSubview:avatarView]; infoLabel.textAlignment = NSTextAlignmentCenter;
[cell.contentView addSubview:cameraImageView]; NSMutableAttributedString *text = [NSMutableAttributedString new];
[weakSelf updateAvatarView]; [text appendAttributedString:[[NSAttributedString alloc]
[avatarView autoPinTrailingToSuperView]; initWithString:NSLocalizedString(@"PROFILE_VIEW_PROFILE_DESCRIPTION",
[avatarView autoPinLeadingToTrailingOfView:fieldLabel margin:10.f]; @"Description of the user profile.")
attributes:@{}]];
[avatarView autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:kAvatarVMargin]; [text appendAttributedString:[[NSAttributedString alloc] initWithString:@" " attributes:@{}]];
[avatarView autoSetDimension:ALDimensionWidth toSize:kAvatarSizePoints]; [text appendAttributedString:[[NSAttributedString alloc]
[avatarView autoSetDimension:ALDimensionHeight toSize:kAvatarSizePoints]; initWithString:NSLocalizedString(@"PROFILE_VIEW_PROFILE_DESCRIPTION_LINK",
[cameraImageView autoPinTrailingToView:avatarView]; @"Link to more information about the user profile.")
[cameraImageView autoPinEdge:ALEdgeBottom toEdge:ALEdgeBottom ofView:avatarView]; attributes:@{
NSUnderlineStyleAttributeName :
return cell; @(NSUnderlineStyleSingle | NSUnderlinePatternSolid),
NSForegroundColorAttributeName : [UIColor ows_materialBlueColor],
}]];
infoLabel.attributedText = text;
infoLabel.numberOfLines = 0;
infoLabel.lineBreakMode = NSLineBreakByWordWrapping;
[infoRow addSubview:infoLabel];
[infoLabel autoPinLeadingToSuperView];
[infoLabel autoPinTrailingToSuperView];
[infoLabel autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:10.f];
[infoLabel autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:10.f];
// Big Button
if (self.profileViewMode == ProfileViewMode_Registration) {
UIView *buttonRow = [UIView containerView];
[rows addObject:buttonRow];
UIButton *skipOrSaveButton = [UIButton buttonWithType:UIButtonTypeCustom];
self.skipOrSaveButton = skipOrSaveButton;
skipOrSaveButton.backgroundColor = [UIColor ows_signalBrandBlueColor];
[skipOrSaveButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
skipOrSaveButton.titleLabel.font = [UIFont ows_boldFontWithSize:fontSizePoints];
[skipOrSaveButton setContentHorizontalAlignment:UIControlContentHorizontalAlignmentCenter];
[skipOrSaveButton setContentVerticalAlignment:UIControlContentVerticalAlignmentCenter];
[buttonRow addSubview:skipOrSaveButton];
[skipOrSaveButton autoPinLeadingAndTrailingToSuperview];
[skipOrSaveButton autoPinHeightToSuperview];
[skipOrSaveButton autoSetDimension:ALDimensionHeight toSize:47.f];
[skipOrSaveButton addTarget:self
action:@selector(skipOrSaveButtonPressed)
forControlEvents:UIControlEventTouchUpInside];
} }
customRowHeight:avatarCellHeight
actionBlock:^{ // Row Layout
[weakSelf avatarTapped];
}]]; UIView *_Nullable lastRow = nil;
UIFont *footnoteFont = [UIFont ows_footnoteFont]; for (UIView *row in rows) {
[section addItem:[OWSTableItem itemWithCustomCellBlock:^{ [contentView addSubview:row];
UITableViewCell *cell = [UITableViewCell new]; if (lastRow) {
cell.preservesSuperviewLayoutMargins = YES; [row autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:lastRow withOffset:5.f];
cell.contentView.preservesSuperviewLayoutMargins = YES; } else {
cell.selectionStyle = UITableViewCellSelectionStyleNone; [row autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:15.f];
}
UILabel *label = [UILabel new]; [row autoPinLeadingToSuperViewWithMargin:18.f];
label.textColor = [UIColor ows_darkGrayColor]; [row autoPinTrailingToSuperViewWithMargin:18.f];
label.font = footnoteFont; lastRow = row;
label.textAlignment = NSTextAlignmentCenter;
NSMutableAttributedString *text = [NSMutableAttributedString new]; if (lastRow == nameRow || lastRow == avatarRow) {
[text appendAttributedString:[[NSAttributedString alloc] UIView *separator = [UIView containerView];
initWithString:NSLocalizedString(@"PROFILE_VIEW_PROFILE_DESCRIPTION", separator.backgroundColor = [UIColor colorWithWhite:0.9f alpha:1.f];
@"Description of the user profile.") [contentView addSubview:separator];
attributes:@{}]]; [separator autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:lastRow withOffset:5.f];
[text appendAttributedString:[[NSAttributedString alloc] initWithString:@" " attributes:@{}]]; [separator autoPinLeadingToSuperViewWithMargin:18.f];
[text appendAttributedString:[[NSAttributedString alloc] [separator autoPinTrailingToSuperViewWithMargin:18.f];
initWithString:NSLocalizedString(@"PROFILE_VIEW_PROFILE_DESCRIPTION_LINK", [separator autoSetDimension:ALDimensionHeight toSize:1.f];
@"Link to more information about the user profile.") lastRow = separator;
attributes:@{ }
NSUnderlineStyleAttributeName :
@(NSUnderlineStyleSingle | NSUnderlinePatternSolid),
NSForegroundColorAttributeName : [UIColor ows_materialBlueColor],
}]];
label.attributedText = text;
label.numberOfLines = 0;
label.lineBreakMode = NSLineBreakByWordWrapping;
[cell.contentView addSubview:label];
[label autoPinLeadingToSuperView];
[label autoPinTrailingToSuperView];
[label autoVCenterInSuperview];
return cell;
} }
customRowHeight:footnoteFont.lineHeight * 5 [lastRow autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:10.f];
actionBlock:^{ }
[weakSelf openProfileInfoURL];
}]];
[contents addSection:section];
self.contents = contents; - (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.nameTextField becomeFirstResponder];
} }
#pragma mark - Event Handling #pragma mark - Event Handling
@ -312,6 +343,13 @@ NSString *const kProfileView_LastPresentedDate = @"kProfileView_LastPresentedDat
target:self target:self
action:@selector(updatePressed)]; action:@selector(updatePressed)];
} }
[self.skipOrSaveButton
setTitle:(self.hasUnsavedChanges
? NSLocalizedString(
@"PROFILE_VIEW_SAVE_BUTTON", @"Button to save the profile view in the profile view.")
: NSLocalizedString(@"PROFILE_VIEW_SKIP_BUTTON",
@"Button to skip the profile view in the registration workflow."))forState
:UIControlStateNormal];
} }
- (void)updatePressed - (void)updatePressed
@ -395,12 +433,6 @@ NSString *const kProfileView_LastPresentedDate = @"kProfileView_LastPresentedDat
OWSAssert([navigationController.topViewController isKindOfClass:[SignalsViewController class]]); OWSAssert([navigationController.topViewController isKindOfClass:[SignalsViewController class]]);
} }
- (void)openProfileInfoURL
{
[UIApplication.sharedApplication
openURL:[NSURL URLWithString:@"https://support.whispersystems.org/hc/en-us/articles/115001110511"]];
}
#pragma mark - UITextFieldDelegate #pragma mark - UITextFieldDelegate
- (BOOL)textField:(UITextField *)textField - (BOOL)textField:(UITextField *)textField
@ -447,6 +479,30 @@ NSString *const kProfileView_LastPresentedDate = @"kProfileView_LastPresentedDat
self.cameraImageView.hidden = self.avatar != nil; self.cameraImageView.hidden = self.avatar != nil;
} }
- (void)nameRowTapped:(UIGestureRecognizer *)sender
{
if (sender.state == UIGestureRecognizerStateRecognized) {
[self.nameTextField becomeFirstResponder];
}
}
- (void)infoRowTapped:(UIGestureRecognizer *)sender
{
if (sender.state == UIGestureRecognizerStateRecognized) {
[UIApplication.sharedApplication
openURL:[NSURL URLWithString:@"https://support.whispersystems.org/hc/en-us/articles/115001110511"]];
}
}
- (void)skipOrSaveButtonPressed
{
if (self.hasUnsavedChanges) {
[self updateProfile];
} else {
[self profileCompletedOrSkipped];
}
}
#pragma mark - AvatarViewHelperDelegate #pragma mark - AvatarViewHelperDelegate
+ (BOOL)shouldDisplayProfileViewOnLaunch + (BOOL)shouldDisplayProfileViewOnLaunch

@ -1105,9 +1105,15 @@
/* Label for the profile name field of the profile view. */ /* Label for the profile name field of the profile view. */
"PROFILE_VIEW_PROFILE_NAME_FIELD" = "Profile Name"; "PROFILE_VIEW_PROFILE_NAME_FIELD" = "Profile Name";
/* Button to save the profile view in the profile view. */
"PROFILE_VIEW_SAVE_BUTTON" = "Save";
/* Alert title that indicates the user's profile view is being saved. */ /* Alert title that indicates the user's profile view is being saved. */
"PROFILE_VIEW_SAVING" = "Saving..."; "PROFILE_VIEW_SAVING" = "Saving...";
/* Button to skip the profile view in the registration workflow. */
"PROFILE_VIEW_SKIP_BUTTON" = "Skip";
/* Title for the profile view. */ /* Title for the profile view. */
"PROFILE_VIEW_TITLE" = "Profile"; "PROFILE_VIEW_TITLE" = "Profile";

Loading…
Cancel
Save