// // SellyCallControlView.m // SellyCloudSDK_Example // // Created by Caleb on 12/17/25. // Copyright © 2025 Caleb. All rights reserved. // #import "SellyCallControlView.h" #import @interface SellyCallControlView () @property (nonatomic, strong) UIButton *speakerButton; @property (nonatomic, strong) UIButton *videoButton; @property (nonatomic, strong) UIButton *switchCameraButton; @property (nonatomic, strong) UIButton *muteButton; @property (nonatomic, strong) UIButton *pipButton; @property (nonatomic, strong) UIButton *screenShareButton; @property (nonatomic, strong) UIButton *hangupButton; @property (nonatomic, strong) UIStackView *mainStackView; // 主垂直容器 @property (nonatomic, strong) UIStackView *topButtonStackView; // 上排按钮 @property (nonatomic, strong) UIStackView *bottomButtonStackView; // 下排按钮 @end @implementation SellyCallControlView - (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { [self setupUI]; } return self; } - (instancetype)initWithCoder:(NSCoder *)coder { self = [super initWithCoder:coder]; if (self) { [self setupUI]; } return self; } - (void)setupUI { // 设置透明背景 self.backgroundColor = [UIColor clearColor]; // 创建主垂直容器 self.mainStackView = [[UIStackView alloc] init]; self.mainStackView.axis = UILayoutConstraintAxisVertical; self.mainStackView.distribution = UIStackViewDistributionFillEqually; self.mainStackView.alignment = UIStackViewAlignmentFill; self.mainStackView.spacing = 10; [self addSubview:self.mainStackView]; // 创建上排按钮容器 self.topButtonStackView = [[UIStackView alloc] init]; self.topButtonStackView.axis = UILayoutConstraintAxisHorizontal; self.topButtonStackView.distribution = UIStackViewDistributionEqualSpacing; self.topButtonStackView.alignment = UIStackViewAlignmentCenter; self.topButtonStackView.spacing = 0; // 创建下排按钮容器 self.bottomButtonStackView = [[UIStackView alloc] init]; self.bottomButtonStackView.axis = UILayoutConstraintAxisHorizontal; self.bottomButtonStackView.distribution = UIStackViewDistributionEqualSpacing; self.bottomButtonStackView.alignment = UIStackViewAlignmentCenter; self.bottomButtonStackView.spacing = 0; [self.mainStackView addArrangedSubview:self.topButtonStackView]; [self.mainStackView addArrangedSubview:self.bottomButtonStackView]; // 创建按钮 self.speakerButton = [self createButtonWithImageName:@"speaker" title:@"扬声器" action:@selector(speakerButtonTapped:)]; self.videoButton = [self createButtonWithImageName:@"video" title:@"视频" action:@selector(videoButtonTapped:)]; self.switchCameraButton = [self createButtonWithImageName:@"switch_camera" title:@"切换" action:@selector(switchCameraButtonTapped:)]; self.muteButton = [self createButtonWithImageName:@"microphone" title:@"静音" action:@selector(muteButtonTapped:)]; self.pipButton = [self createButtonWithImageName:@"pip" title:@"画中画" action:@selector(pipButtonTapped:)]; self.screenShareButton = [self createButtonWithImageName:@"screen_share" title:@"共享屏幕" action:@selector(screenShareButtonTapped:)]; self.hangupButton = [self createButtonWithImageName:@"hangup" title:@"挂断" action:@selector(hangupButtonTapped:)]; // 挂断按钮的图标背景设置为红色 UIView *hangupIconBackground = [self.hangupButton viewWithTag:999]; if (hangupIconBackground) { hangupIconBackground.backgroundColor = [UIColor colorWithRed:0.9 green:0.2 blue:0.2 alpha:1.0]; } // 添加按钮到上排容器(4个按钮) [self.topButtonStackView addArrangedSubview:self.speakerButton]; [self.topButtonStackView addArrangedSubview:self.videoButton]; [self.topButtonStackView addArrangedSubview:self.switchCameraButton]; [self.topButtonStackView addArrangedSubview:self.muteButton]; // 添加按钮到下排容器(根据配置显示 PiP 或屏幕分享) // 默认不显示 PiP 和屏幕分享按钮,由外部控制 self.pipButton.hidden = YES; self.screenShareButton.hidden = YES; [self.bottomButtonStackView addArrangedSubview:self.pipButton]; [self.bottomButtonStackView addArrangedSubview:self.screenShareButton]; [self.bottomButtonStackView addArrangedSubview:self.hangupButton]; // 布局约束 - 使用 Masonry [self.mainStackView mas_makeConstraints:^(MASConstraintMaker *make) { make.leading.equalTo(self).offset(15); make.trailing.equalTo(self).offset(-15); make.top.equalTo(self).offset(10); make.bottom.equalTo(self).offset(-10); }]; // 上排容器内边距(让按钮居中分布) [self.topButtonStackView mas_makeConstraints:^(MASConstraintMaker *make) { make.leading.trailing.equalTo(self.mainStackView); }]; // 下排容器内边距(让2个按钮合理分布,不要太分散) [self.bottomButtonStackView mas_makeConstraints:^(MASConstraintMaker *make) { make.centerX.equalTo(self.mainStackView); make.width.mas_lessThanOrEqualTo(self.mainStackView); }]; } - (UIButton *)createButtonWithImageName:(NSString *)imageName title:(NSString *)title action:(SEL)action { UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; // 创建容器视图 UIView *containerView = [[UIView alloc] init]; containerView.userInteractionEnabled = NO; [button addSubview:containerView]; // 图标背景 UIView *iconBackground = [[UIView alloc] init]; iconBackground.backgroundColor = [UIColor colorWithWhite:1.0 alpha:0.2]; iconBackground.layer.cornerRadius = 26; // 52/2 = 26 iconBackground.clipsToBounds = YES; iconBackground.userInteractionEnabled = NO; iconBackground.tag = 999; // 添加tag以便后续识别 [containerView addSubview:iconBackground]; // 使用系统图标 UIImage *icon = [self systemImageForButtonName:imageName]; UIImageView *imageView = [[UIImageView alloc] initWithImage:icon]; imageView.contentMode = UIViewContentModeScaleAspectFit; imageView.tintColor = [UIColor whiteColor]; imageView.userInteractionEnabled = NO; [iconBackground addSubview:imageView]; // 标题标签 UILabel *titleLabel = [[UILabel alloc] init]; titleLabel.text = title; titleLabel.textColor = [UIColor whiteColor]; titleLabel.font = [UIFont systemFontOfSize:12]; titleLabel.textAlignment = NSTextAlignmentCenter; titleLabel.userInteractionEnabled = NO; [containerView addSubview:titleLabel]; // 使用 Masonry 布局 [containerView mas_makeConstraints:^(MASConstraintMaker *make) { make.center.equalTo(button); make.width.mas_equalTo(70); make.height.mas_equalTo(90); }]; [iconBackground mas_makeConstraints:^(MASConstraintMaker *make) { make.centerX.equalTo(containerView); make.top.equalTo(containerView); make.width.height.mas_equalTo(52); }]; [imageView mas_makeConstraints:^(MASConstraintMaker *make) { make.center.equalTo(iconBackground); make.width.height.mas_equalTo(28); }]; [titleLabel mas_makeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(iconBackground.mas_bottom).offset(8); make.centerX.equalTo(containerView); make.leading.trailing.equalTo(containerView); }]; [button addTarget:self action:action forControlEvents:UIControlEventTouchUpInside]; // 设置按钮尺寸 [button mas_makeConstraints:^(MASConstraintMaker *make) { make.width.mas_equalTo(70); make.height.mas_equalTo(90); }]; return button; } - (UIImage *)systemImageForButtonName:(NSString *)name { NSString *systemName = @"questionmark.circle"; if ([name isEqualToString:@"speaker"]) { systemName = @"speaker.wave.2.fill"; } else if ([name isEqualToString:@"video"]) { systemName = @"video.fill"; } else if ([name isEqualToString:@"switch_camera"]) { systemName = @"arrow.triangle.2.circlepath.camera.fill"; } else if ([name isEqualToString:@"microphone"]) { systemName = @"mic.fill"; } else if ([name isEqualToString:@"pip"]) { systemName = @"pip.fill"; } else if ([name isEqualToString:@"screen_share"]) { systemName = @"rectangle.on.rectangle"; } else if ([name isEqualToString:@"hangup"]) { systemName = @"phone.down.fill"; } UIImageSymbolConfiguration *config = [UIImageSymbolConfiguration configurationWithPointSize:28 weight:UIImageSymbolWeightMedium scale:UIImageSymbolScaleMedium]; return [UIImage systemImageNamed:systemName withConfiguration:config]; } #pragma mark - Button Actions - (void)speakerButtonTapped:(UIButton *)sender { if ([self.delegate respondsToSelector:@selector(callControlView:didTapAction:)]) { [self.delegate callControlView:self didTapAction:SellyCallControlActionSpeaker]; } } - (void)videoButtonTapped:(UIButton *)sender { if ([self.delegate respondsToSelector:@selector(callControlView:didTapAction:)]) { [self.delegate callControlView:self didTapAction:SellyCallControlActionVideo]; } } - (void)switchCameraButtonTapped:(UIButton *)sender { if ([self.delegate respondsToSelector:@selector(callControlView:didTapAction:)]) { [self.delegate callControlView:self didTapAction:SellyCallControlActionSwitchCamera]; } } - (void)muteButtonTapped:(UIButton *)sender { if ([self.delegate respondsToSelector:@selector(callControlView:didTapAction:)]) { [self.delegate callControlView:self didTapAction:SellyCallControlActionMute]; } } - (void)hangupButtonTapped:(UIButton *)sender { if ([self.delegate respondsToSelector:@selector(callControlView:didTapAction:)]) { [self.delegate callControlView:self didTapAction:SellyCallControlActionHangup]; } } - (void)pipButtonTapped:(UIButton *)sender { if ([self.delegate respondsToSelector:@selector(callControlView:didTapAction:)]) { [self.delegate callControlView:self didTapAction:SellyCallControlActionPiP]; } } - (void)screenShareButtonTapped:(UIButton *)sender { if ([self.delegate respondsToSelector:@selector(callControlView:didTapAction:)]) { [self.delegate callControlView:self didTapAction:SellyCallControlActionScreenShare]; } } #pragma mark - Public Methods - (void)setShowPiPButton:(BOOL)showPiPButton { _showPiPButton = showPiPButton; self.pipButton.hidden = !showPiPButton; } - (void)setShowScreenShareButton:(BOOL)showScreenShareButton { _showScreenShareButton = showScreenShareButton; self.screenShareButton.hidden = !showScreenShareButton; } - (void)updateSpeakerEnabled:(BOOL)enabled { // 更新图标和背景 UIView *iconBackground = self.speakerButton.subviews.firstObject.subviews.firstObject; if (enabled) { iconBackground.backgroundColor = [UIColor colorWithRed:0.2 green:0.5 blue:1.0 alpha:1.0]; NSString *systemName = @"speaker.wave.2.fill"; UIImageSymbolConfiguration *config = [UIImageSymbolConfiguration configurationWithPointSize:28 weight:UIImageSymbolWeightMedium scale:UIImageSymbolScaleMedium]; UIImageView *imageView = (UIImageView *)iconBackground.subviews.firstObject; imageView.image = [UIImage systemImageNamed:systemName withConfiguration:config]; } else { iconBackground.backgroundColor = [UIColor colorWithWhite:1.0 alpha:0.2]; NSString *systemName = @"speaker.fill"; UIImageSymbolConfiguration *config = [UIImageSymbolConfiguration configurationWithPointSize:28 weight:UIImageSymbolWeightMedium scale:UIImageSymbolScaleMedium]; UIImageView *imageView = (UIImageView *)iconBackground.subviews.firstObject; imageView.image = [UIImage systemImageNamed:systemName withConfiguration:config]; } } - (void)updateVideoEnabled:(BOOL)enabled { UIView *iconBackground = self.videoButton.subviews.firstObject.subviews.firstObject; if (enabled) { iconBackground.backgroundColor = [UIColor colorWithRed:0.2 green:0.5 blue:1.0 alpha:1.0]; NSString *systemName = @"video.fill"; UIImageSymbolConfiguration *config = [UIImageSymbolConfiguration configurationWithPointSize:28 weight:UIImageSymbolWeightMedium scale:UIImageSymbolScaleMedium]; UIImageView *imageView = (UIImageView *)iconBackground.subviews.firstObject; imageView.image = [UIImage systemImageNamed:systemName withConfiguration:config]; } else { iconBackground.backgroundColor = [UIColor colorWithWhite:1.0 alpha:0.2]; NSString *systemName = @"video.slash.fill"; UIImageSymbolConfiguration *config = [UIImageSymbolConfiguration configurationWithPointSize:28 weight:UIImageSymbolWeightMedium scale:UIImageSymbolScaleMedium]; UIImageView *imageView = (UIImageView *)iconBackground.subviews.firstObject; imageView.image = [UIImage systemImageNamed:systemName withConfiguration:config]; } } - (void)updateMuteEnabled:(BOOL)muted { UIView *iconBackground = self.muteButton.subviews.firstObject.subviews.firstObject; if (muted) { iconBackground.backgroundColor = [UIColor colorWithRed:0.9 green:0.2 blue:0.2 alpha:1.0]; NSString *systemName = @"mic.slash.fill"; UIImageSymbolConfiguration *config = [UIImageSymbolConfiguration configurationWithPointSize:28 weight:UIImageSymbolWeightMedium scale:UIImageSymbolScaleMedium]; UIImageView *imageView = (UIImageView *)iconBackground.subviews.firstObject; imageView.image = [UIImage systemImageNamed:systemName withConfiguration:config]; } else { iconBackground.backgroundColor = [UIColor colorWithWhite:1.0 alpha:0.2]; NSString *systemName = @"mic.fill"; UIImageSymbolConfiguration *config = [UIImageSymbolConfiguration configurationWithPointSize:28 weight:UIImageSymbolWeightMedium scale:UIImageSymbolScaleMedium]; UIImageView *imageView = (UIImageView *)iconBackground.subviews.firstObject; imageView.image = [UIImage systemImageNamed:systemName withConfiguration:config]; } } - (void)updatePiPEnabled:(BOOL)enabled { UIView *iconBackground = self.pipButton.subviews.firstObject.subviews.firstObject; if (enabled) { iconBackground.backgroundColor = [UIColor colorWithRed:0.2 green:0.5 blue:1.0 alpha:1.0]; NSString *systemName = @"pip.fill"; UIImageSymbolConfiguration *config = [UIImageSymbolConfiguration configurationWithPointSize:28 weight:UIImageSymbolWeightMedium scale:UIImageSymbolScaleMedium]; UIImageView *imageView = (UIImageView *)iconBackground.subviews.firstObject; imageView.image = [UIImage systemImageNamed:systemName withConfiguration:config]; } else { iconBackground.backgroundColor = [UIColor colorWithWhite:1.0 alpha:0.2]; NSString *systemName = @"pip"; UIImageSymbolConfiguration *config = [UIImageSymbolConfiguration configurationWithPointSize:28 weight:UIImageSymbolWeightMedium scale:UIImageSymbolScaleMedium]; UIImageView *imageView = (UIImageView *)iconBackground.subviews.firstObject; imageView.image = [UIImage systemImageNamed:systemName withConfiguration:config]; } } - (void)updateScreenShareEnabled:(BOOL)enabled { UIView *iconBackground = self.screenShareButton.subviews.firstObject.subviews.firstObject; if (enabled) { iconBackground.backgroundColor = [UIColor colorWithRed:0.2 green:0.5 blue:1.0 alpha:1.0]; NSString *systemName = @"rectangle.on.rectangle.fill"; UIImageSymbolConfiguration *config = [UIImageSymbolConfiguration configurationWithPointSize:28 weight:UIImageSymbolWeightMedium scale:UIImageSymbolScaleMedium]; UIImageView *imageView = (UIImageView *)iconBackground.subviews.firstObject; imageView.image = [UIImage systemImageNamed:systemName withConfiguration:config]; } else { iconBackground.backgroundColor = [UIColor colorWithWhite:1.0 alpha:0.2]; NSString *systemName = @"rectangle.on.rectangle"; UIImageSymbolConfiguration *config = [UIImageSymbolConfiguration configurationWithPointSize:28 weight:UIImageSymbolWeightMedium scale:UIImageSymbolScaleMedium]; UIImageView *imageView = (UIImageView *)iconBackground.subviews.firstObject; imageView.image = [UIImage systemImageNamed:systemName withConfiguration:config]; } } @end