| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462 |
- //
- // TUIChatPopContextController.m
- // TUIChat
- //
- // Created by wyl on 2022/10/24.
- // Copyright © 2023 Tencent. All rights reserved.
- //
- #import "TUIChatPopContextController.h"
- #import <TIMCommon/TIMDefine.h>
- #import "UIImage+ImageEffects.h"
- #import <TUICore/TUICore.h>
- @interface TUIChatPopContextController ()<V2TIMAdvancedMsgListener>
- @property(nonatomic, strong) UIView *recentView;
- @property(nonatomic, strong) UIView *alertContainerView;
- @property(nonatomic, strong) TUIMessageCell *alertView;
- @property(nonatomic, strong) TUIChatPopContextExtionView *extionView;
- @property(nonatomic, strong) UIColor *backgroundColor; // set backgroundColor
- @property(nonatomic, strong) UIView *backgroundView; // you set coustom view to it
- @property(nonatomic, strong) UITapGestureRecognizer *singleTap;
- @property(nonatomic, assign) BOOL backgoundTapDismissEnable; // default NO
- @end
- @implementation TUIChatPopContextController
- - (instancetype)init {
- if (self = [super init]) {
- [self configureController];
- }
- return self;
- }
- - (void)configureController {
- self.providesPresentationContextTransitionStyle = YES;
- self.definesPresentationContext = YES;
- self.modalPresentationStyle = UIModalPresentationCustom;
- _backgroundColor = [UIColor clearColor];
- _backgoundTapDismissEnable = YES;
- [[V2TIMManager sharedInstance] addAdvancedMsgListener:self];
- }
- - (void)viewDidLoad {
- [super viewDidLoad];
- self.view.backgroundColor = [UIColor clearColor];
- [self addBackgroundView];
- [self addSingleTapGesture];
- [self configureAlertView];
- [self configRecentView];
- [self configExtionView];
- [self.view layoutIfNeeded];
- [self showHapticFeedback];
- }
- - (void)viewWillAppear:(BOOL)animated {
- [super viewWillAppear:animated];
- if (_viewWillShowHandler) {
- _viewWillShowHandler(_alertView);
- }
- }
- - (void)viewDidAppear:(BOOL)animated {
- [super viewDidAppear:animated];
- if (_viewDidShowHandler) {
- _viewDidShowHandler(_alertView);
- }
- //
- // Too far to the top
- CGFloat moveY = 0;
- if (self.recentView.frame.origin.y < NavBar_Height) {
- CGFloat deal = NavBar_Height - self.recentView.frame.origin.y;
- moveY = deal + NavBar_Height + 50;
- }
- //
- // Too far to the right
- CGFloat moveX = 0;
- if (self.recentView.frame.origin.x + self.recentView.frame.size.width > self.view.frame.size.width) {
- CGFloat deal = self.recentView.frame.origin.x + self.recentView.frame.size.width - self.view.frame.size.width;
- moveX = deal + 5;
- }
- //
- // too far down
- if (self.extionView.frame.origin.y + self.extionView.frame.size.height > self.view.frame.size.height) {
- CGFloat deal = self.extionView.frame.origin.y + self.extionView.frame.size.height - self.view.frame.size.height;
- moveY = -deal - 50;
- }
- BOOL oneScreenCanFillCheck = NO;
- // Can only one screen fit
- if (self.recentView.frame.size.height + self.originFrame.size.height + self.extionView.frame.size.height + kScale390(100) > self.view.bounds.size.height) {
- oneScreenCanFillCheck = YES;
- }
- if (oneScreenCanFillCheck) {
- // recentView
- CGFloat recentViewMoveY = NavBar_Height + 50;
- self.recentView.frame =
- CGRectMake(self.recentView.frame.origin.x - moveX, recentViewMoveY, self.recentView.frame.size.width, self.recentView.frame.size.height);
- // alertView
- [UIView animateWithDuration:0.3
- animations:^{
- self.alertContainerView.frame =
- CGRectMake(0, self.recentView.frame.origin.y + kScale390(8) + self.recentView.frame.size.height,
- self.view.frame.size.width, self.originFrame.size.height);
- }
- completion:^(BOOL finished){
- }];
- // extionView
- CGFloat deal = self.extionView.frame.origin.y + self.extionView.frame.size.height - self.view.frame.size.height;
- CGFloat extionViewMoveY = -deal - 50;
- self.extionView.frame = CGRectMake(self.extionView.frame.origin.x - moveX, self.extionView.frame.origin.y + extionViewMoveY,
- self.extionView.frame.size.width, self.extionView.frame.size.height);
- self.extionView.transform = CGAffineTransformMakeScale(0.1, 0.1);
- [UIView animateWithDuration:0.5
- animations:^{
- // Bounces
- self.extionView.transform = CGAffineTransformMakeScale(1, 1);
- }
- completion:^(BOOL finished){
- }];
- return;
- } else {
- // When the container need a displacement change
- // Or do nothing
- if (moveY != 0) {
- [UIView animateWithDuration:0.3
- animations:^{
- self.alertContainerView.frame = CGRectMake(0, self.originFrame.origin.y + moveY, self.view.frame.size.width, self.originFrame.size.height);
- }
- completion:^(BOOL finished){
- }];
- }
- self.recentView.frame = CGRectMake(self.recentView.frame.origin.x - moveX, self.recentView.frame.origin.y, self.recentView.frame.size.width,
- self.recentView.frame.size.height);
- [UIView animateWithDuration:0.2
- animations:^{
- // When recentView needs to have displacement animation
- self.recentView.frame = CGRectMake(self.recentView.frame.origin.x, self.recentView.frame.origin.y + moveY,
- self.recentView.frame.size.width, self.recentView.frame.size.height);
- }
- completion:^(BOOL finished){
- }];
- self.extionView.frame = CGRectMake(self.extionView.frame.origin.x - moveX, self.extionView.frame.origin.y + moveY, self.extionView.frame.size.width,
- self.extionView.frame.size.height);
- self.extionView.transform = CGAffineTransformMakeScale(0.1, 0.1);
- [UIView animateWithDuration:0.5
- animations:^{
- // Bounces
- self.extionView.transform = CGAffineTransformMakeScale(1, 1);
- }
- completion:^(BOOL finished){
- }];
- }
- }
- - (void)addBackgroundView {
- if (_backgroundView == nil) {
- UIView *backgroundView = [[UIView alloc] init];
- backgroundView.backgroundColor = _backgroundColor;
- _backgroundView = backgroundView;
- }
- _backgroundView.translatesAutoresizingMaskIntoConstraints = NO;
- [self.view insertSubview:_backgroundView atIndex:0];
- [self addConstraintToView:_backgroundView edgeInset:UIEdgeInsetsZero];
- }
- - (void)setBackgroundView:(UIView *)backgroundView {
- if (_backgroundView == nil) {
- _backgroundView = backgroundView;
- } else if (_backgroundView != backgroundView) {
- backgroundView.translatesAutoresizingMaskIntoConstraints = NO;
- [self.view insertSubview:backgroundView aboveSubview:_backgroundView];
- [self addConstraintToView:backgroundView edgeInset:UIEdgeInsetsZero];
- backgroundView.alpha = 0;
- [UIView animateWithDuration:0.3
- animations:^{
- backgroundView.alpha = 1;
- }
- completion:^(BOOL finished) {
- [_backgroundView removeFromSuperview];
- _backgroundView = backgroundView;
- [self addSingleTapGesture];
- }];
- }
- }
- - (void)addSingleTapGesture {
- self.view.userInteractionEnabled = YES;
- _backgroundView.userInteractionEnabled = YES;
- UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(singleTap:)];
- singleTap.enabled = _backgoundTapDismissEnable;
- [_backgroundView addGestureRecognizer:singleTap];
- _singleTap = singleTap;
- }
- - (void)configureAlertView {
- self.alertContainerView = [[UIView alloc] init];
- [self.view addSubview:self.alertContainerView];
- _alertView = [[self.alertCellClass alloc] init];
- [self.alertContainerView addSubview:_alertView];
- _alertView.userInteractionEnabled = YES;
- if ([self.alertView isKindOfClass:NSClassFromString(@"TUIMergeMessageCell_Minimalist")]) {
- _alertView.userInteractionEnabled = NO;
- }
- [_alertView fillWithData:self.alertViewCellData];
- [_alertView layoutIfNeeded];
-
- self.alertContainerView.frame = CGRectMake(0, _originFrame.origin.y, self.view.frame.size.width, _originFrame.size.height);
- _alertView.frame = CGRectMake(0, 0, self.alertContainerView.frame.size.width, self.alertContainerView.frame.size.height);
- for (UIView *view in _alertView.contentView.subviews) {
- if(view != _alertView.container) {
- view.hidden = YES;
- }
- }
- [_alertView.container mas_remakeConstraints:^(MASConstraintMaker *make) {
- make.leading.mas_equalTo(_originFrame.origin.x);
- make.top.mas_equalTo(0);
- make.size.mas_equalTo(_originFrame.size);
- }];
- }
- - (void)configRecentView {
- _recentView = [[UIView alloc] init];
- _recentView.backgroundColor = [UIColor clearColor];
- [self.view addSubview:_recentView];
- _recentView.frame = CGRectMake(_originFrame.origin.x,
- _originFrame.origin.y - kScale390(8 + 40),
- MAX(kTIMDefaultEmojiSize.width *8,kScale390(208)),
- kScale390(40));
- NSDictionary *param = @{TUICore_TUIChatExtension_ChatPopMenuReactRecentView_Delegate : self};
- [TUICore raiseExtension:TUICore_TUIChatExtension_ChatPopMenuReactRecentView_MinimalistExtensionID parentView:self.recentView param:param];
- }
- - (void)configExtionView {
- _extionView = [[TUIChatPopContextExtionView alloc] init];
- _extionView.backgroundColor = [UIColor tui_colorWithHex:@"f9f9f9"];
- _extionView.layer.cornerRadius = kScale390(16);
- [self.view addSubview:_extionView];
- CGFloat height = [self configAndCaculateExtionHeight];
- _extionView.frame = CGRectMake(_originFrame.origin.x, _originFrame.origin.y + _originFrame.size.height + kScale390(8), kScale390(180), height);
- }
- - (CGFloat)configAndCaculateExtionHeight {
- NSMutableArray *items = self.items;
- CGFloat height = 0;
- for (int i = 0; i < items.count; i++) {
- height += kScale390(40);
- }
- CGFloat topMargin = kScale390(6);
- CGFloat bottomMargin = kScale390(6);
- height += topMargin;
- height += bottomMargin;
- [_extionView configUIWithItems:items topBottomMargin:topMargin];
- return height;
- }
- - (void)updateExtionView {
- CGFloat height = [self configAndCaculateExtionHeight];
- _extionView.frame = CGRectMake(_extionView.frame.origin.x, _extionView.frame.origin.y, _extionView.frame.size.width, height);
- }
- - (void)setBackgoundTapDismissEnable:(BOOL)backgoundTapDismissEnable {
- _backgoundTapDismissEnable = backgoundTapDismissEnable;
- _singleTap.enabled = backgoundTapDismissEnable;
- }
- - (void)addConstraintToView:(UIView *)view edgeInset:(UIEdgeInsets)edgeInset {
- [self addConstraintWithView:view topView:self.view leftView:self.view bottomView:self.view rightView:self.view edgeInset:edgeInset];
- }
- - (void)addConstraintWithView:(UIView *)view
- topView:(UIView *)topView
- leftView:(UIView *)leftView
- bottomView:(UIView *)bottomView
- rightView:(UIView *)rightView
- edgeInset:(UIEdgeInsets)edgeInset {
- if (topView) {
- [self.view addConstraint:[NSLayoutConstraint constraintWithItem:view
- attribute:NSLayoutAttributeTop
- relatedBy:NSLayoutRelationEqual
- toItem:topView
- attribute:NSLayoutAttributeTop
- multiplier:1
- constant:edgeInset.top]];
- }
- if (leftView) {
- [self.view addConstraint:[NSLayoutConstraint constraintWithItem:view
- attribute:NSLayoutAttributeLeft
- relatedBy:NSLayoutRelationEqual
- toItem:leftView
- attribute:NSLayoutAttributeLeft
- multiplier:1
- constant:edgeInset.left]];
- }
- if (rightView) {
- [self.view addConstraint:[NSLayoutConstraint constraintWithItem:view
- attribute:NSLayoutAttributeRight
- relatedBy:NSLayoutRelationEqual
- toItem:rightView
- attribute:NSLayoutAttributeRight
- multiplier:1
- constant:edgeInset.right]];
- }
- if (bottomView) {
- [self.view addConstraint:[NSLayoutConstraint constraintWithItem:view
- attribute:NSLayoutAttributeBottom
- relatedBy:NSLayoutRelationEqual
- toItem:bottomView
- attribute:NSLayoutAttributeBottom
- multiplier:1
- constant:edgeInset.bottom]];
- }
- }
- #pragma mark - public
- - (void)setBlurEffectWithView:(UIView *)view {
- [self setBlurEffectWithView:view style:BlurEffectStyleDarkEffect];
- }
- - (void)setBlurEffectWithView:(UIView *)view style:(BlurEffectStyle)blurStyle {
- UIImage *snapshotImage = [UIImage snapshotImageWithView:view];
- UIImage *blurImage = [self blurImageWithSnapshotImage:snapshotImage style:blurStyle];
- dispatch_async(dispatch_get_main_queue(), ^{
- UIImageView *blurImageView = [[UIImageView alloc] initWithImage:blurImage];
- self.backgroundView = blurImageView;
- });
- }
- - (void)setBlurEffectWithView:(UIView *)view effectTintColor:(UIColor *)effectTintColor {
- UIImage *snapshotImage = [UIImage snapshotImageWithView:view];
- UIImage *blurImage = [snapshotImage applyTintEffectWithColor:effectTintColor];
- UIImageView *blurImageView = [[UIImageView alloc] initWithImage:blurImage];
- self.backgroundView = blurImageView;
- }
- #pragma mark - private
- - (void)showHapticFeedback {
- if (@available(iOS 10.0, *)) {
- dispatch_async(dispatch_get_main_queue(), ^{
- UIImpactFeedbackGenerator *generator = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleLight];
- [generator prepare];
- [generator impactOccurred];
- });
- } else {
- // Fallback on earlier versions
- }
- }
- - (UIImage *)blurImageWithSnapshotImage:(UIImage *)snapshotImage style:(BlurEffectStyle)blurStyle {
- switch (blurStyle) {
- case BlurEffectStyleLight:
- return [snapshotImage applyLightEffect];
- case BlurEffectStyleDarkEffect:
- return [snapshotImage applyDarkEffect];
- case BlurEffectStyleExtraLight:
- return [snapshotImage applyExtraLightEffect];
- default:
- return nil;
- }
- }
- - (void)blurDismissViewControllerAnimated:(BOOL)animated completion:(void (^__nullable)(BOOL finished))completion {
- [self dismissViewControllerAnimated:animated];
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
- if (completion) {
- completion(YES);
- }
- });
- }
- - (void)dismissViewControllerAnimated:(BOOL)animated {
- [UIView animateWithDuration:0.3
- animations:^{
- self.recentView.frame = CGRectMake(self.recentView.frame.origin.x, self.originFrame.origin.y - self.recentView.frame.size.height,
- self.recentView.frame.size.width, self.recentView.frame.size.height);
- }
- completion:^(BOOL finished){
- }];
- [UIView animateWithDuration:0.3
- animations:^{
- self.alertContainerView.frame = CGRectMake(0, self.originFrame.origin.y , self.view.frame.size.width, self.originFrame.size.height);
- }
- completion:^(BOOL finished) {
- if (finished) {
- [self dismissViewControllerAnimated:animated completion:self.dismissComplete];
- }
- }];
- self.extionView.transform = CGAffineTransformMakeScale(1, 1);
- [UIView animateWithDuration:0.2
- animations:^{
- self.extionView.transform = CGAffineTransformMakeScale(0.1, 0.1);
- }
- completion:^(BOOL finished) {
- if (finished) {
- self.extionView.transform = CGAffineTransformMakeScale(0, 0);
- }
- }];
- }
- #pragma mark - action
- - (void)singleTap:(UITapGestureRecognizer *)sender {
- [self dismissViewControllerAnimated:NO];
- }
- // MARK: V2TIMAdvancedMsgListener
- - (void)onRecvMessageRevoked:(NSString *)msgID operateUser:(V2TIMUserFullInfo *)operateUser reason:(NSString *)reason {
-
- if ([msgID isEqualToString:self.alertViewCellData.msgID]) {
- UIViewController *controller = self;
- while(controller.presentingViewController != nil){
- controller = controller.presentingViewController;
- }
- [controller dismissViewControllerAnimated:YES completion:^{
- [self blurDismissViewControllerAnimated:NO completion:nil];
- }];
- }
- }
- @end
|