From 1a57fe631cb6cb18a50f886f1fc31c51bae94b3c Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Thu, 21 Jun 2018 13:19:56 -0400 Subject: [PATCH] Fix 'contact cell vs. message details layout' issue. --- .../MessageDetailViewController.swift | 18 +- SignalMessaging/Views/ContactTableViewCell.h | 2 + SignalMessaging/Views/ContactTableViewCell.m | 259 +++++++++++++----- 3 files changed, 204 insertions(+), 75 deletions(-) diff --git a/Signal/src/ViewControllers/MessageDetailViewController.swift b/Signal/src/ViewControllers/MessageDetailViewController.swift index 5bd2ddd2d..878b46f7d 100644 --- a/Signal/src/ViewControllers/MessageDetailViewController.swift +++ b/Signal/src/ViewControllers/MessageDetailViewController.swift @@ -238,19 +238,13 @@ class MessageDetailViewController: OWSViewController, MediaGalleryDataSourceDele addDivider() } - let cell = ContactTableViewCell() - cell.configure(withRecipientId: recipientId, contactsManager: self.contactsManager) - let statusLabel = UILabel() + let contentView = UIView() + contentView.layoutMargins = UIEdgeInsets(top: 8, left: 20, bottom: 8, right: 20) + let cell = ContactTableViewCell(customContentView: contentView) // We use the "short" status message to avoid being redundant with the section title. - statusLabel.text = shortStatusMessage - statusLabel.textColor = UIColor.ows_darkGray - statusLabel.font = .ows_dynamicTypeFootnote - statusLabel.adjustsFontSizeToFitWidth = true - statusLabel.sizeToFit() - cell.accessoryView = statusLabel - cell.setContentHuggingLow() - cell.isUserInteractionEnabled = false - groupRows.append(cell) + cell.accessoryMessage = shortStatusMessage + cell.configure(withRecipientId: recipientId, contactsManager: self.contactsManager) + groupRows.append(contentView) } if groupRows.count > 0 { diff --git a/SignalMessaging/Views/ContactTableViewCell.h b/SignalMessaging/Views/ContactTableViewCell.h index d0d206b1f..718512bbe 100644 --- a/SignalMessaging/Views/ContactTableViewCell.h +++ b/SignalMessaging/Views/ContactTableViewCell.h @@ -26,6 +26,8 @@ extern const CGFloat kContactTableViewCellAvatarTextMargin; + (NSString *)reuseIdentifier; +- (instancetype)initWithCustomContentView:(UIView *)customContentView; + - (void)configureWithSignalAccount:(SignalAccount *)signalAccount contactsManager:(OWSContactsManager *)contactsManager; - (void)configureWithRecipientId:(NSString *)recipientId contactsManager:(OWSContactsManager *)contactsManager; diff --git a/SignalMessaging/Views/ContactTableViewCell.m b/SignalMessaging/Views/ContactTableViewCell.m index 0a3c81fc0..9920fca29 100644 --- a/SignalMessaging/Views/ContactTableViewCell.m +++ b/SignalMessaging/Views/ContactTableViewCell.m @@ -27,7 +27,9 @@ const CGFloat kContactTableViewCellAvatarTextMargin = 12; @property (nonatomic) UILabel *profileNameLabel; @property (nonatomic) UIImageView *avatarView; @property (nonatomic) UILabel *subtitle; -@property (nonatomic) UIView *nameContainerView; +@property (nonatomic) UILabel *ows_accessoryView; +@property (nonatomic) UIStackView *nameContainerView; +//@property (nonatomic) UIView *nameContainerView; @property (nonatomic) OWSContactsManager *contactsManager; @property (nonatomic) NSString *recipientId; @@ -41,7 +43,17 @@ const CGFloat kContactTableViewCellAvatarTextMargin = 12; - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(nullable NSString *)reuseIdentifier { if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) { - [self configureProgrammatically]; + [self configureWithContentView:self.contentView]; + } + return self; +} + +- (instancetype)initWithCustomContentView:(UIView *)customContentView +{ + if (self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ContactTableViewCell.reuseIdentifier]) { + OWSAssert(customContentView); + + [self configureWithContentView:customContentView]; } return self; } @@ -51,62 +63,164 @@ const CGFloat kContactTableViewCellAvatarTextMargin = 12; return NSStringFromClass(self.class); } -- (void)configureProgrammatically +- (void)setAccessoryView:(nullable UIView *)accessoryView { - OWSAssert(!self.nameLabel); - - self.contentView.translatesAutoresizingMaskIntoConstraints = NO; - - _avatarView = [AvatarImageView new]; - [self.contentView addSubview:_avatarView]; - - _nameContainerView = [UIView containerView]; - [self.contentView addSubview:_nameContainerView]; - - _nameLabel = [UILabel new]; - _nameLabel.lineBreakMode = NSLineBreakByTruncatingTail; - [_nameContainerView addSubview:_nameLabel]; + OWSFail(@"%@ don't use accessory view for this view.", self.logTag); +} - _profileNameLabel = [UILabel new]; - _profileNameLabel.lineBreakMode = NSLineBreakByTruncatingTail; - _profileNameLabel.textColor = [UIColor grayColor]; - [_nameContainerView addSubview:_profileNameLabel]; +- (void)configureWithContentView:(UIView *)contentView +{ + // self.preservesSuperviewLayoutMargins = YES; + // self.contentView.preservesSuperviewLayoutMargins = YES; + // + OWSAssert(!self.nameLabel); - _subtitle = [UILabel new]; - _subtitle.textColor = [UIColor ows_darkGrayColor]; - [_nameContainerView addSubview:self.subtitle]; + // self.contentView.translatesAutoresizingMaskIntoConstraints = NO; + // self.translatesAutoresizingMaskIntoConstraints = YES; + // self.contentView.translatesAutoresizingMaskIntoConstraints = YES; + // self.translatesAutoresizingMaskIntoConstraints = NO; + // self.contentView.translatesAutoresizingMaskIntoConstraints = NO; - [_avatarView autoVCenterInSuperview]; - [_avatarView autoPinLeadingToSuperviewMargin]; + _avatarView = [AvatarImageView new]; [_avatarView autoSetDimension:ALDimensionWidth toSize:kContactTableViewCellAvatarSize]; [_avatarView autoSetDimension:ALDimensionHeight toSize:kContactTableViewCellAvatarSize]; - [_nameLabel autoPinEdgeToSuperviewEdge:ALEdgeTop]; - [_nameLabel autoPinWidthToSuperview]; - - // profileNameLabel can be zero sized, in which case nameLabel essentially occupies the totality of - // nameContainerView's frame. - [_profileNameLabel autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:_nameLabel]; - [_profileNameLabel autoPinWidthToSuperview]; - - [_subtitle autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:_profileNameLabel]; - [_subtitle autoPinWidthToSuperview]; - [_subtitle autoPinEdgeToSuperviewEdge:ALEdgeBottom]; - - [_nameContainerView autoVCenterInSuperview]; - [_nameContainerView autoPinLeadingToTrailingEdgeOfView:_avatarView offset:kContactTableViewCellAvatarTextMargin]; - [_nameContainerView autoPinTrailingToSuperviewMargin]; - + self.nameLabel = [UILabel new]; + self.nameLabel.lineBreakMode = NSLineBreakByTruncatingTail; + self.nameLabel.textColor = [UIColor blackColor]; + + self.profileNameLabel = [UILabel new]; + self.profileNameLabel.lineBreakMode = NSLineBreakByTruncatingTail; + self.profileNameLabel.textColor = [UIColor grayColor]; + + self.subtitle = [UILabel new]; + self.subtitle.textColor = [UIColor ows_darkGrayColor]; + + self.ows_accessoryView = [[UILabel alloc] init]; + self.ows_accessoryView.textAlignment = NSTextAlignmentRight; + self.ows_accessoryView.textColor = [UIColor colorWithWhite:0.5f alpha:1.f]; + + // self.nameContainerView = self.nameLabel; + + // self.nameContainerView = [UIView containerView]; + // [self.nameContainerView addSubview:self.nameLabel]; + // [self.nameContainerView addSubview:self.profileNameLabel]; + // [self.nameContainerView addSubview:self.subtitle]; + // [self.nameLabel autoPinWidthToSuperview]; + // [self.profileNameLabel autoPinWidthToSuperview]; + // [self.subtitle autoPinWidthToSuperview]; + // [self.nameLabel autoPinTopToSuperviewMargin]; + // [self.profileNameLabel autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:self.nameLabel]; + // [self.subtitle autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:self.profileNameLabel]; + // [self.subtitle autoPinBottomToSuperviewMargin]; + // + // [contentView addSubview:self.avatarView]; + // [contentView addSubview:self.nameContainerView]; + // [contentView addSubview:self.ows_accessoryView]; + // + // [self.avatarView autoVCenterInSuperview]; + // [self.nameContainerView autoVCenterInSuperview]; + // [self.ows_accessoryView autoVCenterInSuperview]; + // [self.avatarView autoPinLeadingToSuperviewMargin]; + // [self.nameContainerView autoPinLeadingToTrailingEdgeOfView:self.avatarView + // offset:kContactTableViewCellAvatarTextMargin]; + //// [self.nameContainerView autoPinEdgeToSuperviewEdge:ALEdgeTrailing]; + //// [self.nameContainerView autoPinTrailingToSuperviewMargin]; + // [self.ows_accessoryView autoPinLeadingToTrailingEdgeOfView:self.nameContainerView + // offset:kContactTableViewCellAvatarTextMargin]; [self.ows_accessoryView autoPinTrailingToSuperviewMargin]; + // // Ensure that the cell's contents never overflow the cell bounds. + // [self.avatarView autoPinEdgeToSuperviewMargin:ALEdgeTop relation:NSLayoutRelationGreaterThanOrEqual]; + // [self.avatarView autoPinEdgeToSuperviewMargin:ALEdgeBottom relation:NSLayoutRelationGreaterThanOrEqual]; + // [self.nameContainerView autoPinEdgeToSuperviewMargin:ALEdgeTop relation:NSLayoutRelationGreaterThanOrEqual]; + // [self.nameContainerView autoPinEdgeToSuperviewMargin:ALEdgeBottom + // relation:NSLayoutRelationGreaterThanOrEqual]; [self.ows_accessoryView autoPinEdgeToSuperviewMargin:ALEdgeTop + // relation:NSLayoutRelationGreaterThanOrEqual]; [self.ows_accessoryView + // autoPinEdgeToSuperviewMargin:ALEdgeBottom relation:NSLayoutRelationGreaterThanOrEqual]; + + // + //// UIView h = [UIView containerView]; + //// [self.nameContainerView addSubview:self.nameLabel]; + //// [self.nameContainerView addSubview:self.profileNameLabel]; + //// [self.nameContainerView addSubview:self.subtitle]; + //// [self.nameLabel autoPinWidthToSuperview]; + //// [self.profileNameLabel autoPinWidthToSuperview]; + //// [self.subtitle autoPinWidthToSuperview]; + //// [self.nameLabel autoPinTopToSuperviewMargin]; + //// [self.profileNameLabel autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:self.nameLabel]; + //// [self.subtitle autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:self.profileNameLabel]; + //// [self.subtitle autoPinBottomToSuperviewMargin]; + // + + self.nameContainerView = [[UIStackView alloc] initWithArrangedSubviews:@[ + self.nameLabel, + self.profileNameLabel, + self.subtitle, + ]]; + self.nameContainerView.axis = UILayoutConstraintAxisVertical; + self.nameContainerView.alignment = UIStackViewAlignmentFill; + // hStackView.distribution = UIStackViewDistributionFill; + // [self.contentView addSubview:hStackView]; + // [hStackView autoVCenterInSuperview]; + // [hStackView autoPinLeadingToSuperviewMargin]; + // [hStackView autoPinTrailingToSuperviewMargin]; + // // Ensure that the cell's contents never overflow the cell bounds. + // [hStackView autoPinEdgeToSuperviewMargin:ALEdgeTop relation:NSLayoutRelationGreaterThanOrEqual]; + // [hStackView autoPinEdgeToSuperviewMargin:ALEdgeBottom relation:NSLayoutRelationGreaterThanOrEqual]; + // + // + //// [self.avatarView setContentHuggingHorizontalHigh]; + //// [self.nameLabel setContentHuggingHorizontalLow]; + //// [self.profileNameLabel setContentHuggingHorizontalLow]; + //// [self.subtitle setContentHuggingHorizontalLow]; + //// [self.nameContainerView setContentHuggingHorizontalLow]; + // + // [self.ows_accessoryView setContentHuggingHorizontalLow]; + // + //// UIView *hStackView = [UIView new]; + //// hStackView.backgroundColor = UIColor.greenColor; + //// [self.contentView addSubview:hStackView]; + //// [hStackView autoPinToSuperviewEdges]; + //// [hStackView setContentHuggingLow]; + // + //// [hStackView autoVCenterInSuperview]; + //// [hStackView autoPinLeadingToSuperviewMargin]; + //// // [hStackView autoPinTrailingToSuperviewMargin]; + //// [hStackView autoPinEdgeToSuperviewEdge:ALEdgeTrailing]; + //// // Ensure that the cell's contents never overflow the cell bounds. + //// [hStackView autoPinEdgeToSuperviewMargin:ALEdgeTop relation:NSLayoutRelationGreaterThanOrEqual]; + //// [hStackView autoPinEdgeToSuperviewMargin:ALEdgeBottom relation:NSLayoutRelationGreaterThanOrEqual]; + //// [hStackView setContentHuggingHorizontalLow]; + // + UIStackView *hStackView = [[UIStackView alloc] initWithArrangedSubviews:@[ + self.avatarView, + self.nameContainerView, + self.ows_accessoryView, + ]]; + hStackView.axis = UILayoutConstraintAxisHorizontal; + hStackView.spacing = kContactTableViewCellAvatarTextMargin; + hStackView.distribution = UIStackViewDistributionFill; + [contentView addSubview:hStackView]; + [hStackView autoVCenterInSuperview]; + [hStackView autoPinLeadingToSuperviewMargin]; + [hStackView autoPinTrailingToSuperviewMargin]; + // [hStackView autoPinEdgeToSuperviewEdge:ALEdgeTrailing]; // Ensure that the cell's contents never overflow the cell bounds. - [self.avatarView autoPinEdgeToSuperviewMargin:ALEdgeTop relation:NSLayoutRelationGreaterThanOrEqual]; - [self.avatarView autoPinEdgeToSuperviewMargin:ALEdgeBottom relation:NSLayoutRelationGreaterThanOrEqual]; - [self.nameContainerView autoPinEdgeToSuperviewMargin:ALEdgeTop relation:NSLayoutRelationGreaterThanOrEqual]; - [self.nameContainerView autoPinEdgeToSuperviewMargin:ALEdgeBottom relation:NSLayoutRelationGreaterThanOrEqual]; + [hStackView autoPinEdgeToSuperviewMargin:ALEdgeTop relation:NSLayoutRelationGreaterThanOrEqual]; + [hStackView autoPinEdgeToSuperviewMargin:ALEdgeBottom relation:NSLayoutRelationGreaterThanOrEqual]; + // [hStackView setContentHuggingHorizontalLow]; + // [hStackView setCompressionResistanceHorizontalLow]; + // [hStackView addBackgroundViewWithBackgroundColor:[UIColor greenColor]]; + // [self.nameContainerView addBackgroundViewWithBackgroundColor:[UIColor blueColor]]; [self configureFonts]; - // Force layout, since imageView isn't being initally rendered on App Store optimized build. - [self layoutSubviews]; + // // Force layout, since imageView isn't being initally rendered on App Store optimized build. + // [self layoutSubviews]; + // + // [self logFrameLaterWithLabel:@"cell"]; + // [self.contentView logFrameLaterWithLabel:@"contentView"]; + // [self.avatarView logFrameLaterWithLabel:@"avatarView"]; + // [self.nameContainerView logFrameLaterWithLabel:@"nameContainerView"]; } - (void)configureFonts @@ -114,6 +228,7 @@ const CGFloat kContactTableViewCellAvatarTextMargin = 12; self.nameLabel.font = [UIFont ows_dynamicTypeBodyFont]; self.profileNameLabel.font = [UIFont ows_regularFontWithSize:11.f]; self.subtitle.font = [UIFont ows_regularFontWithSize:11.f]; + self.ows_accessoryView.font = [UIFont ows_mediumFontWithSize:13.f]; } - (void)configureWithSignalAccount:(SignalAccount *)signalAccount contactsManager:(OWSContactsManager *)contactsManager @@ -143,18 +258,42 @@ const CGFloat kContactTableViewCellAvatarTextMargin = 12; [self updateAvatar]; if (self.accessoryMessage) { - UILabel *blockedLabel = [[UILabel alloc] init]; - blockedLabel.textAlignment = NSTextAlignmentRight; - blockedLabel.text = self.accessoryMessage; - blockedLabel.font = [UIFont ows_mediumFontWithSize:13.f]; - blockedLabel.textColor = [UIColor colorWithWhite:0.5f alpha:1.f]; - [blockedLabel sizeToFit]; - - self.accessoryView = blockedLabel; + self.ows_accessoryView.text = self.accessoryMessage; } // Force layout, since imageView isn't being initally rendered on App Store optimized build. [self layoutSubviews]; + + DDLogVerbose(@"%@ nameLabel size: %@, %@", + self.logTag, + NSStringFromCGSize([self.nameLabel sizeThatFits:CGSizeZero]), + NSStringFromCGSize([self.nameLabel intrinsicContentSize])); + DDLogVerbose(@"%@ nameContainerView size: %@, %@", + self.logTag, + NSStringFromCGSize([self.nameContainerView sizeThatFits:CGSizeZero]), + NSStringFromCGSize([self.nameContainerView intrinsicContentSize])); + DDLogVerbose(@"%@ ows_accessoryView size: %@, %@", + self.logTag, + NSStringFromCGSize([self.ows_accessoryView sizeThatFits:CGSizeZero]), + NSStringFromCGSize([self.ows_accessoryView intrinsicContentSize])); + DDLogVerbose(@"%@ contentView size: %@, %@", + self.logTag, + NSStringFromCGSize([self.contentView sizeThatFits:CGSizeZero]), + NSStringFromCGSize([self.contentView intrinsicContentSize])); + + // [self.nameLabel sizeToFit]; + // [self.nameLabel autoSetDimension:ALDimensionWidth toSize:self.nameLabel.width]; + // [self.nameLabel autoSetDimension:ALDimensionHeight toSize:self.nameLabel.height]; + + // [self.nameContainerView sizeToFit]; + // [self.nameContainerView.superview sizeToFit]; + // [self.nameContainerView logFrameWithLabel:@"nameContainerView?"]; + + [self logFrameLaterWithLabel:@"cell"]; + [self.contentView logFrameLaterWithLabel:@"contentView"]; + [self.avatarView logFrameLaterWithLabel:@"avatarView"]; + [self.nameContainerView logFrameLaterWithLabel:@"nameContainerView"]; + [self.ows_accessoryView logFrameLaterWithLabel:@"ows_accessoryView"]; } - (void)configureWithThread:(TSThread *)thread contactsManager:(OWSContactsManager *)contactsManager @@ -192,14 +331,7 @@ const CGFloat kContactTableViewCellAvatarTextMargin = 12; contactsManager:contactsManager]; if (self.accessoryMessage) { - UILabel *blockedLabel = [[UILabel alloc] init]; - blockedLabel.textAlignment = NSTextAlignmentRight; - blockedLabel.text = self.accessoryMessage; - blockedLabel.font = [UIFont ows_mediumFontWithSize:13.f]; - blockedLabel.textColor = [UIColor colorWithWhite:0.5f alpha:1.f]; - [blockedLabel sizeToFit]; - - self.accessoryView = blockedLabel; + self.ows_accessoryView.text = self.accessoryMessage; } // Force layout, since imageView isn't being initally rendered on App Store optimized build. @@ -282,6 +414,7 @@ const CGFloat kContactTableViewCellAvatarTextMargin = 12; self.nameLabel.text = nil; self.subtitle.text = nil; self.profileNameLabel.text = nil; + self.ows_accessoryView.text = nil; } - (void)otherUsersProfileDidChange:(NSNotification *)notification