// // TIMCommonModel.m // TIMCommon // // Created by cologne on 2023/3/14. // Copyright © 2023 Tencent. All rights reserved. // #import "TIMCommonModel.h" ///////////////////////////////////////////////////////////////////////////////// // // TUIPopView // ///////////////////////////////////////////////////////////////////////////////// @interface TUIPopView () @property(nonatomic, strong) NSMutableArray *data; @end @implementation TUIPopView - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { [self setupViews]; } return self; } - (void)setData:(NSMutableArray *)data { _data = data; [_tableView reloadData]; } - (void)showInWindow:(UIWindow *)window { [window addSubview:self]; __weak typeof(self) ws = self; self.alpha = 0; [UIView animateWithDuration:0.25 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{ ws.alpha = 1; } completion:nil]; } - (void)setupViews { UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onTap:)]; tap.delegate = self; [self addGestureRecognizer:tap]; UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(onTap:)]; [self addGestureRecognizer:pan]; self.backgroundColor = [UIColor clearColor]; CGSize arrowSize = TUIPopView_Arrow_Size; _tableView = [[UITableView alloc] initWithFrame:CGRectMake(self.frame.origin.x, self.frame.origin.y + arrowSize.height, self.frame.size.width, self.frame.size.height - arrowSize.height)]; self.frame = [UIScreen mainScreen].bounds; _tableView.delegate = self; _tableView.dataSource = self; _tableView.backgroundColor = TUIDemoDynamicColor(@"pop_bg_color", @"#FFFFFF"); _tableView.tableFooterView = [[UIView alloc] init]; _tableView.scrollEnabled = NO; _tableView.layer.cornerRadius = 5.0; [self addSubview:_tableView]; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return _data.count; } - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { return [TUIPopCell getHeight]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { TUIPopCell *cell = [tableView dequeueReusableCellWithIdentifier:TUIPopCell_ReuseId]; if (!cell) { cell = [[TUIPopCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:TUIPopCell_ReuseId]; } [cell setData:_data[indexPath.row]]; if (indexPath.row == _data.count - 1) { cell.separatorInset = UIEdgeInsetsMake(0, self.bounds.size.width, 0, 0); } return cell; } - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [tableView deselectRowAtIndexPath:indexPath animated:NO]; if (_delegate && [_delegate respondsToSelector:@selector(popView:didSelectRowAtIndex:)]) { [_delegate popView:self didSelectRowAtIndex:indexPath.row]; } [self hide]; } - (void)drawRect:(CGRect)rect { [[UIColor whiteColor] set]; CGSize arrowSize = TUIPopView_Arrow_Size; UIBezierPath *arrowPath = [[UIBezierPath alloc] init]; [arrowPath moveToPoint:_arrowPoint]; [arrowPath addLineToPoint:CGPointMake(_arrowPoint.x + arrowSize.width * 0.5, _arrowPoint.y + arrowSize.height)]; [arrowPath addLineToPoint:CGPointMake(_arrowPoint.x - arrowSize.width * 0.5, _arrowPoint.y + arrowSize.height)]; [arrowPath closePath]; [arrowPath fill]; } - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch { if ([NSStringFromClass([touch.view class]) isEqualToString:@"UITableViewCellContentView"]) { return NO; } return YES; } - (void)onTap:(UIGestureRecognizer *)recognizer { [self hide]; } - (void)hide { __weak typeof(self) ws = self; self.alpha = 1; [UIView animateWithDuration:0.25 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{ ws.alpha = 0; } completion:^(BOOL finished) { if ([ws superview]) { [ws removeFromSuperview]; } }]; } @end @implementation TUIPopCellData @end @implementation TUIPopCell - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; if (self) { [self setupViews]; } return self; } - (void)setupViews { self.backgroundColor = [UIColor clearColor]; _image = [[UIImageView alloc] init]; _image.contentMode = UIViewContentModeScaleAspectFit; [self addSubview:_image]; _title = [[UILabel alloc] init]; _title.font = [UIFont systemFontOfSize:15]; _title.textColor = TUIDemoDynamicColor(@"pop_text_color", @"#444444"); _title.numberOfLines = 0; [self addSubview:_title]; [self setSeparatorInset:UIEdgeInsetsMake(0, TUIPopCell_Padding, 0, 0)]; } - (void)layoutSubviews { CGFloat headHeight = TUIPopCell_Height - 2 * TUIPopCell_Padding; self.image.frame = CGRectMake(TUIPopCell_Padding, TUIPopCell_Padding, headHeight, headHeight); self.image.center = CGPointMake(self.image.center.x, self.contentView.center.y); CGFloat titleWidth = self.frame.size.width - 2 * TUIPopCell_Padding - TUIPopCell_Margin - _image.frame.size.width; self.title.frame = CGRectMake(_image.frame.origin.x + _image.frame.size.width + TUIPopCell_Margin, TUIPopCell_Padding, titleWidth, self.contentView.bounds.size.height); self.title.center = CGPointMake(self.title.center.x, self.contentView.center.y); if (isRTL()) { [self.image resetFrameToFitRTL]; [self.title resetFrameToFitRTL]; } } - (void)setData:(TUIPopCellData *)data { _image.image = data.image; _title.text = data.title; } + (CGFloat)getHeight { return TUIPopCell_Height; } @end ///////////////////////////////////////////////////////////////////////////////// // // TUIModifyView // ///////////////////////////////////////////////////////////////////////////////// #define kContainerWidth Screen_Width #define kContainerHeight kContainerWidth * 3 / 4 @implementation TUIModifyViewData - (instancetype)init { if (self = [super init]) { self.enableNull = NO; } return self; } @end @interface TUIModifyView () @property(nonatomic, assign) BOOL keyboardShowing; @property(nonatomic, strong) TUIModifyViewData *data; @property(nonatomic, strong) UIButton *closeBtn; @end @implementation TUIModifyView - (id)init { self = [super init]; if (self) { [self setupViews]; } return self; } - (void)setupViews { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidHide:) name:UIKeyboardDidHideNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil]; self.frame = [UIScreen mainScreen].bounds; UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onTap:)]; tap.delegate = self; [self addGestureRecognizer:tap]; self.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.4]; _container = [[UIView alloc] initWithFrame:CGRectMake(0, Screen_Height, kContainerWidth, kContainerHeight)]; _container.backgroundColor = TUIContactDynamicColor(@"group_modify_container_view_bg_color", @"#FFFFFF"); _container.layer.cornerRadius = 8; [_container.layer setMasksToBounds:YES]; [self addSubview:_container]; CGFloat buttonHeight = 46; CGFloat titleHeight = 63; _title = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, _container.frame.size.width, titleHeight)]; _title.font = [UIFont fontWithName:@"PingFangSC-Medium" size:17]; _title.textColor = TUIContactDynamicColor(@"group_modify_title_color", @"#000000"); _title.textAlignment = NSTextAlignmentCenter; [_container addSubview:_title]; _hLine = [[UIView alloc] initWithFrame:CGRectMake(0, CGRectGetMaxY(_title.frame), kContainerWidth, TLine_Heigh)]; _hLine.backgroundColor = TIMCommonDynamicColor(@"separator_color", @"#E4E5E9"); [_container addSubview:_hLine]; CGFloat contentMargin = 20; CGFloat contentWidth = _container.frame.size.width - 2 * contentMargin; CGFloat contentY = CGRectGetMaxY(_hLine.frame) + 17; CGFloat contentheight = 40; _content = [[UITextField alloc] initWithFrame:CGRectMake(contentMargin, contentY, contentWidth, contentheight)]; _content.textAlignment = isRTL()?NSTextAlignmentRight:NSTextAlignmentLeft; _content.delegate = self; _content.backgroundColor = TUIContactDynamicColor(@"group_modify_input_bg_color", @"#F5F5F5"); _content.textColor = TUIContactDynamicColor(@"group_modify_input_text_color", @"#000000"); [_content setFont:[UIFont systemFontOfSize:16]]; [_content.layer setMasksToBounds:YES]; [_content.layer setCornerRadius:4.0f]; [_content setReturnKeyType:UIReturnKeyDone]; [_content addTarget:self action:@selector(textChanged) forControlEvents:UIControlEventEditingChanged]; CGRect leftviewFrame = _content.frame; leftviewFrame.size.width = 16; UIView *leftview = [[UIView alloc] initWithFrame:leftviewFrame]; _content.leftView = leftview; _content.leftViewMode = UITextFieldViewModeAlways; CGRect rightviewFrame = _content.frame; rightviewFrame.size.width = 16; rightviewFrame.origin.x = rightviewFrame.size.width - 16; UIView *rightView = [[UIView alloc] initWithFrame:rightviewFrame]; _content.rightView = rightView; _content.rightViewMode = UITextFieldViewModeAlways; [_container addSubview:_content]; _descLabel = [[UILabel alloc] initWithFrame:CGRectMake(_content.frame.origin.x, CGRectGetMaxY(_content.frame) + 17, contentWidth, 20)]; _descLabel.textColor = TUIContactDynamicColor(@"group_modify_desc_color", @"#888888"); _descLabel.font = [UIFont systemFontOfSize:13.0]; _descLabel.numberOfLines = 0; _descLabel.text = @"desc"; [_container addSubview:_descLabel]; _confirm = [[UIButton alloc] initWithFrame:CGRectMake(_content.frame.origin.x, CGRectGetMaxY(_descLabel.frame) + 30, contentWidth, buttonHeight)]; [_confirm setTitle:TIMCommonLocalizableString(Confirm) forState:UIControlStateNormal]; [_confirm setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; _confirm.titleLabel.font = [UIFont systemFontOfSize:15]; _confirm.layer.cornerRadius = 8; _confirm.layer.masksToBounds = YES; _confirm.imageView.contentMode = UIViewContentModeScaleToFill; [self enableConfirmButton:self.data.enableNull]; [_confirm addTarget:self action:@selector(didConfirm:) forControlEvents:UIControlEventTouchUpInside]; [_container addSubview:_confirm]; _closeBtn = [[UIButton alloc] initWithFrame:CGRectMake(_container.frame.size.width - 24 - 20, 0, 24, 24)]; _closeBtn.mm__centerY(_title.mm_centerY); [_closeBtn setImage:[UIImage imageNamed:TUIContactImagePath(@"ic_close_poppings")] forState:UIControlStateNormal]; [_closeBtn addTarget:self action:@selector(didCancel:) forControlEvents:UIControlEventTouchUpInside]; [_container addSubview:_closeBtn]; } - (void)setData:(TUIModifyViewData *)data { _title.text = data.title; _content.text = data.content; _descLabel.text = data.desc; _data = data; CGRect rect = [data.desc boundingRectWithSize:CGSizeMake(self.content.bounds.size.width, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName : [UIFont systemFontOfSize:13.0]} context:nil]; CGRect frame = _descLabel.frame; frame.size.height = rect.size.height; _descLabel.frame = frame; [self textChanged]; } - (void)showInWindow:(UIWindow *)window { [window addSubview:self]; [self layoutIfNeeded]; CGFloat height = CGRectGetMaxY(self.confirm.frame) + 50; __weak typeof(self) ws = self; [UIView animateWithDuration:0.25 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{ ws.container.frame = CGRectMake(0, Screen_Height - height, kContainerWidth, height); } completion:nil]; } - (void)onTap:(UIGestureRecognizer *)recognizer { [_content resignFirstResponder]; if (!self.keyboardShowing) { [self hide]; } } - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch { return [touch.view isEqual:self]; } - (void)hide { __weak typeof(self) ws = self; self.alpha = 1; [UIView animateWithDuration:0.25 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{ ws.alpha = 0; } completion:^(BOOL finished) { [[NSNotificationCenter defaultCenter] removeObserver:ws]; if ([ws superview]) { [ws removeFromSuperview]; } }]; } - (void)didCancel:(UIButton *)sender { [self hide]; } - (void)didConfirm:(UIButton *)sender { if (_delegate && [_delegate respondsToSelector:@selector(modifyView:didModiyContent:)]) { [_delegate modifyView:self didModiyContent:_content.text]; } [self hide]; } - (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text { if ([text isEqualToString:@"\n"]) { [textView resignFirstResponder]; return NO; } return YES; } - (void)textChanged { [self enableConfirmButton:(self.content.text.length || self.data.enableNull)]; } - (void)keyboardWillChangeFrame:(NSNotification *)notification { CGRect keyboardFrame = [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue]; self.keyboardShowing = keyboardFrame.size.height > 0; [self animateContainer:keyboardFrame.size.height]; } - (void)keyboardWillHide:(NSNotification *)notification { [self animateContainer:0]; } - (void)keyboardDidHide:(NSNotification *)notice { self.keyboardShowing = NO; } - (void)animateContainer:(CGFloat)keyboardHeight { CGFloat height = CGRectGetMaxY(self.confirm.frame) + 50; CGRect frame = _container.frame; frame.origin.y = Screen_Height - height - keyboardHeight; //(self.frame.size.height - keyboardHeight - frame.size.height) * 0.5; __weak typeof(self) ws = self; [UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{ ws.container.frame = frame; } completion:nil]; } - (void)enableConfirmButton:(BOOL)enable { if (enable) { _confirm.backgroundColor = TUIContactDynamicColor(@"group_modify_confirm_enable_bg_color", @"147AFF"); _confirm.enabled = YES; } else { _confirm.backgroundColor = [TUIContactDynamicColor(@"group_modify_confirm_enable_bg_color", @"147AFF") colorWithAlphaComponent:0.3]; _confirm.enabled = NO; } } @end ///////////////////////////////////////////////////////////////////////////////// // // TUINaviBarIndicatorView // ///////////////////////////////////////////////////////////////////////////////// @implementation TUINaviBarIndicatorView - (id)init { self = [super init]; if (self) { [self setupViews]; } return self; } - (void)setupViews { _indicator = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(0, 0, 20, 20)]; _indicator.center = CGPointMake(0, NavBar_Height * 0.5); _indicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyleGray; [self addSubview:_indicator]; _label = [[UILabel alloc] init]; _label.backgroundColor = [UIColor clearColor]; _label.font = [UIFont boldSystemFontOfSize:17]; _label.textColor = TIMCommonDynamicColor(@"nav_title_text_color", @"#000000"); [self addSubview:_label]; _maxLabelLength = 150; } - (void)setTitle:(NSString *)title { _label.textColor = TIMCommonDynamicColor(@"nav_title_text_color", @"#000000"); _label.text = title; [self updateLayout]; } - (void)updateLayout { [_label sizeToFit]; CGSize labelSize = _label.bounds.size; // [_label sizeThatFits:CGSizeMake(Screen_Width, NavBar_Height)]; CGFloat labelWidth = MIN(labelSize.width, _maxLabelLength); CGFloat labelY = 0; CGFloat labelX = _indicator.hidden ? 0 : (_indicator.frame.origin.x + _indicator.frame.size.width + TUINaviBarIndicatorView_Margin); _label.frame = CGRectMake(labelX, labelY, labelWidth, NavBar_Height); self.frame = CGRectMake(0, 0, labelX + labelWidth + TUINaviBarIndicatorView_Margin, NavBar_Height); // self.center = CGPointMake(Screen_Width * 0.5, NavBar_Height * 0.5); } - (void)startAnimating { [_indicator startAnimating]; } - (void)stopAnimating { [_indicator stopAnimating]; } @end ///////////////////////////////////////////////////////////////////////////////// // // TUICommonCell & data // ///////////////////////////////////////////////////////////////////////////////// @implementation TUICommonCellData - (CGFloat)heightOfWidth:(CGFloat)width { return 62; } - (CGFloat)estimatedHeight { return 62; } @end @interface TUICommonTableViewCell () @property TUICommonCellData *data; @property UITapGestureRecognizer *tapRecognizer; @end @implementation TUICommonTableViewCell - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; if (self) { _tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGesture:)]; _tapRecognizer.delegate = self; _tapRecognizer.cancelsTouchesInView = NO; self.backgroundColor = TIMCommonDynamicColor(@"form_bg_color", @"#FFFFFF"); self.contentView.backgroundColor = TIMCommonDynamicColor(@"form_bg_color", @"#FFFFFF"); } return self; } - (void)tapGesture:(UIGestureRecognizer *)gesture { if (self.data.cselector) { UIViewController *vc = self.mm_viewController; if ([vc respondsToSelector:self.data.cselector]) { self.selected = YES; #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-performSelector-leaks" [vc performSelector:self.data.cselector withObject:self]; #pragma clang diagnostic pop } } } - (void)fillWithData:(TUICommonCellData *)data { self.data = data; if (data.cselector) { [self addGestureRecognizer:self.tapRecognizer]; } else { [self removeGestureRecognizer:self.tapRecognizer]; } } @end ///////////////////////////////////////////////////////////////////////////////// // // TUICommonTextCell & data // ///////////////////////////////////////////////////////////////////////////////// @implementation TUICommonTextCellData - (instancetype)init { self = [super init]; self.keyEdgeInsets = UIEdgeInsetsMake(0, 20, 0, 0); return self; } - (CGFloat)heightOfWidth:(CGFloat)width { CGFloat height = [super heightOfWidth:width]; if (self.enableMultiLineValue) { NSString *str = self.value; NSDictionary *attribute = @{NSFontAttributeName : [UIFont systemFontOfSize:16]}; CGSize size = [str boundingRectWithSize:CGSizeMake(280, 999) options:NSStringDrawingTruncatesLastVisibleLine | NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading attributes:attribute context:nil] .size; height = size.height + 30; } return height; } @end @interface TUICommonTextCell () @property TUICommonTextCellData *textData; @end @implementation TUICommonTextCell - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { if (self = [super initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:reuseIdentifier]) { self.backgroundColor = TIMCommonDynamicColor(@"form_bg_color", @"#FFFFFF"); self.contentView.backgroundColor = TIMCommonDynamicColor(@"form_bg_color", @"#FFFFFF"); _keyLabel = [[UILabel alloc] init]; _keyLabel.textColor = TIMCommonDynamicColor(@"form_key_text_color", @"#444444"); _keyLabel.font = [UIFont systemFontOfSize:16.0]; [self.contentView addSubview:_keyLabel]; [_keyLabel setRtlAlignment:TUITextRTLAlignmentTrailing]; _valueLabel = [[UILabel alloc] init]; [self.contentView addSubview:_valueLabel]; _valueLabel.textColor = TIMCommonDynamicColor(@"form_value_text_color", @"#000000"); _valueLabel.font = [UIFont systemFontOfSize:16.0]; [_valueLabel setRtlAlignment:TUITextRTLAlignmentTrailing]; self.selectionStyle = UITableViewCellSelectionStyleNone; } return self; } - (void)fillWithData:(TUICommonTextCellData *)textData { [super fillWithData:textData]; self.textData = textData; RAC(_keyLabel, text) = [RACObserve(textData, key) takeUntil:self.rac_prepareForReuseSignal]; RAC(_valueLabel, text) = [RACObserve(textData, value) takeUntil:self.rac_prepareForReuseSignal]; if (textData.showAccessory) { self.accessoryType = UITableViewCellAccessoryDisclosureIndicator; } else { self.accessoryType = UITableViewCellAccessoryNone; } if (self.textData.keyColor) { self.keyLabel.textColor = self.textData.keyColor; } if (self.textData.valueColor) { self.valueLabel.textColor = self.textData.valueColor; } if (self.textData.enableMultiLineValue) { self.valueLabel.numberOfLines = 0; } else { self.valueLabel.numberOfLines = 1; } // tell constraints they need updating [self setNeedsUpdateConstraints]; // update constraints now so we can animate the change [self updateConstraintsIfNeeded]; [self layoutIfNeeded]; } + (BOOL)requiresConstraintBasedLayout { return YES; } // this is Apple's recommended place for adding/updating constraints - (void)updateConstraints { [super updateConstraints]; [self.keyLabel sizeToFit]; [self.keyLabel mas_remakeConstraints:^(MASConstraintMaker *make) { make.size.mas_equalTo(self.keyLabel.frame.size); make.leading.mas_equalTo(self.contentView).mas_offset(self.textData.keyEdgeInsets.left); make.centerY.mas_equalTo(self.contentView); }]; [self.valueLabel sizeToFit]; [self.valueLabel mas_remakeConstraints:^(MASConstraintMaker *make) { make.leading.mas_equalTo(self.keyLabel.mas_trailing).mas_offset(10); if (self.textData.showAccessory) { make.trailing.mas_equalTo(self.contentView.mas_trailing).mas_offset(-10); } else { make.trailing.mas_equalTo(self.contentView.mas_trailing).mas_offset(-20); } make.centerY.mas_equalTo(self.contentView); }]; } @end ///////////////////////////////////////////////////////////////////////////////// // // TUICommonSwitchCell & data // ///////////////////////////////////////////////////////////////////////////////// @implementation TUICommonSwitchCellData - (instancetype)init { self = [super init]; _margin = 20; return self; } - (CGFloat)heightOfWidth:(CGFloat)width { CGFloat height = [super heightOfWidth:width]; if (self.desc.length > 0) { NSString *str = self.desc; NSDictionary *attribute = @{NSFontAttributeName : [UIFont systemFontOfSize:12]}; CGSize size = [str boundingRectWithSize:CGSizeMake(264, 999) options:NSStringDrawingTruncatesLastVisibleLine | NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading attributes:attribute context:nil] .size; height += size.height + 10; } return height; } @end @interface TUICommonSwitchCell () @property TUICommonSwitchCellData *switchData; @property(nonatomic, strong) UIView *leftSeparatorLine; @end @implementation TUICommonSwitchCell - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) { _titleLabel = [[UILabel alloc] init]; _titleLabel.textColor = TIMCommonDynamicColor(@"form_key_text_color", @"#444444"); _titleLabel.font = [UIFont systemFontOfSize:16]; [_titleLabel setRtlAlignment:TUITextRTLAlignmentLeading]; [self.contentView addSubview:_titleLabel]; _descLabel = [[UILabel alloc] init]; _descLabel.textColor = TIMCommonDynamicColor(@"group_modify_desc_color", @"#888888"); _descLabel.font = [UIFont systemFontOfSize:12]; _descLabel.numberOfLines = 0; [_descLabel setRtlAlignment:TUITextRTLAlignmentLeading]; _descLabel.hidden = YES; [self.contentView addSubview:_descLabel]; _switcher = [[UISwitch alloc] init]; _switcher.onTintColor = TIMCommonDynamicColor(@"common_switch_on_color", @"#147AFF"); self.accessoryView = _switcher; [self.contentView addSubview:_switcher]; [_switcher addTarget:self action:@selector(switchClick) forControlEvents:UIControlEventValueChanged]; _leftSeparatorLine = [[UIView alloc] init]; _leftSeparatorLine.backgroundColor = [[UIColor grayColor] colorWithAlphaComponent:0.3]; [self.contentView addSubview:_leftSeparatorLine]; self.selectionStyle = UITableViewCellSelectionStyleNone; } return self; } - (void)layoutSubviews { [super layoutSubviews]; } - (void)fillWithData:(TUICommonSwitchCellData *)switchData { [super fillWithData:switchData]; self.switchData = switchData; _titleLabel.text = switchData.title; [_switcher setOn:switchData.isOn]; _descLabel.text = switchData.desc; // tell constraints they need updating [self setNeedsUpdateConstraints]; // update constraints now so we can animate the change [self updateConstraintsIfNeeded]; [self layoutIfNeeded]; } + (BOOL)requiresConstraintBasedLayout { return YES; } // this is Apple's recommended place for adding/updating constraints - (void)updateConstraints { [super updateConstraints]; if (self.switchData.disableChecked) { _titleLabel.textColor = [UIColor grayColor]; _titleLabel.alpha = 0.4; _switcher.alpha = 0.4; self.userInteractionEnabled = NO; } else { _titleLabel.alpha = 1; _switcher.alpha = 1; _titleLabel.textColor = TIMCommonDynamicColor(@"form_key_text_color", @"#444444"); _switcher.onTintColor = TIMCommonDynamicColor(@"common_switch_on_color", @"#147AFF"); self.userInteractionEnabled = YES; } CGFloat leftMargin = 0; CGFloat padding = 5; if (self.switchData.displaySeparatorLine) { _leftSeparatorLine.mm_width(10).mm_height(2).mm_left(self.switchData.margin).mm__centerY(self.contentView.mm_h / 2); leftMargin = self.switchData.margin + _leftSeparatorLine.mm_w + padding; } else { _leftSeparatorLine.mm_width(0).mm_height(0); leftMargin = self.switchData.margin; } if (self.switchData.desc.length > 0) { _descLabel.text = self.switchData.desc; _descLabel.hidden = NO; NSString *str = self.switchData.desc; NSDictionary *attribute = @{NSFontAttributeName : [UIFont systemFontOfSize:12]}; CGSize size = [str boundingRectWithSize:CGSizeMake(264, 999) options:NSStringDrawingTruncatesLastVisibleLine | NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading attributes:attribute context:nil] .size; [self.titleLabel mas_remakeConstraints:^(MASConstraintMaker *make) { make.width.mas_equalTo(size.width); make.height.mas_equalTo(24); make.leading.mas_equalTo(leftMargin); make.top.mas_equalTo(12); }]; [self.descLabel mas_remakeConstraints:^(MASConstraintMaker *make) { make.width.mas_equalTo(size.width); make.height.mas_equalTo(size.height); make.leading.mas_equalTo(self.titleLabel.mas_leading); make.top.mas_equalTo(self.titleLabel.mas_bottom).mas_offset(2); }]; } else { _descLabel.text = @""; [self.titleLabel sizeToFit]; [self.titleLabel mas_remakeConstraints:^(MASConstraintMaker *make) { make.size.mas_equalTo(self.titleLabel.frame.size); make.leading.mas_equalTo(self.switchData.margin); make.centerY.mas_equalTo(self.contentView); }]; } } - (void)switchClick { if (self.switchData.cswitchSelector) { UIViewController *vc = self.mm_viewController; if ([vc respondsToSelector:self.switchData.cswitchSelector]) { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-performSelector-leaks" [vc performSelector:self.switchData.cswitchSelector withObject:self]; #pragma clang diagnostic pop } } } @end ///////////////////////////////////////////////////////////////////////////////// // // TUIGroupPendencyCell & data // ///////////////////////////////////////////////////////////////////////////////// @interface TUIGroupPendencyCellData () @property V2TIMUserFullInfo *fromUserProfile; @property V2TIMGroupApplication *pendencyItem; @end @implementation TUIGroupPendencyCellData - (instancetype)initWithPendency:(V2TIMGroupApplication *)args { self = [self init]; _pendencyItem = args; _groupId = args.groupID; _fromUser = args.fromUser; _toUser = args.toUser; if (args.fromUserNickName.length > 0) { _title = args.fromUserNickName; } else { _title = args.fromUser; } _avatarUrl = [NSURL URLWithString:args.fromUserFaceUrl]; _requestMsg = args.requestMsg; if (_requestMsg.length == 0) { if (args.applicationType == V2TIM_GROUP_INVITE_APPLICATION_NEED_APPROVED_BY_ADMIN) { _requestMsg = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitInviteJoinGroupFormat), _toUser]; } else { _requestMsg = [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitWhoRequestForJoinGroupFormat), _title]; } } return self; } - (void)accept { [self agreeWithSuccess:nil failure:nil]; } - (void)reject { [self rejectWithSuccess:nil failure:nil]; } - (void)agreeWithSuccess:(TUIGroupPendencyCellDataSuccessCallback)success failure:(TUIGroupPendencyCellDataFailureCallback)failure { [[V2TIMManager sharedInstance] acceptGroupApplication:_pendencyItem reason:TIMCommonLocalizableString(TUIKitAgreedByAdministor) succ:^{ [TUITool makeToast:TIMCommonLocalizableString(Have_been_sent)]; [[NSNotificationCenter defaultCenter] postNotificationName: TUIGroupPendencyCellData_onPendencyChanged object:nil]; if (success) { success(); } ; } fail:^(int code, NSString *msg) { [TUITool makeToastError:code msg:msg]; if (failure) { failure(code,msg); } }]; self.isAccepted = YES; } - (void)rejectWithSuccess:(TUIGroupPendencyCellDataSuccessCallback)success failure:(TUIGroupPendencyCellDataFailureCallback)failure { [[V2TIMManager sharedInstance] refuseGroupApplication:_pendencyItem reason:TIMCommonLocalizableString(TUIkitDiscliedByAdministor) succ:^{ [TUITool makeToast:TIMCommonLocalizableString(Have_been_sent)]; [[NSNotificationCenter defaultCenter] postNotificationName: TUIGroupPendencyCellData_onPendencyChanged object:nil]; if (success) { success(); } } fail:^(int code, NSString *msg) { [TUITool makeToastError:code msg:msg]; if (failure) { failure(code,msg); } }]; self.isRejectd = YES; } @end @implementation TUIGroupPendencyCell - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; self.avatarView = [[UIImageView alloc] initWithImage:DefaultAvatarImage]; [self.contentView addSubview:self.avatarView]; self.avatarView.mm_width(54).mm_height(54).mm__centerY(38).mm_left(12); self.titleLabel = [[UILabel alloc] initWithFrame:CGRectZero]; [self.contentView addSubview:self.titleLabel]; self.titleLabel.textColor = [UIColor darkTextColor]; self.titleLabel.mm_left(self.avatarView.mm_maxX + 12).mm_top(14).mm_height(20).mm_width(120); self.addWordingLabel = [[UILabel alloc] initWithFrame:CGRectZero]; [self.contentView addSubview:self.addWordingLabel]; self.addWordingLabel.textColor = [UIColor lightGrayColor]; self.addWordingLabel.font = [UIFont systemFontOfSize:15]; self.addWordingLabel.mm_left(self.titleLabel.mm_x).mm_top(self.titleLabel.mm_maxY + 6).mm_height(15).mm_width(self.mm_w - self.titleLabel.mm_x - 80); self.agreeButton = [UIButton buttonWithType:UIButtonTypeSystem]; self.accessoryView = self.agreeButton; [self.agreeButton addTarget:self action:@selector(agreeClick) forControlEvents:UIControlEventTouchUpInside]; return self; } - (void)awakeFromNib { [super awakeFromNib]; // Initialization code } - (void)setSelected:(BOOL)selected animated:(BOOL)animated { [super setSelected:selected animated:animated]; // Configure the view for the selected state } - (void)fillWithData:(TUIGroupPendencyCellData *)pendencyData { [super fillWithData:pendencyData]; self.pendencyData = pendencyData; self.titleLabel.text = pendencyData.title; self.addWordingLabel.text = pendencyData.requestMsg; self.avatarView.image = DefaultAvatarImage; if (pendencyData.avatarUrl) { [self.avatarView sd_setImageWithURL:pendencyData.avatarUrl placeholderImage:[UIImage imageNamed:TIMCommonImagePath(@"default_c2c_head")]]; } @weakify(self); [[RACObserve(pendencyData, isAccepted) takeUntil:self.rac_prepareForReuseSignal] subscribeNext:^(NSNumber *isAccepted) { @strongify(self); if ([isAccepted boolValue]) { [self.agreeButton setTitle:TIMCommonLocalizableString(Agreed) forState:UIControlStateNormal]; self.agreeButton.enabled = NO; [self.agreeButton setTitleColor:[UIColor lightGrayColor] forState:UIControlStateNormal]; self.agreeButton.layer.borderColor = [UIColor clearColor].CGColor; } }]; [[RACObserve(pendencyData, isRejectd) takeUntil:self.rac_prepareForReuseSignal] subscribeNext:^(NSNumber *isAccepted) { @strongify(self); if ([isAccepted boolValue]) { [self.agreeButton setTitle:TIMCommonLocalizableString(Disclined) forState:UIControlStateNormal]; self.agreeButton.enabled = NO; [self.agreeButton setTitleColor:[UIColor lightGrayColor] forState:UIControlStateNormal]; self.agreeButton.layer.borderColor = [UIColor clearColor].CGColor; } }]; if (!(pendencyData.isAccepted || pendencyData.isRejectd)) { [self.agreeButton setTitle:TIMCommonLocalizableString(Agree) forState:UIControlStateNormal]; self.agreeButton.enabled = YES; [self.agreeButton setTitleColor:[UIColor darkTextColor] forState:UIControlStateNormal]; self.agreeButton.layer.borderColor = [UIColor grayColor].CGColor; self.agreeButton.layer.borderWidth = 1; } self.agreeButton.mm_sizeToFit().mm_width(self.agreeButton.mm_w + 20); } - (void)agreeClick { if (self.pendencyData.cbuttonSelector) { UIViewController *vc = self.mm_viewController; if ([vc respondsToSelector:self.pendencyData.cbuttonSelector]) { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-performSelector-leaks" [vc performSelector:self.pendencyData.cbuttonSelector withObject:self]; #pragma clang diagnostic pop } } } - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch { if ((touch.view == self.agreeButton)) { return NO; } return YES; } @end ///////////////////////////////////////////////////////////////////////////////// // // TUIButtonCell & data // ///////////////////////////////////////////////////////////////////////////////// @implementation TUIButtonCellData - (CGFloat)heightOfWidth:(CGFloat)width { return TButtonCell_Height; } @end @implementation TUIButtonCell { UIView *_line; } - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; if (self) { [self setupViews]; self.changeColorWhenTouched = YES; } return self; } - (void)setupViews { self.backgroundColor = TIMCommonDynamicColor(@"form_bg_color", @"#FFFFFF"); self.contentView.backgroundColor = TIMCommonDynamicColor(@"form_bg_color", @"#FFFFFF"); _button = [UIButton buttonWithType:UIButtonTypeCustom]; [_button.titleLabel setFont:[UIFont systemFontOfSize:18]]; [_button addTarget:self action:@selector(onClick:) forControlEvents:UIControlEventTouchUpInside]; [self.contentView addSubview:_button]; [self setSeparatorInset:UIEdgeInsetsMake(0, Screen_Width, 0, 0)]; [self setSelectionStyle:UITableViewCellSelectionStyleNone]; self.changeColorWhenTouched = YES; _line = [[UIView alloc] initWithFrame:CGRectZero]; [self.contentView addSubview:_line]; _line.backgroundColor = TIMCommonDynamicColor(@"separator_color", @"#DBDBDB"); } - (void)fillWithData:(TUIButtonCellData *)data { [super fillWithData:data]; self.buttonData = data; [_button setTitle:data.title forState:UIControlStateNormal]; switch (data.style) { case ButtonGreen: { [_button setTitleColor:TIMCommonDynamicColor(@"form_green_button_text_color", @"#FFFFFF") forState:UIControlStateNormal]; _button.backgroundColor = TIMCommonDynamicColor(@"form_green_button_bg_color", @"#232323"); [_button setBackgroundImage:[self imageWithColor:TIMCommonDynamicColor(@"form_green_button_highlight_bg_color", @"#179A1A")] forState:UIControlStateHighlighted]; } break; case ButtonWhite: { [_button setTitleColor:TIMCommonDynamicColor(@"form_white_button_text_color", @"#000000") forState:UIControlStateNormal]; _button.backgroundColor = TIMCommonDynamicColor(@"form_white_button_bg_color", @"#FFFFFF"); } break; case ButtonRedText: { [_button setTitleColor:TIMCommonDynamicColor(@"form_redtext_button_text_color", @"#FF0000") forState:UIControlStateNormal]; _button.backgroundColor = TIMCommonDynamicColor(@"form_redtext_button_bg_color", @"#FFFFFF"); break; } case ButtonBule: { [_button.titleLabel setTextColor:TIMCommonDynamicColor(@"form_blue_button_text_color", @"#FFFFFF")]; _button.backgroundColor = TIMCommonDynamicColor(@"form_blue_button_bg_color", @"#1E90FF"); [_button setBackgroundImage:[self imageWithColor:TIMCommonDynamicColor(@"form_blue_button_highlight_bg_color", @"#1978D5")] forState:UIControlStateHighlighted]; } break; default: break; } if (data.textColor) { [_button setTitleColor:data.textColor forState:UIControlStateNormal]; } _line.hidden = data.hideSeparatorLine; } - (void)layoutSubviews { [super layoutSubviews]; _button.mm_width(Screen_Width - 2 * TButtonCell_Margin).mm_height(self.mm_h - TButtonCell_Margin).mm_left(TButtonCell_Margin); _line.mm_width(Screen_Width).mm_height(0.2).mm_left(20).mm_bottom(0); } - (void)onClick:(UIButton *)sender { if (self.buttonData.cbuttonSelector) { UIViewController *vc = self.mm_viewController; if ([vc respondsToSelector:self.buttonData.cbuttonSelector]) { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-performSelector-leaks" [vc performSelector:self.buttonData.cbuttonSelector withObject:self]; #pragma clang diagnostic pop } } } - (void)didAddSubview:(UIView *)subview { [super didAddSubview:subview]; if (subview != self.contentView) { [subview removeFromSuperview]; } } - (UIImage *)imageWithColor:(UIColor *)color { CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f); UIGraphicsBeginImageContext(rect.size); CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetFillColorWithColor(context, [color CGColor]); CGContextFillRect(context, rect); UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return image; } @end ///////////////////////////////////////////////////////////////////////////////// // // TUIFaceCell & data // ///////////////////////////////////////////////////////////////////////////////// @implementation TUIFaceCellData @end @implementation TUIFaceCell - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { [self setupViews]; [self defaultLayout]; } return self; } - (void)setupViews { _face = [[UIImageView alloc] init]; _face.contentMode = UIViewContentModeScaleAspectFill; [self addSubview:_face]; UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(onLongPress:)]; [self addGestureRecognizer:longPress]; [self setUserInteractionEnabled:YES]; } - (void)defaultLayout { CGSize size = self.frame.size; _face.frame = CGRectMake(0, 0, size.width, size.height); } #define kTUIFaceCellAllowDynamicImageShow 0 - (void)setData:(TUIFaceCellData *)data { if (!kTUIFaceCellAllowDynamicImageShow) { UIImage * image = [[TUIImageCache sharedInstance] getFaceFromCache:data.path]; SDImageFormat imageFormat = [image sd_imageFormat]; if (SDImageFormatGIF == imageFormat ) { self.gifImage = image; if (image.images.count > 1) { self.staicImage = image.images[0]; } } else { self.staicImage = image; } _face.image = self.staicImage; } else { _face.image = [[TUIImageCache sharedInstance] getFaceFromCache:data.path]; } [self defaultLayout]; } - (void)onLongPress:(UILongPressGestureRecognizer *)longPress { if (self.longPressCallback) { self.longPressCallback(longPress); } } @end ///////////////////////////////////////////////////////////////////////////////// // // TUIFaceGroup // ///////////////////////////////////////////////////////////////////////////////// @implementation TUIFaceGroup - (NSDictionary *)facesMap { if (!_facesMap || (_facesMap.count != _faces.count )) { NSMutableDictionary *faceDic = [NSMutableDictionary dictionaryWithCapacity:3]; if (_faces.count > 0) { for (TUIFaceCellData *data in _faces) { [faceDic setObject:data.path forKey:data.name]; } } _facesMap = [NSDictionary dictionaryWithDictionary:faceDic]; } return _facesMap; } @end @implementation TUIEmojiTextAttachment - (CGRect)attachmentBoundsForTextContainer:(NSTextContainer *)textContainer proposedLineFragment:(CGRect)lineFrag glyphPosition:(CGPoint)position characterIndex:(NSUInteger)charIndex { return CGRectMake( 0 , -0.4* lineFrag.size.height, kTIMDefaultEmojiSize.width , kTIMDefaultEmojiSize.height); } @end ///////////////////////////////////////////////////////////////////////////////// // // TUIUnReadView // ///////////////////////////////////////////////////////////////////////////////// @implementation TUIUnReadView - (id)init { self = [super init]; if (self) { [self setupViews]; [self defaultLayout]; } return self; } - (void)setNum:(NSInteger)num { NSString *unReadStr = [[NSNumber numberWithInteger:num] stringValue]; if (num > 99) { unReadStr = @"99+"; } _unReadLabel.text = unReadStr; self.hidden = (num == 0 ? YES : NO); [self defaultLayout]; } - (void)setupViews { _unReadLabel = [[UILabel alloc] init]; _unReadLabel.text = @"11"; _unReadLabel.font = [UIFont systemFontOfSize:12]; _unReadLabel.textColor = [UIColor whiteColor]; _unReadLabel.textAlignment = NSTextAlignmentCenter; [_unReadLabel sizeToFit]; [self addSubview:_unReadLabel]; self.layer.cornerRadius = (_unReadLabel.frame.size.height + TUnReadView_Margin_TB * 2) / 2.0; [self.layer masksToBounds]; self.backgroundColor = [UIColor redColor]; self.hidden = YES; } - (void)defaultLayout { [_unReadLabel sizeToFit]; CGFloat width = _unReadLabel.frame.size.width + 2 * TUnReadView_Margin_LR; CGFloat height = _unReadLabel.frame.size.height + 2 * TUnReadView_Margin_TB; if (width < height) { width = height; } self.bounds = CGRectMake(0, 0, width, height); _unReadLabel.frame = self.bounds; } - (void)layoutSubviews { [super layoutSubviews]; if (@available(iOS 11.0, *)) { // Here is a workaround on iOS 11 UINavigationBarItem init with custom view, position issue UIView *view = self; while (![view isKindOfClass:[UINavigationBar class]] && [view superview] != nil) { view = [view superview]; if ([view isKindOfClass:[UIStackView class]] && [view superview] != nil) { CGFloat margin = 40.0f; // margin = 4.0f; [view.superview addConstraint:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:view.superview attribute:NSLayoutAttributeLeading multiplier:1.0 constant:margin]]; break; } } } } @end ///////////////////////////////////////////////////////////////////////////////// // // TUIConversationPin // ///////////////////////////////////////////////////////////////////////////////// #define TOP_CONV_KEY @"TUIKIT_TOP_CONV_KEY" NSString *kTopConversationListChangedNotification = @"kTopConversationListChangedNotification"; @implementation TUIConversationPin + (instancetype)sharedInstance { static TUIConversationPin *instance; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ instance = [TUIConversationPin new]; }); return instance; } - (NSArray *)topConversationList { #ifndef SDKPlaceTop #define SDKPlaceTop #endif #ifdef SDKPlaceTop return @[]; #else NSArray *list = [[NSUserDefaults standardUserDefaults] objectForKey:TOP_CONV_KEY]; if ([list isKindOfClass:[NSArray class]]) { return list; } return @[]; #endif } - (void)addTopConversation:(NSString *)conv callback:(void (^)(BOOL success, NSString *errorMessage))callback { #ifndef SDKPlaceTop #define SDKPlaceTop #endif #ifdef SDKPlaceTop [V2TIMManager.sharedInstance pinConversation:conv isPinned:YES succ:^{ if (callback) { callback(YES, nil); } } fail:^(int code, NSString *desc) { if (callback) { callback(NO, desc); } }]; #else [TUITool dispatchMainAsync:^{ NSMutableArray *list = [self topConversationList].mutableCopy; if ([list containsObject:conv]) { [list removeObject:conv]; } [list insertObject:conv atIndex:0]; [[NSUserDefaults standardUserDefaults] setValue:list forKey:TOP_CONV_KEY]; [[NSNotificationCenter defaultCenter] postNotificationName:kTopConversationListChangedNotification object:nil]; if (callback) { callback(YES, nil); } }]; #endif } - (void)removeTopConversation:(NSString *)conv callback:(void (^)(BOOL success, NSString *errorMessage))callback { #ifndef SDKPlaceTop #define SDKPlaceTop #endif #ifdef SDKPlaceTop [V2TIMManager.sharedInstance pinConversation:conv isPinned:NO succ:^{ if (callback) { callback(YES, nil); } } fail:^(int code, NSString *desc) { if (callback) { callback(NO, desc); } }]; #else [TUITool dispatchMainAsync:^{ NSMutableArray *list = [self topConversationList].mutableCopy; if ([list containsObject:conv]) { [list removeObject:conv]; [[NSUserDefaults standardUserDefaults] setValue:list forKey:TOP_CONV_KEY]; [[NSNotificationCenter defaultCenter] postNotificationName:kTopConversationListChangedNotification object:nil]; } if (callback) { callback(YES, nil); } }]; #endif } @end ///////////////////////////////////////////////////////////////////////////////// // // TUICommonContactSelectCellData // ///////////////////////////////////////////////////////////////////////////////// @implementation TUICommonContactSelectCellData - (instancetype)init { self = [super init]; if (self) { _enabled = YES; } return self; } - (NSComparisonResult)compare:(TUICommonContactSelectCellData *)data { return [self.title localizedCompare:data.title]; } @end ///////////////////////////////////////////////////////////////////////////////// // // TUICommonContactListPickerCell // ///////////////////////////////////////////////////////////////////////////////// @implementation TUICommonContactListPickerCell - (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { CGFloat avatarWidth = 35.0; _avatar = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, avatarWidth, avatarWidth)]; [self.contentView addSubview:_avatar]; _avatar.center = CGPointMake(avatarWidth / 2.0, avatarWidth / 2.0); _avatar.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin; } return self; } - (void)layoutSubviews { [super layoutSubviews]; if ([TUIConfig defaultConfig].avatarType == TAvatarTypeRounded) { _avatar.layer.masksToBounds = YES; _avatar.layer.cornerRadius = _avatar.frame.size.height / 2; } else if ([TUIConfig defaultConfig].avatarType == TAvatarTypeRadiusCorner) { _avatar.layer.masksToBounds = YES; _avatar.layer.cornerRadius = [TUIConfig defaultConfig].avatarCornerRadius; } } @end ///////////////////////////////////////////////////////////////////////////////// // // TUIContactListPickerOnCancel // ///////////////////////////////////////////////////////////////////////////////// @interface TUIContactListPicker () @property(nonatomic) UICollectionView *collectionView; @property(nonatomic) UIButton *accessoryBtn; @end @implementation TUIContactListPicker - (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; [self initControl]; [self setupBinding]; return self; } - (void)initControl { UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; layout.scrollDirection = UICollectionViewScrollDirectionHorizontal; self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout]; self.collectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; self.collectionView.showsHorizontalScrollIndicator = NO; self.collectionView.decelerationRate = UIScrollViewDecelerationRateNormal; [self.collectionView registerClass:[TUICommonContactListPickerCell class] forCellWithReuseIdentifier:@"PickerIdentifier"]; [self.collectionView setBackgroundColor:[UIColor clearColor]]; [self.collectionView setDelegate:self]; [self.collectionView setDataSource:self]; [self addSubview:_collectionView]; self.accessoryBtn = [UIButton buttonWithType:UIButtonTypeCustom]; [self.accessoryBtn setBackgroundImage:TIMCommonBundleImage(@"icon_cell_blue_normal") forState:UIControlStateNormal]; [self.accessoryBtn setBackgroundImage:TIMCommonBundleImage(@"icon_cell_blue_normal") forState:UIControlStateHighlighted]; [self.accessoryBtn setTitle:[NSString stringWithFormat:@" %@ ", TIMCommonLocalizableString(Confirm)] forState:UIControlStateNormal]; self.accessoryBtn.enabled = NO; [self addSubview:self.accessoryBtn]; } - (void)setupBinding { [self addObserver:self forKeyPath:@"selectArray" options:NSKeyValueObservingOptionNew context:nil]; } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if ([keyPath isEqualToString:@"selectArray"]) { [self.collectionView reloadData]; NSArray *newSelectArray = change[NSKeyValueChangeNewKey]; if ([newSelectArray isKindOfClass:NSArray.class]) { self.accessoryBtn.enabled = [newSelectArray count]; } } } - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { return [self.selectArray count]; } - (CGSize)collectionView:(nonnull UICollectionView *)collectionView layout:(nonnull UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(nonnull NSIndexPath *)indexPath { return CGSizeMake(35, collectionView.bounds.size.height); } - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { TUICommonContactListPickerCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"PickerIdentifier" forIndexPath:indexPath]; TUICommonContactSelectCellData *data = self.selectArray[indexPath.row]; if (data.avatarUrl) { [cell.avatar sd_setImageWithURL:data.avatarUrl placeholderImage:DefaultAvatarImage]; } else if (data.avatarImage) { cell.avatar.image = data.avatarImage; } else { cell.avatar.image = DefaultAvatarImage; } return cell; } - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { [collectionView deselectItemAtIndexPath:indexPath animated:NO]; if (indexPath.item >= self.selectArray.count) { return; } TUICommonContactSelectCellData *data = self.selectArray[indexPath.item]; if (self.onCancel) { self.onCancel(data); } } - (void)layoutSubviews { [super layoutSubviews]; self.accessoryBtn.mm_sizeToFit().mm_height(30).mm_right(15).mm_top(13); self.collectionView.mm_left(15).mm_height(40).mm_width(self.accessoryBtn.mm_x - 30).mm__centerY(self.accessoryBtn.mm_centerY); if (isRTL()) { [self.accessoryBtn resetFrameToFitRTL]; [self.collectionView resetFrameToFitRTL]; } } @end ///////////////////////////////////////////////////////////////////////////////// // // TUIProfileCardCell & VC // ///////////////////////////////////////////////////////////////////////////////// @implementation TUIProfileCardCellData - (instancetype)init { self = [super init]; if (self) { _avatarImage = DefaultAvatarImage; if ([_genderString isEqualToString:TIMCommonLocalizableString(Male)]) { _genderIconImage = TUIContactCommonBundleImage(@"male"); } else if ([_genderString isEqualToString:TIMCommonLocalizableString(Female)]) { _genderIconImage = TUIContactCommonBundleImage(@"female"); } else { _genderIconImage = nil; } } return self; } - (CGFloat)heightOfWidth:(CGFloat)width { return TPersonalCommonCell_Image_Size.height + 2 * TPersonalCommonCell_Margin + (self.showSignature ? 24 : 0); } @end @implementation TUIProfileCardCell - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; if (self) { [self setupViews]; } return self; } - (void)setupViews { CGSize headSize = TPersonalCommonCell_Image_Size; _avatar = [[UIImageView alloc] initWithFrame:CGRectMake(TPersonalCommonCell_Margin, TPersonalCommonCell_Margin, headSize.width, headSize.height)]; _avatar.contentMode = UIViewContentModeScaleAspectFit; _avatar.layer.cornerRadius = 4; _avatar.layer.masksToBounds = YES; UITapGestureRecognizer *tapAvatar = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onTapAvatar)]; [_avatar addGestureRecognizer:tapAvatar]; _avatar.userInteractionEnabled = YES; if ([TUIConfig defaultConfig].avatarType == TAvatarTypeRounded) { self.avatar.layer.masksToBounds = YES; self.avatar.layer.cornerRadius = headSize.height / 2; } else if ([TUIConfig defaultConfig].avatarType == TAvatarTypeRadiusCorner) { self.avatar.layer.masksToBounds = YES; self.avatar.layer.cornerRadius = [TUIConfig defaultConfig].avatarCornerRadius; } [self.contentView addSubview:_avatar]; // CGSize genderIconSize = CGSizeMake(20, 20); _genderIcon = [[UIImageView alloc] init]; _genderIcon.contentMode = UIViewContentModeScaleAspectFit; _genderIcon.image = self.cardData.genderIconImage; [self.contentView addSubview:_genderIcon]; _name = [[UILabel alloc] init]; [_name setFont:[UIFont boldSystemFontOfSize:18]]; [_name setTextColor:TIMCommonDynamicColor(@"form_title_color", @"#000000")]; [self.contentView addSubview:_name]; _identifier = [[UILabel alloc] init]; [_identifier setFont:[UIFont systemFontOfSize:13]]; [_identifier setTextColor:TIMCommonDynamicColor(@"form_subtitle_color", @"#888888")]; [self.contentView addSubview:_identifier]; _signature = [[UILabel alloc] init]; [_signature setFont:[UIFont systemFontOfSize:14]]; [_signature setTextColor:TIMCommonDynamicColor(@"form_subtitle_color", @"#888888")]; [self.contentView addSubview:_signature]; self.selectionStyle = UITableViewCellSelectionStyleNone; } - (void)fillWithData:(TUIProfileCardCellData *)data { [super fillWithData:data]; self.cardData = data; _signature.hidden = !data.showSignature; // set data @weakify(self); RAC(_signature, text) = [RACObserve(data, signature) takeUntil:self.rac_prepareForReuseSignal]; [[[RACObserve(data, identifier) takeUntil:self.rac_prepareForReuseSignal] distinctUntilChanged] subscribeNext:^(NSString *x) { @strongify(self); self.identifier.text = [NSString stringWithFormat:@"%@:%@",TIMCommonLocalizableString(TUIKitIdentity),data.identifier]; }]; [[[RACObserve(data, name) takeUntil:self.rac_prepareForReuseSignal] distinctUntilChanged] subscribeNext:^(NSString *x) { @strongify(self); self.name.text = x; [self.name sizeToFit]; }]; [[RACObserve(data, avatarUrl) takeUntil:self.rac_prepareForReuseSignal] subscribeNext:^(NSURL *x) { @strongify(self); [self.avatar sd_setImageWithURL:x placeholderImage:self.cardData.avatarImage]; }]; [[RACObserve(data, genderString) takeUntil:self.rac_prepareForReuseSignal] subscribeNext:^(NSString *x) { @strongify(self); if ([x isEqualToString:TIMCommonLocalizableString(Male)]) { self.genderIcon.image = TUIContactCommonBundleImage(@"male"); } else if ([x isEqualToString:TIMCommonLocalizableString(Female)]) { self.genderIcon.image = TUIContactCommonBundleImage(@"female"); } else { self.genderIcon.image = nil; } }]; if (data.showAccessory) { self.accessoryType = UITableViewCellAccessoryDisclosureIndicator; } else { self.accessoryType = UITableViewCellAccessoryNone; } // tell constraints they need updating [self setNeedsUpdateConstraints]; // update constraints now so we can animate the change [self updateConstraintsIfNeeded]; [self layoutIfNeeded]; } - (void)layoutSubviews { [super layoutSubviews]; } + (BOOL)requiresConstraintBasedLayout { return YES; } // this is Apple's recommended place for adding/updating constraints - (void)updateConstraints { [super updateConstraints]; CGSize headSize = CGSizeMake(kScale390(66), kScale390(66)); [self.avatar mas_remakeConstraints:^(MASConstraintMaker *make) { make.size.mas_equalTo(headSize); make.top.mas_equalTo(kScale390(10)); make.leading.mas_equalTo(kScale390(16)); }]; if ([TUIConfig defaultConfig].avatarType == TAvatarTypeRounded) { self.avatar.layer.masksToBounds = YES; self.avatar.layer.cornerRadius = headSize.height / 2; } else if ([TUIConfig defaultConfig].avatarType == TAvatarTypeRadiusCorner) { self.avatar.layer.masksToBounds = YES; self.avatar.layer.cornerRadius = [TUIConfig defaultConfig].avatarCornerRadius; } [self.name sizeToFit]; [self.name mas_remakeConstraints:^(MASConstraintMaker *make) { make.top.mas_equalTo(TPersonalCommonCell_Margin); make.leading.mas_equalTo(self.avatar.mas_trailing).mas_offset(15); make.width.mas_lessThanOrEqualTo(self.name.frame.size.width); make.height.mas_greaterThanOrEqualTo(self.name.frame.size.height); make.trailing.mas_lessThanOrEqualTo(self.genderIcon.mas_leading).mas_offset(- 1); }]; [self.genderIcon mas_remakeConstraints:^(MASConstraintMaker *make) { make.width.height.mas_equalTo(self.name.font.pointSize *0.9); make.centerY.mas_equalTo(self.name); make.leading.mas_equalTo(self.name.mas_trailing).mas_offset(1); make.trailing.mas_lessThanOrEqualTo(self.contentView.mas_trailing).mas_offset(- 10); }]; [self.identifier sizeToFit]; [self.identifier mas_remakeConstraints:^(MASConstraintMaker *make) { make.leading.mas_equalTo(self.name); make.top.mas_equalTo(self.name.mas_bottom).mas_offset(5); if(self.identifier.frame.size.width > 80) { make.width.mas_greaterThanOrEqualTo(self.identifier.frame.size.width); } else { make.width.mas_greaterThanOrEqualTo(@80); } make.height.mas_greaterThanOrEqualTo(self.identifier.frame.size.height); make.trailing.mas_lessThanOrEqualTo(self.contentView.mas_trailing).mas_offset(-1); }]; if (self.cardData.showSignature) { [self.signature sizeToFit]; [self.signature mas_remakeConstraints:^(MASConstraintMaker *make) { make.leading.mas_equalTo(self.name); make.top.mas_equalTo(self.identifier.mas_bottom).mas_offset(5); if(self.signature.frame.size.width > 80) { make.width.mas_greaterThanOrEqualTo(self.signature.frame.size.width); } else { make.width.mas_greaterThanOrEqualTo(@80); } make.height.mas_greaterThanOrEqualTo(self.signature.frame.size.height); make.trailing.mas_lessThanOrEqualTo(self.contentView.mas_trailing).mas_offset(-1); }]; } else { self.signature.frame = CGRectZero; } } - (void)onTapAvatar { if (_delegate && [_delegate respondsToSelector:@selector(didTapOnAvatar:)]) [_delegate didTapOnAvatar:self]; } @end @interface TUIAvatarViewController () @property UIImageView *avatarView; @property TUIScrollView *avatarScrollView; @property UIImage *saveBackgroundImage; @property UIImage *saveShadowImage; @end @implementation TUIAvatarViewController - (void)viewDidLoad { [super viewDidLoad]; self.saveBackgroundImage = [self.navigationController.navigationBar backgroundImageForBarMetrics:UIBarMetricsDefault]; self.saveShadowImage = self.navigationController.navigationBar.shadowImage; [self.navigationController.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault]; self.navigationController.navigationBar.shadowImage = [UIImage new]; CGRect rect = self.view.bounds; self.avatarScrollView = [[TUIScrollView alloc] initWithFrame:CGRectZero]; [self.view addSubview:self.avatarScrollView]; self.avatarScrollView.backgroundColor = [UIColor blackColor]; self.avatarScrollView.frame = rect; self.avatarView = [[UIImageView alloc] initWithImage:self.avatarData.avatarImage]; self.avatarScrollView.imageView = self.avatarView; self.avatarScrollView.maximumZoomScale = 4.0; self.avatarScrollView.delegate = self; self.avatarView.image = self.avatarData.avatarImage; TUIProfileCardCellData *data = self.avatarData; /* @weakify(self); [RACObserve(data, avatarUrl) subscribeNext:^(NSURL *x) { @strongify(self); [self.avatarView sd_setImageWithURL:x placeholderImage:self.avatarData.avatarImage]; }]; */ @weakify(self); [RACObserve(data, avatarUrl) subscribeNext:^(NSURL *x) { @strongify(self); [self.avatarView sd_setImageWithURL:x placeholderImage:self.avatarData.avatarImage]; [self.avatarScrollView setNeedsLayout]; }]; } - (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView { return self.avatarView; } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; [[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationNone]; [self.navigationController.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault]; self.navigationController.navigationBar.shadowImage = [UIImage new]; self.navigationController.navigationBar.backgroundColor = [UIColor clearColor]; } - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; [[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationNone]; } - (void)willMoveToParentViewController:(UIViewController *)parent { if (parent == nil) { [self.navigationController.navigationBar setBackgroundImage:self.saveBackgroundImage forBarMetrics:UIBarMetricsDefault]; self.navigationController.navigationBar.shadowImage = self.saveShadowImage; } } @end #define UserAvatarURL(x) [NSString stringWithFormat:@"https://im.sdk.qcloud.com/download/tuikit-resource/avatar/avatar_%d.png", x] #define UserAvatarCount 26 #define GroupAvatarURL(x) [NSString stringWithFormat:@"https://im.sdk.qcloud.com/download/tuikit-resource/group-avatar/group_avatar_%d.png", x] #define GroupAvatarCount 24 #define Community_coverURL(x) [NSString stringWithFormat:@"https://im.sdk.qcloud.com/download/tuikit-resource/community-cover/community_cover_%d.png", x] #define Community_coverCount 12 #define BackGroundCoverURL(x) \ [NSString stringWithFormat:@"https://im.sdk.qcloud.com/download/tuikit-resource/conversation-backgroundImage/backgroundImage_%d.png", x] #define BackGroundCoverURL_full(x) \ [NSString stringWithFormat:@"https://im.sdk.qcloud.com/download/tuikit-resource/conversation-backgroundImage/backgroundImage_%d_full.png", x] #define BackGroundCoverCount 7 @implementation TUISelectAvatarCardItem @end @interface TUISelectAvatarCollectionCell : UICollectionViewCell @property(nonatomic, strong) UIImageView *imageView; @property(nonatomic, strong) UIImageView *selectedView; @property(nonatomic, strong) UIView *maskView; @property(nonatomic, strong) UILabel *descLabel; @property(nonatomic, strong) TUISelectAvatarCardItem *cardItem; - (void)updateSelectedUI; @end @implementation TUISelectAvatarCollectionCell - (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { self.imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)]; [self.imageView setUserInteractionEnabled:YES]; self.imageView.layer.cornerRadius = [TUIConfig defaultConfig].avatarCornerRadius; self.imageView.layer.borderWidth = 2; self.imageView.layer.masksToBounds = YES; [self.contentView addSubview:self.imageView]; [self.imageView addSubview:self.selectedView]; [self setupMaskView]; } return self; } - (void)layoutSubviews { [self updateCellView]; self.selectedView.frame = CGRectMake(self.imageView.frame.size.width - 16 - 4, 4, 16, 16); } - (void)updateCellView { [self updateSelectedUI]; [self updateImageView]; [self updateMaskView]; } - (void)updateSelectedUI { if (self.cardItem.isSelect) { self.imageView.layer.borderColor = TIMCommonDynamicColor(@"", @"#006EFF").CGColor; self.selectedView.hidden = NO; } else { if (self.cardItem.isDefaultBackgroundItem) { self.imageView.layer.borderColor = [[UIColor grayColor] colorWithAlphaComponent:0.1].CGColor; } else { self.imageView.layer.borderColor = UIColor.clearColor.CGColor; } self.selectedView.hidden = YES; } } - (void)updateImageView { if (self.cardItem.isGroupGridAvatar) { [self updateNormalGroupGridAvatar]; } else { [self.imageView sd_setImageWithURL:[NSURL URLWithString:self.cardItem.posterUrlStr] placeholderImage:TIMCommonBundleThemeImage(@"default_c2c_head_img", @"default_c2c_head_img")]; } } - (void)updateMaskView { if (self.cardItem.isDefaultBackgroundItem) { self.maskView.hidden = NO; self.maskView.frame = CGRectMake(0, self.imageView.frame.size.height - 28, self.imageView.frame.size.width, 28); [self.descLabel sizeToFit]; self.descLabel.tui_mm_center(); } else { self.maskView.hidden = YES; } } - (void)updateNormalGroupGridAvatar { if (TUIConfig.defaultConfig.enableGroupGridAvatar && self.cardItem.cacheGroupGridAvatarImage) { [self.imageView sd_setImageWithURL:nil placeholderImage:self.cardItem.cacheGroupGridAvatarImage]; } } - (void)setupMaskView { self.maskView = [[UIView alloc] initWithFrame:CGRectZero]; self.maskView.backgroundColor = [UIColor tui_colorWithHex:@"cccccc"]; [self.imageView addSubview:self.maskView]; self.descLabel = [[UILabel alloc] initWithFrame:CGRectZero]; self.descLabel.text = TIMCommonLocalizableString(TUIKitDefaultBackground); self.descLabel.textColor = [UIColor whiteColor]; self.descLabel.font = [UIFont systemFontOfSize:13]; [self.maskView addSubview:self.descLabel]; [self.descLabel sizeToFit]; self.descLabel.tui_mm_center(); } - (void)setCardItem:(TUISelectAvatarCardItem *)cardItem { _cardItem = cardItem; } - (UIImageView *)selectedView { if (!_selectedView) { _selectedView = [[UIImageView alloc] initWithFrame:CGRectZero]; _selectedView.image = [UIImage imageNamed:TIMCommonImagePath(@"icon_avatar_selected")]; } return _selectedView; } @end @interface TUISelectAvatarController () @property(nonatomic, strong) TUINaviBarIndicatorView *titleView; @property(nonatomic, strong) UICollectionView *collectionView; @property(nonatomic, strong) NSMutableArray *dataArr; @property(nonatomic, strong) TUISelectAvatarCardItem *currentSelectCardItem; @property(nonatomic, strong) UIButton *rightButton; @end @implementation TUISelectAvatarController static NSString *const reuseIdentifier = @"TUISelectAvatarCollectionCell"; - (instancetype)init { if (self = [super init]) { self.selectAvatarType = TUISelectAvatarTypeUserAvatar; } return self; } - (void)viewDidLoad { [super viewDidLoad]; UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init]; [flowLayout setScrollDirection:UICollectionViewScrollDirectionVertical]; CGRect frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height); self.collectionView = [[UICollectionView alloc] initWithFrame:frame collectionViewLayout:flowLayout]; [self.view addSubview:self.collectionView]; self.collectionView.backgroundColor = TIMCommonDynamicColor(@"controller_bg_color", @"#F2F3F5"); self.collectionView.dataSource = self; self.collectionView.delegate = self; // Register cell classes [self.collectionView registerClass:[TUISelectAvatarCollectionCell class] forCellWithReuseIdentifier:reuseIdentifier]; // Do any additional setup after loading the view. [self setupNavigator]; self.dataArr = [NSMutableArray arrayWithCapacity:3]; [self loadData]; } - (void)loadData { if (self.selectAvatarType == TUISelectAvatarTypeUserAvatar) { for (int i = 0; i < UserAvatarCount; i++) { TUISelectAvatarCardItem *cardItem = [self creatCardItemByURL:UserAvatarURL(i + 1)]; [self.dataArr addObject:cardItem]; } } else if (self.selectAvatarType == TUISelectAvatarTypeGroupAvatar) { if (TUIConfig.defaultConfig.enableGroupGridAvatar && self.cacheGroupGridAvatarImage) { TUISelectAvatarCardItem *cardItem = [self creatGroupGridAvatarCardItem]; [self.dataArr addObject:cardItem]; } for (int i = 0; i < GroupAvatarCount; i++) { TUISelectAvatarCardItem *cardItem = [self creatCardItemByURL:GroupAvatarURL(i + 1)]; [self.dataArr addObject:cardItem]; } } else if (self.selectAvatarType == TUISelectAvatarTypeConversationBackGroundCover) { TUISelectAvatarCardItem *cardItem = [self creatCleanCardItem]; [self.dataArr addObject:cardItem]; for (int i = 0; i < BackGroundCoverCount; i++) { TUISelectAvatarCardItem *cardItem = [self creatCardItemByURL:BackGroundCoverURL(i + 1) fullUrl:BackGroundCoverURL_full(i + 1)]; [self.dataArr addObject:cardItem]; } } else { for (int i = 0; i < Community_coverCount; i++) { TUISelectAvatarCardItem *cardItem = [self creatCardItemByURL:Community_coverURL(i + 1)]; [self.dataArr addObject:cardItem]; } } [self.collectionView reloadData]; } - (TUISelectAvatarCardItem *)creatCardItemByURL:(NSString *)urlStr { TUISelectAvatarCardItem *cardItem = [[TUISelectAvatarCardItem alloc] init]; cardItem.posterUrlStr = urlStr; cardItem.isSelect = NO; if ([cardItem.posterUrlStr isEqualToString:self.profilFaceURL]) { cardItem.isSelect = YES; self.currentSelectCardItem = cardItem; } return cardItem; } - (TUISelectAvatarCardItem *)creatGroupGridAvatarCardItem { TUISelectAvatarCardItem *cardItem = [[TUISelectAvatarCardItem alloc] init]; cardItem.posterUrlStr = nil; cardItem.isSelect = NO; cardItem.isGroupGridAvatar = YES; cardItem.createGroupType = self.createGroupType; cardItem.cacheGroupGridAvatarImage = self.cacheGroupGridAvatarImage; if (!self.profilFaceURL) { cardItem.isSelect = YES; self.currentSelectCardItem = cardItem; } return cardItem; } - (TUISelectAvatarCardItem *)creatCardItemByURL:(NSString *)urlStr fullUrl:(NSString *)fullUrl { TUISelectAvatarCardItem *cardItem = [[TUISelectAvatarCardItem alloc] init]; cardItem.posterUrlStr = urlStr; cardItem.fullUrlStr = fullUrl; cardItem.isSelect = NO; if ([cardItem.posterUrlStr isEqualToString:self.profilFaceURL] || [cardItem.fullUrlStr isEqualToString:self.profilFaceURL]) { cardItem.isSelect = YES; self.currentSelectCardItem = cardItem; } return cardItem; } - (TUISelectAvatarCardItem *)creatCleanCardItem { TUISelectAvatarCardItem *cardItem = [[TUISelectAvatarCardItem alloc] init]; cardItem.posterUrlStr = nil; cardItem.isSelect = NO; cardItem.isDefaultBackgroundItem = YES; if (self.profilFaceURL.length == 0) { cardItem.isSelect = YES; self.currentSelectCardItem = cardItem; } return cardItem; } - (void)setupNavigator { _titleView = [[TUINaviBarIndicatorView alloc] init]; self.navigationItem.titleView = _titleView; self.navigationItem.title = @""; if (self.selectAvatarType == TUISelectAvatarTypeCover) { [self.titleView setTitle:TIMCommonLocalizableString(TUIKitChooseCover)]; } else if (self.selectAvatarType == TUISelectAvatarTypeConversationBackGroundCover) { [self.titleView setTitle:TIMCommonLocalizableString(TUIKitChooseBackground)]; } else { [self.titleView setTitle:TIMCommonLocalizableString(TUIKitChooseAvatar)]; } self.rightButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 30, 30)]; [self.rightButton setTitle:TIMCommonLocalizableString(Save) forState:UIControlStateNormal]; [self.rightButton addTarget:self action:@selector(rightBarButtonClick) forControlEvents:UIControlEventTouchUpInside]; self.rightButton.titleLabel.font = [UIFont fontWithName:@"PingFangSC-Regular" size:14]; [self.rightButton setTitleColor:[UIColor grayColor] forState:UIControlStateNormal]; UIBarButtonItem *rightItem = [[UIBarButtonItem alloc] initWithCustomView:self.rightButton]; self.navigationItem.rightBarButtonItems = @[ rightItem ]; } - (void)setCurrentSelectCardItem:(TUISelectAvatarCardItem *)currentSelectCardItem { _currentSelectCardItem = currentSelectCardItem; if (_currentSelectCardItem) { [self.rightButton setTitleColor:TIMCommonDynamicColor(@"", @"#006EFF") forState:UIControlStateNormal]; } else { [self.rightButton setTitleColor:[UIColor grayColor] forState:UIControlStateNormal]; } } - (void)rightBarButtonClick { if (!self.currentSelectCardItem) { return; } if (self.selectCallBack) { if (self.selectAvatarType == TUISelectAvatarTypeConversationBackGroundCover) { if (IS_NOT_EMPTY_NSSTRING(self.currentSelectCardItem.fullUrlStr)) { dispatch_async(dispatch_get_main_queue(), ^{ [TUITool makeToastActivity]; }); @weakify(self); [[SDWebImagePrefetcher sharedImagePrefetcher] prefetchURLs:@[ [NSURL URLWithString:self.currentSelectCardItem.fullUrlStr] ] progress:nil completed:^(NSUInteger noOfFinishedUrls, NSUInteger noOfSkippedUrls) { @strongify(self); dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.25 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{ [TUITool hideToastActivity]; [TUITool makeToast:TIMCommonLocalizableString(TUIKitChooseBackgroundSuccess)]; if (self.selectCallBack) { self.selectCallBack(self.currentSelectCardItem.fullUrlStr); [self.navigationController popViewControllerAnimated:YES]; } }); }); }]; } else { [TUITool makeToast:TIMCommonLocalizableString(TUIKitChooseBackgroundSuccess)]; self.selectCallBack(self.currentSelectCardItem.fullUrlStr); [self.navigationController popViewControllerAnimated:YES]; } } else { self.selectCallBack(self.currentSelectCardItem.posterUrlStr); [self.navigationController popViewControllerAnimated:YES]; } } } #pragma mark - UICollectionViewDelegateFlowLayout - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { CGFloat margin = 15; CGFloat padding = 13; int rowCount = 4.0; if (self.selectAvatarType == TUISelectAvatarTypeCover || self.selectAvatarType == TUISelectAvatarTypeConversationBackGroundCover) { rowCount = 2.0; } else { rowCount = 4.0; } CGFloat width = (self.view.frame.size.width - 2 * margin - (rowCount - 1) * padding) / rowCount; CGFloat height = 77; if (self.selectAvatarType == TUISelectAvatarTypeConversationBackGroundCover) { height = 125; } return CGSizeMake(width, height); } - (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section { return UIEdgeInsetsMake(24, 15, 0, 15); } #pragma mark - (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView { return 1; } - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { return [self.dataArr count]; } - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { TUISelectAvatarCollectionCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath]; // Configure the cell if (indexPath.row < self.dataArr.count) { cell.cardItem = self.dataArr[indexPath.row]; } return cell; } #pragma mark - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { [self recoverSelectedStatus]; TUISelectAvatarCollectionCell *cell = (TUISelectAvatarCollectionCell *)[self.collectionView cellForItemAtIndexPath:indexPath]; if (cell == nil) { [self.collectionView layoutIfNeeded]; cell = (TUISelectAvatarCollectionCell *)[self.collectionView cellForItemAtIndexPath:indexPath]; } if (self.currentSelectCardItem == cell.cardItem) { self.currentSelectCardItem = nil; } else { cell.cardItem.isSelect = YES; [cell updateSelectedUI]; self.currentSelectCardItem = cell.cardItem; } } - (void)recoverSelectedStatus { NSInteger index = 0; for (TUISelectAvatarCardItem *card in self.dataArr) { if (self.currentSelectCardItem == card) { card.isSelect = NO; break; } index++; } NSIndexPath *indexPath = [NSIndexPath indexPathForRow:index inSection:0]; TUISelectAvatarCollectionCell *cell = (TUISelectAvatarCollectionCell *)[self.collectionView cellForItemAtIndexPath:indexPath]; if (cell == nil) { [self.collectionView layoutIfNeeded]; cell = (TUISelectAvatarCollectionCell *)[self.collectionView cellForItemAtIndexPath:indexPath]; } [cell updateSelectedUI]; } @end ///////////////////////////////////////////////////////////////////////////////// // // TUICommonAvatarCell & Data // ///////////////////////////////////////////////////////////////////////////////// @implementation TUICommonAvatarCellData - (instancetype)init { self = [super init]; if (self) { _avatarImage = DefaultAvatarImage; } return self; } - (CGFloat)heightOfWidth:(CGFloat)width { return TPersonalCommonCell_Image_Size.height + 2 * TPersonalCommonCell_Margin; } @end @interface TUICommonAvatarCell () @property TUICommonAvatarCellData *avatarData; @end @implementation TUICommonAvatarCell - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { if (self = [super initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:reuseIdentifier]) { [self setupViews]; self.selectionStyle = UITableViewCellSelectionStyleNone; } return self; } - (void)fillWithData:(TUICommonAvatarCellData *)avatarData { [super fillWithData:avatarData]; self.avatarData = avatarData; RAC(_keyLabel, text) = [RACObserve(avatarData, key) takeUntil:self.rac_prepareForReuseSignal]; RAC(_valueLabel, text) = [RACObserve(avatarData, value) takeUntil:self.rac_prepareForReuseSignal]; @weakify(self); [[RACObserve(avatarData, avatarUrl) takeUntil:self.rac_prepareForReuseSignal] subscribeNext:^(NSURL *x) { @strongify(self); [self.avatar sd_setImageWithURL:x placeholderImage:self.avatarData.avatarImage]; }]; if (avatarData.showAccessory) { self.accessoryType = UITableViewCellAccessoryDisclosureIndicator; } else { self.accessoryType = UITableViewCellAccessoryNone; } // tell constraints they need updating [self setNeedsUpdateConstraints]; // update constraints now so we can animate the change [self updateConstraintsIfNeeded]; [self layoutIfNeeded]; } - (void)setupViews { _avatar = [[UIImageView alloc] initWithFrame:CGRectZero]; _avatar.contentMode = UIViewContentModeScaleAspectFit; [self addSubview:_avatar]; _keyLabel = self.textLabel; _valueLabel = self.detailTextLabel; [self addSubview:_keyLabel]; [self addSubview:_valueLabel]; self.keyLabel.textColor = TIMCommonDynamicColor(@"form_key_text_color", @"#444444"); self.valueLabel.textColor = TIMCommonDynamicColor(@"form_value_text_color", @"#000000"); self.selectionStyle = UITableViewCellSelectionStyleNone; } + (BOOL)requiresConstraintBasedLayout { return YES; } // this is Apple's recommended place for adding/updating constraints - (void)updateConstraints { [super updateConstraints]; CGSize headSize = TPersonalCommonCell_Image_Size; [self.avatar mas_remakeConstraints:^(MASConstraintMaker *make) { make.size.mas_equalTo(headSize); if (self.avatarData.showAccessory) { make.trailing.mas_equalTo(self.contentView.mas_trailing).mas_offset(-10); } else { make.trailing.mas_equalTo(self.contentView.mas_trailing).mas_offset(-20); } make.centerY.mas_equalTo(self); }]; if ([TUIConfig defaultConfig].avatarType == TAvatarTypeRounded) { self.avatar.layer.masksToBounds = YES; self.avatar.layer.cornerRadius = headSize.height / 2; } else if ([TUIConfig defaultConfig].avatarType == TAvatarTypeRadiusCorner) { self.avatar.layer.masksToBounds = YES; self.avatar.layer.cornerRadius = [TUIConfig defaultConfig].avatarCornerRadius; } } - (void)layoutSubviews { [super layoutSubviews]; } @end ///////////////////////////////////////////////////////////////////////////////// // // TUIConversationGroupItem // ///////////////////////////////////////////////////////////////////////////////// NSUInteger kConversationMarkStarType = V2TIM_CONVERSATION_MARK_TYPE_STAR; @implementation TUIConversationGroupItem - (instancetype)init { self = [super init]; if (self) { self.unreadCount = 0; self.groupIndex = 0; self.isShow = YES; } return self; } @end @implementation TUISendMessageAppendParams + (instancetype)defaultConfig { TUISendMessageAppendParams *params = [[TUISendMessageAppendParams alloc] init]; params.priority = V2TIM_PRIORITY_NORMAL; return params; } @end