MOLiveMsgTextCell.m 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. //
  2. // MOLiveMsgTextCell.m
  3. // MiMoLive
  4. //
  5. // Created by SuperC on 2025/6/9.
  6. //
  7. #import "MOLiveMsgTextCell.h"
  8. #import "UIView+MOCornerRadius.h"
  9. @interface MOLiveMsgTextCell ()
  10. @property (nonatomic, strong) BigBtn *translateBtn;//翻译按钮
  11. @end
  12. @implementation MOLiveMsgTextCell
  13. - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{
  14. self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
  15. if (self != nil) {
  16. self.contentView.transform = CGAffineTransformMakeScale(1, -1);
  17. self.backgroundColor = [UIColor clearColor];
  18. self.selectionStyle = UITableViewCellSelectionStyleNone;
  19. [self setupUI];
  20. }
  21. return self;
  22. }
  23. - (void)setupUI{
  24. [self.contentView addSubview:self.titleLab];
  25. [self.titleLab mas_makeConstraints:^(MASConstraintMaker *make) {
  26. make.top.equalTo(self.contentView).offset(2.0);
  27. make.leading.trailing.equalTo(self.contentView);
  28. make.height.equalTo(@(MOTextTitleLabeHeight));
  29. }];
  30. [self.contentView addSubview:self.bgView];
  31. [self.bgView mas_makeConstraints:^(MASConstraintMaker *make) {
  32. make.left.equalTo(self.contentView).offset(MOBgViewOffSet);
  33. make.width.equalTo(@(MOBgViewMaxWidth));
  34. make.top.equalTo(self.titleLab.mas_bottom).offset(MOBgViewOffSet);
  35. make.bottom.equalTo(self.contentView).offset(-MOBgViewOffSet);
  36. }];
  37. [self.contentView addSubview:self.translateBtn];
  38. CGFloat translateBtnWidth = [MOTools getWidthWithString:self.translateBtn.titleLabel.text font:[MOTextTools regularFont:10.0]] + 10 + 12.0 * 2.0 + 10.0;
  39. [self.translateBtn mas_makeConstraints:^(MASConstraintMaker *make) {
  40. make.right.equalTo(self.bgView.mas_right).offset(0);
  41. make.height.equalTo(@18.0);
  42. make.bottom.equalTo(self.bgView.mas_top).offset(-1);
  43. make.width.equalTo(@(translateBtnWidth));
  44. }];
  45. [self.contentView addSubview:self.bubbleImgView];
  46. [self.bubbleImgView mas_makeConstraints:^(MASConstraintMaker *make) {
  47. make.left.equalTo(self.bgView).offset(-MOBgViewOffSet);
  48. make.right.equalTo(self.bgView).offset(MOBgViewOffSet);
  49. make.top.equalTo(self.bgView).offset(-MOBgViewOffSet);
  50. make.bottom.equalTo(self.bgView).offset(MOBgViewOffSet);
  51. }];
  52. [self.contentView addSubview:self.contentTextView];
  53. [self.contentTextView mas_makeConstraints:^(MASConstraintMaker *make) {
  54. make.left.equalTo(self.bgView).offset(MOContentLeftAndRighSpacing);
  55. make.right.equalTo(self.bgView).offset(-MOContentLeftAndRighSpacing);
  56. make.centerY.equalTo(self.bgView);
  57. make.height.equalTo(@16.0);
  58. }];
  59. self.contentView.userInteractionEnabled = YES;
  60. _bubbleTapGestureRecognizer = [UITapGestureRecognizer new];
  61. [_bubbleTapGestureRecognizer addTarget:self action:@selector(bubbleTapped:)];
  62. _bubbleTapGestureRecognizer.delegate = self;
  63. [self.contentView addGestureRecognizer:self.bubbleTapGestureRecognizer];
  64. _bubbleLongPressGestureRecognizer = [UILongPressGestureRecognizer new];
  65. [_bubbleLongPressGestureRecognizer addTarget:self action:@selector(bubbleLongPressHandler:)];
  66. [self.contentView addGestureRecognizer:self.bubbleLongPressGestureRecognizer];
  67. }
  68. - (void)bubbleTapped:(UITapGestureRecognizer *)recognizer
  69. {
  70. MOLogV(@"触发了点击");
  71. self.cellTapBlock ? self.cellTapBlock(self.cellModel) : nil;
  72. }
  73. - (void)bubbleLongPressHandler:(UILongPressGestureRecognizer *)recognizer{
  74. if (recognizer.state == UIGestureRecognizerStateBegan){
  75. MOLogV(@"触发了长按");
  76. // self.cellLongPressBlock ? self.cellLongPressBlock(self.cellModel) : nil;
  77. //
  78. // recognizer.enabled = NO;
  79. //白名单用户
  80. if(self.isWhiteList){
  81. self.translateBtn.hidden = NO;
  82. }
  83. }
  84. // else if (recognizer.state == UIGestureRecognizerStateEnded || recognizer.state == UIGestureRecognizerStateCancelled)
  85. // {
  86. // recognizer.enabled = YES;
  87. // }
  88. }
  89. - (void)setCellModel:(MORtmEntity *)cellModel{
  90. _cellModel = cellModel;
  91. NSMutableAttributedString *titleAttri = [MOTextTools creteTitleTextWith:cellModel];
  92. self.titleLab.attributedText = titleAttri;
  93. NSMutableAttributedString *contentAttri = [MOTextTools creteTextWith:cellModel];
  94. self.contentTextView.attributedText = contentAttri;
  95. // 计算文本高度
  96. CGFloat contentHeight = cellModel.cellHeight - MOTextTitleLabeHeight;
  97. if(contentHeight < MORtmContentMixHeight){
  98. contentHeight = MORtmContentMixHeight;
  99. }
  100. [self.contentTextView mas_updateConstraints:^(MASConstraintMaker *make) {
  101. make.height.equalTo(@(contentHeight));
  102. }];
  103. self.bgView.backgroundColor = MONormalBgViewColor;
  104. MORtmJosnEntity *jsonEntity = (MORtmJosnEntity *)cellModel.data;
  105. MORtmUser *rtmUser = cellModel.user;
  106. NSInteger theBubble = rtmUser.bubble;
  107. if(theBubble == 0){
  108. theBubble = rtmUser.dressing.bubble;
  109. }
  110. if(theBubble != 0){
  111. //旧逻辑 - 本地找
  112. UIImage *bubbleImg = [MOTextTools getBubbleImgWithCodeNum:theBubble];
  113. if(bubbleImg){
  114. [self.bubbleImgView setImage:bubbleImg];
  115. self.bubbleImgView.hidden = NO;
  116. self.bgView.backgroundColor = [UIColor clearColor];
  117. }
  118. else{
  119. //使用新逻辑 - 素材库
  120. MOEffect *bubbleObject = [[MOSvgaSourceManage shareManager] getPropsInfoWithCode:theBubble];
  121. if(bubbleObject){
  122. WEAKSELF
  123. NSURL *bubbleUrl = [NSURL URLWithString:bubbleObject.effectFile];
  124. [[MOBubbleImageManager sharedManager] resizableImageWithURL:bubbleUrl completion:^(UIImage *image) {
  125. dispatch_async(dispatch_get_main_queue(), ^{
  126. [weakSelf.bubbleImgView setImage:image];
  127. });
  128. }];
  129. self.bubbleImgView.hidden = NO;
  130. self.bgView.backgroundColor = [UIColor clearColor];
  131. }
  132. else{
  133. self.bubbleImgView.hidden = YES;
  134. }
  135. }
  136. }
  137. else{
  138. self.bubbleImgView.hidden = YES;
  139. }
  140. if(cellModel.cellHeight > (28.0 + MOTextTitleLabeHeight)){
  141. [self.bgView mas_updateConstraints:^(MASConstraintMaker *make) {
  142. make.width.equalTo(@(MOBgViewMaxWidth));
  143. }];
  144. [self.translateBtn mas_updateConstraints:^(MASConstraintMaker *make) {
  145. make.right.equalTo(self.bgView.mas_right).offset(0);
  146. }];
  147. }
  148. else{
  149. CGFloat width = cellModel.contentWidth + MOContentLeftAndRighSpacing * 2.0 + MOContentOffSet * 2.0;
  150. if(width > MOBgViewMaxWidth){
  151. width = MOBgViewMaxWidth;
  152. }
  153. if(width < MOBgViewMinWidth){
  154. width = MOBgViewMinWidth;
  155. }
  156. [self.bgView mas_updateConstraints:^(MASConstraintMaker *make) {
  157. make.width.equalTo(@(width));
  158. }];
  159. CGFloat translateBtnWidth = [MOTools getWidthWithString:self.translateBtn.titleLabel.text font:[MOTextTools regularFont:10.0]] + 10 + 12.0 * 2.0 + 10.0;
  160. CGFloat translateRight = translateBtnWidth - width + 10.0;
  161. if(translateBtnWidth > width){
  162. [self.translateBtn mas_updateConstraints:^(MASConstraintMaker *make) {
  163. make.right.equalTo(self.bgView.mas_right).offset(translateRight);
  164. }];
  165. }
  166. }
  167. }
  168. - (void)layoutSubviews {
  169. [super layoutSubviews];
  170. if(self.bubbleImgView.hidden){
  171. [self.bgView setCornerRadiusWithTopLeft:4 topRight:12 bottomRight:12 bottomLeft:12];
  172. }
  173. else{
  174. [self.bgView setCornerRadiusWithTopLeft:0 topRight:0 bottomRight:0 bottomLeft:0];
  175. }
  176. [self.translateBtn setCornerRadiusWithTopLeft:9.0 topRight:9.0 bottomRight:9.0 bottomLeft:2.0];
  177. }
  178. - (void)awakeFromNib {
  179. [super awakeFromNib];
  180. // Initialization code
  181. }
  182. - (void)setSelected:(BOOL)selected animated:(BOOL)animated {
  183. [super setSelected:selected animated:animated];
  184. // Configure the view for the selected state
  185. }
  186. #pragma mark - Lazy
  187. - (UIView *)bgView
  188. {
  189. if (_bgView == nil)
  190. {
  191. _bgView = [UIView new];
  192. _bgView.backgroundColor = MONormalBgViewColor;
  193. }
  194. return _bgView;
  195. }
  196. - (UIImageView *)bubbleImgView{
  197. if(!_bubbleImgView){
  198. _bubbleImgView = [[UIImageView alloc] init];
  199. [_bubbleImgView setImage:[UIImage imageNamed:@""]];
  200. }
  201. return _bubbleImgView;
  202. }
  203. - (YYLabel *)titleLab{
  204. if(!_titleLab){
  205. _titleLab = [YYLabel new];
  206. _titleLab.userInteractionEnabled = NO;
  207. _titleLab.textColor = [MOTools colorWithHexString:@"#FFFFFF" alpha:1.0];
  208. }
  209. return _titleLab;
  210. }
  211. - (MOMsgContentTextView *)contentTextView{
  212. if(!_contentTextView){
  213. _contentTextView = [MOMsgContentTextView new];
  214. _contentTextView.backgroundColor = [UIColor clearColor];
  215. _contentTextView.textContainerInset = UIEdgeInsetsMake(MOContentBaseTopSpcing, MOContentBaseLeftSpacing, MOContentBaseBottomSpcing, MOContentBaseRightSpacing);//UITextView原本文字距离左右有间距,设置负数消除边距
  216. _contentTextView.editable = NO;
  217. _contentTextView.scrollEnabled = NO;//防止滑出屏幕又滑入时有时单行文字消失
  218. _contentTextView.userInteractionEnabled = NO;
  219. _contentTextView.textColor = [MOTools colorWithHexString:@"#FFFFFF" alpha:1.0];
  220. }
  221. return _contentTextView;
  222. }
  223. - (BigBtn *)translateBtn{
  224. if (!_translateBtn) {
  225. _translateBtn = [BigBtn buttonWithType:UIButtonTypeCustom];
  226. [_translateBtn addTarget:self action:@selector(translateBtnClick) forControlEvents:UIControlEventTouchUpInside];
  227. [_translateBtn setFont:[MOTextTools regularFont:10.0]];
  228. [_translateBtn setTitle:NSLocalString(@"mimo_2_translate") forState:UIControlStateNormal];
  229. [_translateBtn setTitle:NSLocalString(@"mimo_2_translate_load") forState:UIControlStateSelected];
  230. [_translateBtn setTitleColor:[MOTools colorWithHexString:@"#4363FF"] forState:UIControlStateNormal];
  231. [_translateBtn setTitleColor:kBaseTextColor_2 forState:UIControlStateSelected];
  232. _translateBtn.backgroundColor = [UIColor whiteColor];
  233. [_translateBtn setImage:[UIImage imageNamed:@"v_2_tranlate"] forState:UIControlStateNormal];
  234. [_translateBtn setImage:[UIImage imageNamed:@"v_2_t_loading"] forState:UIControlStateSelected];
  235. // 调整图文间距和内边距
  236. CGFloat spacing = 5.0; // 减小图文间距
  237. _translateBtn.contentEdgeInsets = UIEdgeInsetsMake(2, 12, 2, 12); // 增加左右内边距
  238. _translateBtn.imageEdgeInsets = UIEdgeInsetsMake(0, -spacing/2, 0, spacing/2);
  239. _translateBtn.titleEdgeInsets = UIEdgeInsetsMake(0, spacing/2, 0, -spacing/2);
  240. // 2. 防止被压缩和截断
  241. [_translateBtn setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];
  242. [_translateBtn setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];
  243. _translateBtn.titleLabel.lineBreakMode = NSLineBreakByClipping;
  244. _translateBtn.titleLabel.adjustsFontSizeToFitWidth = NO; // 不自动缩小字体
  245. _translateBtn.hidden = YES;
  246. }
  247. return _translateBtn;
  248. }
  249. - (void)translateBtnClick{
  250. WEAKSELF
  251. NSString *bizIdStr = [MOTools generateUniqueID];
  252. self.cellModel.bizId = bizIdStr;
  253. MORtmJosnEntity *jsonEntity = (MORtmJosnEntity *)self.cellModel.data;
  254. NSString *contentStr = jsonEntity.content;
  255. if(bizIdStr.length == 0){
  256. return;
  257. }
  258. if(contentStr.length == 0){
  259. return;
  260. }
  261. self.translateBtn.selected = YES;
  262. [self startSpinAnimationOnButton:self.translateBtn];
  263. NSDictionary *dict = @{@"bizId":bizIdStr,@"content":contentStr};
  264. [kHttpManager toTranslationTheContentWith:dict andBlock:^(id _Nonnull data, NSError * _Nonnull error) {
  265. [weakSelf stopSpinAnimationOnButton:weakSelf.translateBtn];
  266. weakSelf.translateBtn.selected = NO;
  267. weakSelf.translateBtn.hidden = YES;
  268. if(kCode_Success){
  269. MOLogV(@"%@",[[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:data options:0 error:nil] encoding:NSUTF8StringEncoding]);
  270. NSDictionary *resultDict = data[@"data"];
  271. NSString *bizIdStr = [MODataManager objectOrNilForKey:@"bizId" fromDictionary:resultDict];
  272. NSString *contentStr = [MODataManager objectOrNilForKey:@"content" fromDictionary:resultDict];
  273. if([weakSelf.cellModel.bizId isEqualToString:bizIdStr]){
  274. MORtmJosnEntity *jsonEntityObject = (MORtmJosnEntity *)weakSelf.cellModel.data;
  275. if(contentStr.length != 0){
  276. jsonEntityObject.content = contentStr;
  277. CGSize size = [MOTextTools textMessageCellSizeWith:weakSelf.cellModel];
  278. weakSelf.cellModel.cellHeight = MAX(size.height + 1.0, MOTextLabelMinHeight);
  279. weakSelf.cellModel.contentWidth = [MOTextTools getWidthWith:weakSelf.cellModel];
  280. }
  281. }
  282. weakSelf.toRefreshTheCell ? weakSelf.toRefreshTheCell(weakSelf.cellModel) : nil;
  283. }
  284. else{
  285. MOLogV(@"toTranslationTheContentWith 接口报错了");
  286. kShowNetError(data)
  287. }
  288. }];
  289. }
  290. - (void)startSpinAnimationOnButton:(UIButton *)button {
  291. UIImageView *imageView = button.imageView;
  292. if (!imageView) return;
  293. // 创建旋转动画
  294. CABasicAnimation *rotation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
  295. rotation.toValue = @(M_PI * 2); // 旋转360°
  296. rotation.duration = 1.0; // 动画时长(秒)
  297. rotation.repeatCount = HUGE_VALF; // 无限循环
  298. rotation.removedOnCompletion = NO;
  299. rotation.fillMode = kCAFillModeForwards;
  300. [imageView.layer addAnimation:rotation forKey:@"spin"];
  301. }
  302. - (void)stopSpinAnimationOnButton:(UIButton *)button {
  303. [button.imageView.layer removeAnimationForKey:@"spin"];
  304. }
  305. @end