//
//  TIMCommonModel.m
//  TIMCommon
//
//  Created by cologne on 2023/3/14.
//  Copyright © 2023 Tencent. All rights reserved.
//

#import "TIMCommonModel.h"

/////////////////////////////////////////////////////////////////////////////////
//
//                           TUIPopView
//
/////////////////////////////////////////////////////////////////////////////////

@interface TUIPopView () <UITableViewDelegate, UITableViewDataSource, UIGestureRecognizerDelegate>
@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 () <UITextFieldDelegate, UIGestureRecognizerDelegate>
@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 60;
}

- (CGFloat)estimatedHeight {
    return 60;
}

@end

@interface TUICommonTableViewCell () <UIGestureRecognizerDelegate>
@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 () <UICollectionViewDelegate, UICollectionViewDataSource>
@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<NSKeyValueChangeKey, id> *)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 () <UIScrollViewDelegate>
@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 () <UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout>

@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 <UICollectionViewDataSource>

- (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 <UICollectionViewDelegate>

- (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
