提交
This commit is contained in:
17
QXLive/Base/NSURLSession+QX.h
Normal file
17
QXLive/Base/NSURLSession+QX.h
Normal file
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// NSURLSession+BJX.h
|
||||
// BJXGame
|
||||
//
|
||||
// Created by apple on 2022/11/7.
|
||||
// Copyright © 2022 鑫创. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface NSURLSession (QX)
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
37
QXLive/Base/NSURLSession+QX.m
Normal file
37
QXLive/Base/NSURLSession+QX.m
Normal file
@@ -0,0 +1,37 @@
|
||||
//
|
||||
// NSURLSession+BJX.m
|
||||
// BJXGame
|
||||
//
|
||||
// Created by apple on 2022/11/7.
|
||||
// Copyright © 2022 鑫创. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSURLSession+QX.h"
|
||||
#import <objc/runtime.h>
|
||||
|
||||
@implementation NSURLSession (QX)
|
||||
+ (void)load{
|
||||
Method method1 = class_getClassMethod([NSURLSession class],@selector(sessionWithConfiguration:));
|
||||
Method method2 = class_getClassMethod([NSURLSession class],@selector(px_sessionWithConfiguration:));
|
||||
method_exchangeImplementations(method1, method2);
|
||||
|
||||
Method method3 =class_getClassMethod([NSURLSession class],@selector(sessionWithConfiguration:delegate:delegateQueue:));
|
||||
Method method4 =class_getClassMethod([NSURLSession class],@selector(px_sessionWithConfiguration:delegate:delegateQueue:));
|
||||
method_exchangeImplementations(method3, method4);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+ (NSURLSession*)px_sessionWithConfiguration:(NSURLSessionConfiguration*)configuration delegate:(nullable id)delegate delegateQueue:(nullable NSOperationQueue*)queue{
|
||||
if(configuration) configuration.connectionProxyDictionary=@{};
|
||||
return [self px_sessionWithConfiguration:configuration delegate:delegate delegateQueue:queue];
|
||||
}
|
||||
|
||||
|
||||
|
||||
+ (NSURLSession*)px_sessionWithConfiguration:(NSURLSessionConfiguration*)configuration{
|
||||
if(configuration) configuration.connectionProxyDictionary=@{};
|
||||
return [self px_sessionWithConfiguration:configuration];
|
||||
}
|
||||
|
||||
@end
|
||||
26
QXLive/Base/QXAlertViewController.h
Normal file
26
QXLive/Base/QXAlertViewController.h
Normal file
@@ -0,0 +1,26 @@
|
||||
//
|
||||
// QXAlertViewController.h
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/4/27.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
typedef NS_ENUM(NSInteger) {
|
||||
///从底部向上弹出view 弹出形式类似于actionsheet
|
||||
PopViewTypeBottomToUpActionSheet = 0,
|
||||
///从中间弹出
|
||||
PopViewTypePopFromCenter,
|
||||
///从顶部向中间弹窗
|
||||
PopViewTypeTopToCenter,
|
||||
}PopViewType;
|
||||
@interface QXAlertViewController : UIViewController
|
||||
@property (nonatomic,strong)UIView *alertView;
|
||||
@property (nonatomic,assign)PopViewType popType;
|
||||
@property (nonatomic,assign)BOOL tapDismiss;
|
||||
-(void)hideViewFinishBlock:(void(^)(void))closeBlock;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
152
QXLive/Base/QXAlertViewController.m
Normal file
152
QXLive/Base/QXAlertViewController.m
Normal file
@@ -0,0 +1,152 @@
|
||||
//
|
||||
// QXAlertViewController.m
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/4/27.
|
||||
//
|
||||
|
||||
#import "QXAlertViewController.h"
|
||||
|
||||
@interface QXAlertViewController ()<UIGestureRecognizerDelegate>
|
||||
|
||||
@property(nonatomic,copy)void (^closeBlock)(void);
|
||||
@end
|
||||
|
||||
@implementation QXAlertViewController
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
// Do any additional setup after loading the view.
|
||||
self.view.backgroundColor = [UIColor colorWithWhite:0.0 alpha:0.3];
|
||||
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapAction)];
|
||||
tap.delegate = self;
|
||||
[self.view addGestureRecognizer:tap];
|
||||
|
||||
}
|
||||
-(void)viewDidAppear:(BOOL)animated{
|
||||
[super viewDidAppear:animated];
|
||||
[self beginShow];
|
||||
}
|
||||
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
|
||||
[self.view endEditing:YES];
|
||||
}
|
||||
-(void)beginShow{
|
||||
_alertView.centerX = self.view.centerX;
|
||||
switch (_popType) {
|
||||
case PopViewTypeBottomToUpActionSheet:{
|
||||
_alertView.y = SCREEN_HEIGHT;
|
||||
[self.view addSubview:_alertView];
|
||||
[UIView animateWithDuration:0.3 animations:^{
|
||||
self->_alertView.y = (SCREEN_HEIGHT-self->_alertView.height);
|
||||
} completion:^(BOOL finished) {
|
||||
|
||||
}];
|
||||
}
|
||||
break;
|
||||
case PopViewTypePopFromCenter:{
|
||||
_alertView.centerX = self.view.centerX;
|
||||
_alertView.centerY = self.view.centerY;
|
||||
[self.view addSubview:_alertView];
|
||||
_alertView.transform = CGAffineTransformMakeScale(0.1, 0.1);
|
||||
// 弹性动画
|
||||
[UIView animateWithDuration:0.3
|
||||
delay:0
|
||||
usingSpringWithDamping:0.9
|
||||
initialSpringVelocity:0.1
|
||||
options:UIViewAnimationOptionCurveEaseInOut
|
||||
animations:^{
|
||||
self->_alertView.transform = CGAffineTransformIdentity;
|
||||
} completion:nil];
|
||||
}
|
||||
|
||||
break;
|
||||
case PopViewTypeTopToCenter:{
|
||||
_alertView.y = -SCREEN_HEIGHT;
|
||||
[self.view addSubview:_alertView];
|
||||
[UIView animateWithDuration:0.3 delay:0 usingSpringWithDamping:0.6 initialSpringVelocity:1 options:UIViewAnimationOptionCurveEaseInOut animations:^{
|
||||
self->_alertView.y = (SCREEN_HEIGHT-self->_alertView.height)/2.0;
|
||||
} completion:^(BOOL finished) {
|
||||
|
||||
}];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
-(void)tapAction{
|
||||
if (!self.tapDismiss) {
|
||||
return;
|
||||
}
|
||||
[self hideViewFinishBlock:self.closeBlock];
|
||||
}
|
||||
|
||||
-(void)hideViewFinishBlock:(void (^)(void))closeBlock{
|
||||
MJWeakSelf
|
||||
switch (_popType) {
|
||||
case PopViewTypeBottomToUpActionSheet:{
|
||||
[UIView animateWithDuration:0.3 animations:^{
|
||||
self->_alertView.y = SCREEN_HEIGHT;
|
||||
} completion:^(BOOL finished) {
|
||||
[self->_alertView removeFromSuperview];
|
||||
[self dismissViewControllerAnimated:NO completion:^{
|
||||
if (closeBlock) {
|
||||
closeBlock();
|
||||
}
|
||||
}];
|
||||
}];
|
||||
}
|
||||
break;
|
||||
case PopViewTypePopFromCenter:{
|
||||
[UIView animateWithDuration:0.3
|
||||
delay:0
|
||||
usingSpringWithDamping:0.9
|
||||
initialSpringVelocity:1
|
||||
options:UIViewAnimationOptionCurveEaseInOut
|
||||
animations:^{
|
||||
self->_alertView.transform = CGAffineTransformMakeScale(0.001, 0.001);
|
||||
} completion:^(BOOL finished) {
|
||||
[self->_alertView removeFromSuperview];
|
||||
[self dismissViewControllerAnimated:NO completion:^{
|
||||
if (closeBlock) {
|
||||
closeBlock();
|
||||
}
|
||||
}];
|
||||
}];
|
||||
}
|
||||
break;
|
||||
case PopViewTypeTopToCenter:{
|
||||
[UIView animateWithDuration:0.3 delay:0 usingSpringWithDamping:0.6 initialSpringVelocity:1 options:UIViewAnimationOptionCurveEaseInOut animations:^{
|
||||
self->_alertView.y = SCREEN_HEIGHT;
|
||||
} completion:^(BOOL finished) {
|
||||
[self->_alertView removeFromSuperview];
|
||||
[self dismissViewControllerAnimated:NO completion:^{
|
||||
if (closeBlock) {
|
||||
closeBlock();
|
||||
}
|
||||
}];
|
||||
}];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
-(void)setPopType:(PopViewType)popType{
|
||||
_popType = popType;
|
||||
}
|
||||
|
||||
-(void)setAlertView:(UIView *)alertView{
|
||||
if (_alertView) {
|
||||
[_alertView removeFromSuperview];
|
||||
_alertView = nil;
|
||||
}
|
||||
_alertView = alertView;
|
||||
}
|
||||
|
||||
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{
|
||||
return touch.view == self.view;
|
||||
}
|
||||
|
||||
@end
|
||||
16
QXLive/Base/QXBadgeButton.h
Normal file
16
QXLive/Base/QXBadgeButton.h
Normal file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// QXBadgeButton.h
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/7/28.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "TIMCommonModel.h"
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QXBadgeButton : UIButton
|
||||
@property (nonatomic,strong)TUIUnReadView *unreadView;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
64
QXLive/Base/QXBadgeButton.m
Normal file
64
QXLive/Base/QXBadgeButton.m
Normal file
@@ -0,0 +1,64 @@
|
||||
//
|
||||
// QXBadgeButton.m
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/7/28.
|
||||
//
|
||||
|
||||
#import "QXBadgeButton.h"
|
||||
|
||||
@implementation QXBadgeButton
|
||||
- (instancetype)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
[self addSubview:self.unreadView];
|
||||
[self.unreadView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.mas_equalTo(self);
|
||||
make.right.equalTo(self);
|
||||
make.width.mas_equalTo(kScale375(17));
|
||||
make.height.mas_equalTo(kScale375(17));
|
||||
}];
|
||||
|
||||
|
||||
[self.unreadView.unReadLabel mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.center.mas_equalTo(self.unreadView);
|
||||
make.size.mas_equalTo(self.unreadView.unReadLabel);
|
||||
}];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (instancetype)initWithFrame:(CGRect)frame
|
||||
{
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
[self addSubview:self.unreadView];
|
||||
[self.unreadView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.mas_equalTo(self);
|
||||
make.right.equalTo(self);
|
||||
make.width.mas_equalTo(kScale375(17));
|
||||
make.height.mas_equalTo(kScale375(17));
|
||||
}];
|
||||
|
||||
|
||||
[self.unreadView.unReadLabel mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.center.mas_equalTo(self.unreadView);
|
||||
make.size.mas_equalTo(self.unreadView.unReadLabel);
|
||||
}];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
-(TUIUnReadView *)unreadView{
|
||||
if (!_unreadView) {
|
||||
_unreadView = [[TUIUnReadView alloc] init];
|
||||
_unreadView.userInteractionEnabled = NO;
|
||||
[_unreadView setNum:0];
|
||||
|
||||
[_unreadView.unReadLabel sizeToFit];
|
||||
|
||||
_unreadView.layer.cornerRadius = kScale375(10);
|
||||
[_unreadView.layer masksToBounds];
|
||||
}
|
||||
return _unreadView;
|
||||
}
|
||||
@end
|
||||
16
QXLive/Base/QXBaseModel.h
Normal file
16
QXLive/Base/QXBaseModel.h
Normal file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// QXBaseModel.h
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/5/13.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QXBaseModel : NSObject
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
12
QXLive/Base/QXBaseModel.m
Normal file
12
QXLive/Base/QXBaseModel.m
Normal file
@@ -0,0 +1,12 @@
|
||||
//
|
||||
// QXBaseModel.m
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/5/13.
|
||||
//
|
||||
|
||||
#import "QXBaseModel.h"
|
||||
|
||||
@implementation QXBaseModel
|
||||
|
||||
@end
|
||||
16
QXLive/Base/QXBaseNavigationController.h
Normal file
16
QXLive/Base/QXBaseNavigationController.h
Normal file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// QXBaseNavigationController.h
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/4/24.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QXBaseNavigationController : UINavigationController
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
79
QXLive/Base/QXBaseNavigationController.m
Normal file
79
QXLive/Base/QXBaseNavigationController.m
Normal file
@@ -0,0 +1,79 @@
|
||||
//
|
||||
// QXBaseNavigationController.m
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/4/24.
|
||||
//
|
||||
|
||||
#import "QXBaseNavigationController.h"
|
||||
|
||||
@interface QXBaseNavigationController ()<UINavigationControllerDelegate,UIGestureRecognizerDelegate>
|
||||
|
||||
@end
|
||||
|
||||
@implementation QXBaseNavigationController
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
// Do any additional setup after loading the view.
|
||||
self.interactivePopGestureRecognizer.delegate = self;
|
||||
self.delegate = self;
|
||||
}
|
||||
-(void)viewWillAppear:(BOOL)animated{
|
||||
[super viewWillAppear:animated];
|
||||
}
|
||||
|
||||
-(void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated{
|
||||
if (self.viewControllers.count == 1) {
|
||||
viewController.hidesBottomBarWhenPushed = YES;
|
||||
}
|
||||
// if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
|
||||
// self.interactivePopGestureRecognizer.enabled = YES;
|
||||
// }
|
||||
[super pushViewController:viewController animated:animated];
|
||||
}
|
||||
//-(UIViewController *)popViewControllerAnimated:(BOOL)animated{
|
||||
// if (self.childViewControllers.count == 2) {
|
||||
// if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
|
||||
// self.interactivePopGestureRecognizer.enabled = YES;
|
||||
// }
|
||||
// }
|
||||
// return [super popViewControllerAnimated:animated];
|
||||
//}
|
||||
-(void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated{
|
||||
if (self.childViewControllers.count > 1) {
|
||||
if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
|
||||
if ([self.visibleViewController isKindOfClass:NSClassFromString(@"QXRoomViewController")]) {
|
||||
self.interactivePopGestureRecognizer.enabled = NO;
|
||||
}else{
|
||||
self.interactivePopGestureRecognizer.enabled = YES;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
|
||||
self.interactivePopGestureRecognizer.enabled = NO;
|
||||
}
|
||||
}
|
||||
}
|
||||
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
|
||||
if (self.viewControllers.count == 1) {
|
||||
return NO;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
/*
|
||||
#pragma mark - Navigation
|
||||
|
||||
// In a storyboard-based application, you will often want to do a little preparation before navigation
|
||||
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
|
||||
// Get the new view controller using [segue destinationViewController].
|
||||
// Pass the selected object to the new view controller.
|
||||
}
|
||||
*/
|
||||
|
||||
@end
|
||||
26
QXLive/Base/QXBaseViewController.h
Normal file
26
QXLive/Base/QXBaseViewController.h
Normal file
@@ -0,0 +1,26 @@
|
||||
//
|
||||
// QXBaseViewController.h
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/4/24.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QXBaseViewController : UIViewController
|
||||
@property (nonatomic,strong)NSMutableArray *dataArray;
|
||||
@property (nonatomic,assign)NSInteger page;
|
||||
@property (nonatomic,assign)BOOL bgImageHidden;
|
||||
//交给子类来实现
|
||||
-(void)setNavgationItems;
|
||||
-(void)initSubViews;
|
||||
- (void)getData;
|
||||
/**
|
||||
imageurl :图片名称或链接
|
||||
*/
|
||||
-(void)updateBgImage:(NSString*)imageUrl;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
79
QXLive/Base/QXBaseViewController.m
Normal file
79
QXLive/Base/QXBaseViewController.m
Normal file
@@ -0,0 +1,79 @@
|
||||
//
|
||||
// QXBaseViewController.m
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/4/24.
|
||||
//
|
||||
|
||||
#import "QXBaseViewController.h"
|
||||
|
||||
@interface QXBaseViewController ()
|
||||
@property (nonatomic,strong)UIImageView *bgImageView;
|
||||
@property (nonatomic,strong)NSString *imageUrl;
|
||||
@end
|
||||
|
||||
@implementation QXBaseViewController
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
// Do any additional setup after loading the view.
|
||||
[self.view insertSubview:self.bgImageView atIndex:0];
|
||||
[self updateBgImage:QXConfig.backgroundImage];
|
||||
[self initSubViews];
|
||||
[self setNavgationItems];
|
||||
[self getData];
|
||||
self.page = 1;
|
||||
}
|
||||
- (void)initSubViews{
|
||||
|
||||
}
|
||||
- (void)getData{
|
||||
|
||||
}
|
||||
-(void)setNavgationItems{
|
||||
UIButton*backBtn = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 44, 44)];
|
||||
[backBtn setImage:[UIImage imageNamed:@"back"] forState:(UIControlStateNormal)];
|
||||
backBtn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeading;
|
||||
[backBtn addTarget:self action:@selector(backAction) forControlEvents:(UIControlEventTouchUpInside)];
|
||||
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:backBtn];
|
||||
}
|
||||
-(void)backAction{
|
||||
if (self.navigationController.viewControllers.count > 1) {
|
||||
[self.navigationController popViewControllerAnimated:YES];
|
||||
return;
|
||||
}else{
|
||||
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
|
||||
}
|
||||
}
|
||||
-(void)setBgImageHidden:(BOOL)bgImageHidden{
|
||||
_bgImageHidden = bgImageHidden;
|
||||
self.bgImageView.hidden = bgImageHidden;
|
||||
}
|
||||
-(void)updateBgImage:(NSString *)imageUrl{
|
||||
_imageUrl = imageUrl;
|
||||
if (![imageUrl isExist]) {
|
||||
return;
|
||||
}
|
||||
if ([imageUrl hasPrefix:@"http"]) {
|
||||
[self.bgImageView sd_setImageWithURL:[NSURL URLWithString:imageUrl] placeholderImage:nil];
|
||||
}else{
|
||||
self.bgImageView.image = [UIImage imageNamed:imageUrl];
|
||||
}
|
||||
}
|
||||
-(UIImageView *)bgImageView{
|
||||
if (!_bgImageView) {
|
||||
_bgImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT)];
|
||||
_bgImageView.contentMode = UIViewContentModeScaleAspectFill;
|
||||
}
|
||||
return _bgImageView;
|
||||
}
|
||||
-(NSMutableArray *)dataArray{
|
||||
if (!_dataArray) {
|
||||
_dataArray = [NSMutableArray array];
|
||||
}
|
||||
return _dataArray;
|
||||
}
|
||||
-(void)dealloc{
|
||||
QXLOG(@"%@已销毁",NSStringFromClass([self class]));
|
||||
}
|
||||
@end
|
||||
23
QXLive/Base/QXBaseWebViewController.h
Normal file
23
QXLive/Base/QXBaseWebViewController.h
Normal file
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// TBaseWebViewController.h
|
||||
// YSDTrucksProject
|
||||
//
|
||||
// Created by 党凯 on 2020/7/3.
|
||||
// Copyright © 2020 党凯. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QXBaseViewController.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QXBaseWebViewController : QXBaseViewController
|
||||
//网页链接
|
||||
@property(nonatomic,copy)NSString *urlStr;
|
||||
//html内容
|
||||
@property(nonatomic,copy)NSString *content;
|
||||
/** 进度条颜色 */
|
||||
@property (nonatomic, assign) UIColor *progressColor;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
243
QXLive/Base/QXBaseWebViewController.m
Normal file
243
QXLive/Base/QXBaseWebViewController.m
Normal file
@@ -0,0 +1,243 @@
|
||||
//
|
||||
// QXBaseWebViewController.m
|
||||
// YSDTrucksProject
|
||||
//
|
||||
// Created by 党凯 on 2020/7/3.
|
||||
// Copyright © 2020 党凯. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QXBaseWebViewController.h"
|
||||
#import <WebKit/WebKit.h>
|
||||
|
||||
static void *WKWebBrowserContext = &WKWebBrowserContext;
|
||||
@interface QXBaseWebViewController ()<WKNavigationDelegate,WKUIDelegate,WKScriptMessageHandler>
|
||||
@property(nonatomic,strong)WKWebView *contentWebView;
|
||||
@property(nonatomic,strong)UIProgressView *progressView;
|
||||
//@property (nonatomic,strong)TitleView *titleView;
|
||||
@end
|
||||
|
||||
@implementation QXBaseWebViewController
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
// Do any additional setup after loading the view.
|
||||
// if (@available(iOS 11.0, *)) {
|
||||
// self.contentWebView.scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
|
||||
// } else {
|
||||
// self.automaticallyAdjustsScrollViewInsets = NO;
|
||||
// }
|
||||
|
||||
[self.view addSubview:self.contentWebView];
|
||||
[self.view addSubview:self.progressView];
|
||||
|
||||
[self layoutConstraints];
|
||||
[self loadData];
|
||||
}
|
||||
-(void)viewWillAppear:(BOOL)animated{
|
||||
[super viewWillAppear:animated];
|
||||
[self.navigationController setNavigationBarHidden:NO animated:YES];
|
||||
}
|
||||
-(void)setNavgationItems{
|
||||
[super setNavgationItems];
|
||||
}
|
||||
- (void)layoutConstraints {
|
||||
[self.contentWebView setFrame:CGRectMake(0, NavContentHeight, SCREEN_WIDTH, SCREEN_HEIGHT-(NavContentHeight))];
|
||||
[self.progressView setFrame:CGRectMake(0, NavContentHeight, SCREEN_WIDTH
|
||||
, 2)];
|
||||
}
|
||||
- (void)loadData {
|
||||
if (self.urlStr.length) {
|
||||
if ([self.urlStr hasPrefix:@"http"]) {
|
||||
NSURL* url=[NSURL URLWithString:self.urlStr];
|
||||
NSURLRequest *request =[NSURLRequest requestWithURL:url];
|
||||
[self.contentWebView loadRequest:request];
|
||||
}else{
|
||||
NSURL* url=[NSURL fileURLWithPath:self.urlStr];
|
||||
NSURLRequest *request =[NSURLRequest requestWithURL:url];
|
||||
[self.contentWebView loadRequest:request];
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (self.content.length) {
|
||||
[self.contentWebView loadHTMLString:self.content baseURL:nil];
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - WKNavigationDelegate
|
||||
//开始加载
|
||||
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation{
|
||||
//开始加载的时候,让加载进度条显示
|
||||
self.progressView.hidden = NO;
|
||||
}
|
||||
|
||||
//网页加载完成
|
||||
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{
|
||||
// 获取加载网页的标题
|
||||
if (self.title.length == 0) {
|
||||
self.title = self.contentWebView.title;
|
||||
}
|
||||
// if ([self.titleString containsString:@"转账"]) {
|
||||
// // 设置字体
|
||||
// NSString *fontFamilyStr = @"document.getElementsByTagName('body')[0].style.fontFamily='Arial';";
|
||||
// [webView evaluateJavaScript:fontFamilyStr completionHandler:nil];
|
||||
// //设置颜色
|
||||
// [ webView evaluateJavaScript:@"document.getElementsByTagName('body')[0].style.webkitTextFillColor= '#333333'" completionHandler:nil];
|
||||
// //修改字体大小
|
||||
// [ webView evaluateJavaScript:@"document.getElementsByTagName('body')[0].style.webkitTextSizeAdjust= '150%'"completionHandler:nil];
|
||||
// }
|
||||
}
|
||||
//内容返回时调用
|
||||
- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation {
|
||||
|
||||
}
|
||||
|
||||
//服务器请求跳转的时候调用
|
||||
- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation {
|
||||
|
||||
}
|
||||
|
||||
// 内容加载失败时候调用
|
||||
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error{
|
||||
|
||||
}
|
||||
-(void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
|
||||
NSLog(@"message.name====%@ body=%@",message.name,message.body);
|
||||
if([message.name isEqualToString:@"toRegister"]){
|
||||
// RegistVC *vc = [[RegistVC alloc] init];
|
||||
// vc.isRegist = YES;
|
||||
// [self.navigationController pushViewController:vc animated:YES];
|
||||
// NSMutableArray *vcArr = [[NSMutableArray alloc]initWithArray:self.navigationController.viewControllers];
|
||||
// for (UIViewController *vc in vcArr) {
|
||||
// if ([vc isKindOfClass:[self class]]) {
|
||||
// [vcArr removeObject:vc];
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// self.navigationController.viewControllers = vcArr;
|
||||
}
|
||||
}
|
||||
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
|
||||
//如果是跳转一个新页面
|
||||
if (navigationAction.targetFrame == nil) {
|
||||
[webView loadRequest:navigationAction.request];
|
||||
}
|
||||
NSURL *URL = navigationAction.request.URL;
|
||||
[self dealSomeThing:URL];
|
||||
decisionHandler(WKNavigationActionPolicyAllow);
|
||||
}
|
||||
|
||||
- (void)dealSomeThing:(NSURL *)url{
|
||||
NSString *scheme = [url scheme];
|
||||
NSString *resourceSpecifier = [url resourceSpecifier];
|
||||
if ([scheme isEqualToString:@"tel"]) {
|
||||
NSString *callPhone = [NSString stringWithFormat:@"tel://%@", resourceSpecifier];
|
||||
/// 防止iOS 10及其之后,拨打电话系统弹出框延迟出现
|
||||
dispatch_async(dispatch_get_global_queue(0, 0), ^{
|
||||
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:callPhone]];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//进度条
|
||||
- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView {
|
||||
}
|
||||
|
||||
//KVO监听进度条
|
||||
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
|
||||
|
||||
if ([keyPath isEqualToString:NSStringFromSelector(@selector(estimatedProgress))] && object == self.contentWebView) {
|
||||
[self.progressView setAlpha:1.0f];
|
||||
BOOL animated = self.contentWebView.estimatedProgress > self.progressView.progress;
|
||||
[self.progressView setProgress:self.contentWebView.estimatedProgress animated:animated];
|
||||
|
||||
// Once complete, fade out UIProgressView
|
||||
if(self.contentWebView.estimatedProgress >= 1.0f) {
|
||||
[UIView animateWithDuration:0.3f delay:0.3f options:UIViewAnimationOptionCurveEaseOut animations:^{
|
||||
[self.progressView setAlpha:0.0f];
|
||||
} completion:^(BOOL finished) {
|
||||
[self.progressView setProgress:0.0f animated:NO];
|
||||
}];
|
||||
}
|
||||
}
|
||||
else {
|
||||
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - getters and setters
|
||||
- (WKWebView *)contentWebView {
|
||||
if (!_contentWebView) {
|
||||
//设置网页的配置文件
|
||||
WKWebViewConfiguration * configuration = [[WKWebViewConfiguration alloc]init];
|
||||
// 允许可以与网页交互,选择视图
|
||||
configuration.selectionGranularity = YES;
|
||||
// web内容处理池pr
|
||||
configuration.processPool = [[WKProcessPool alloc] init];
|
||||
//自定义配置,一般用于 js调用oc方法(OC拦截URL中的数据做自定义操作)
|
||||
WKUserContentController * UserContentController = [[WKUserContentController alloc]init];
|
||||
// 是否支持记忆读取
|
||||
configuration.suppressesIncrementalRendering = YES;
|
||||
// 允许用户更改网页的设置
|
||||
[UserContentController addScriptMessageHandler:self name:@"toRegister"];
|
||||
configuration.preferences.javaScriptEnabled = YES;
|
||||
configuration.preferences.javaScriptCanOpenWindowsAutomatically = YES;
|
||||
configuration.userContentController = UserContentController;
|
||||
// 此处一定要做判断,因为是iOS9之后才有的方法,否则在iOS8下会崩溃
|
||||
if ([[UIDevice currentDevice].systemVersion floatValue] >= 9.0) {
|
||||
//允许视频播放
|
||||
configuration.allowsAirPlayForMediaPlayback = YES;
|
||||
// 允许在线播放
|
||||
configuration.allowsInlineMediaPlayback = YES;
|
||||
//开启手势触摸 默认设置就是NO。在ios8系统中会导致手势问题,程序崩溃
|
||||
_contentWebView.allowsBackForwardNavigationGestures = YES;
|
||||
}
|
||||
_contentWebView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:configuration];
|
||||
_contentWebView.backgroundColor = [UIColor whiteColor];
|
||||
_contentWebView.opaque = YES;
|
||||
//适应你设定的尺寸
|
||||
[_contentWebView sizeToFit];
|
||||
_contentWebView.scrollView.showsVerticalScrollIndicator = NO;
|
||||
// 设置代理
|
||||
_contentWebView.navigationDelegate = self;
|
||||
//kvo 添加进度监控
|
||||
[_contentWebView addObserver:self forKeyPath:NSStringFromSelector(@selector(estimatedProgress)) options:0 context:WKWebBrowserContext];
|
||||
}
|
||||
return _contentWebView;
|
||||
}
|
||||
|
||||
- (UIProgressView *)progressView {
|
||||
if (!_progressView) {
|
||||
_progressView = [[UIProgressView alloc]initWithProgressViewStyle:UIProgressViewStyleDefault];
|
||||
[_progressView setTrackTintColor:[UIColor colorWithRed:240.0/255 green:240.0/255 blue:240.0/255 alpha:1.0]];
|
||||
_progressView.progressTintColor = QXConfig.themeColor;
|
||||
}
|
||||
return _progressView;
|
||||
}
|
||||
|
||||
-(void)setProgressColor:(UIColor *)progressColor{
|
||||
_progressView.progressTintColor = progressColor;
|
||||
}
|
||||
// 记得dealloc
|
||||
- (void)dealloc {
|
||||
if (self) {
|
||||
[self.contentWebView removeObserver:self forKeyPath:NSStringFromSelector(@selector(estimatedProgress))];
|
||||
}
|
||||
}
|
||||
- (void)didReceiveMemoryWarning {
|
||||
[super didReceiveMemoryWarning];
|
||||
// Dispose of any resources that can be recreated.
|
||||
}
|
||||
|
||||
/*
|
||||
#pragma mark - Navigation
|
||||
|
||||
// In a storyboard-based application, you will often want to do a little preparation before navigation
|
||||
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
|
||||
// Get the new view controller using [segue destinationViewController].
|
||||
// Pass the selected object to the new view controller.
|
||||
}
|
||||
*/
|
||||
|
||||
@end
|
||||
116
QXLive/Base/QXGlobal.h
Normal file
116
QXLive/Base/QXGlobal.h
Normal file
@@ -0,0 +1,116 @@
|
||||
//
|
||||
// QXGlobal.h
|
||||
// YSDTrucksProject
|
||||
//
|
||||
// Created by 党凯 on 2020/6/30.
|
||||
// Copyright © 2020 党凯. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "QXAlertViewController.h"
|
||||
#import "QXLoginModel.h"
|
||||
#import "QXMiniRoomView.h"
|
||||
#import "QXDayTaskModel.h"
|
||||
#import "QXRoomViewController.h"
|
||||
|
||||
typedef void (^closeBlock)(void);
|
||||
typedef void (^showFinishBlock)(void);
|
||||
typedef NS_ENUM(NSInteger) {
|
||||
/// 房主
|
||||
QXRoomRoleTypeOwner = 0,
|
||||
/// 主持
|
||||
QXRoomRoleTypeCompere,
|
||||
/// 管理员
|
||||
QXRoomRoleTypeManager,
|
||||
/// 观众
|
||||
QXRoomRoleTypeAudience,
|
||||
}QXRoomRoleType;
|
||||
|
||||
|
||||
@interface QXGlobal : NSObject
|
||||
+(instancetype)shareGlobal;
|
||||
// 是否登录
|
||||
@property (nonatomic,readonly,assign)BOOL isLogin;
|
||||
@property (nonatomic,assign)BOOL isShowLoginVC;
|
||||
/// 房间id
|
||||
@property (nonatomic,strong,readonly)NSString *roomId;
|
||||
// 是否实名
|
||||
@property (nonatomic,assign)BOOL isRealName;
|
||||
|
||||
/// 钻石兑币比例
|
||||
@property (nonatomic,strong)NSString *coin_exchange_rate;
|
||||
/// 提现手续费
|
||||
@property (nonatomic,strong)NSString *withdrawal_service_fee;
|
||||
/// 购买金币比例
|
||||
@property (nonatomic,strong)NSString *rmb_coin_ratio;
|
||||
|
||||
@property (nonatomic,strong)QXLoginModel *loginModel;
|
||||
// 初始化时是否支持一键登录
|
||||
@property (nonatomic,assign)BOOL canOneLogin;
|
||||
|
||||
@property (nonatomic,strong)QXAlertViewController *alertViewController;
|
||||
|
||||
@property (nonatomic,strong) QXMiniRoomView *miniView;
|
||||
|
||||
/// 每日任务id
|
||||
@property (nonatomic,strong) QXDayTaskListModel *taskModel;
|
||||
|
||||
@property (nonatomic,strong) QXRoomViewController *roomVC;
|
||||
|
||||
-(void)miniRoomWithRoomId:(NSString*)roomId roomCover:(NSString*)roomCover;
|
||||
|
||||
|
||||
-(BOOL)isOpenRecharge;
|
||||
|
||||
-(UIWindow*)getKeyWindow;
|
||||
|
||||
/// 退出登录
|
||||
-(void)logOut;
|
||||
|
||||
-(void)removeLocalData;
|
||||
|
||||
/// 保存个人信息
|
||||
-(void)saveLoginData:(NSString*)userInfoJson;
|
||||
/// 更新个人信息
|
||||
-(void)updateUserInfoWithMolde:(QXLoginModel *)loginModel;
|
||||
|
||||
-(void)removeMemory;
|
||||
|
||||
-(void)toLogin;
|
||||
-(void)showView:(UIView *)view popType:(PopViewType)popType tapDismiss:(BOOL)tapDismiss finishBlock:(showFinishBlock)finishBlock;
|
||||
-(void)showView:(UIView *)view controller:(UIViewController*)controller popType:(PopViewType)popType tapDismiss:(BOOL)tapDismiss finishBlock:(showFinishBlock)finishBlock;
|
||||
-(void)hideViewBlock:(closeBlock)closeBlock;
|
||||
|
||||
/**
|
||||
去聊天
|
||||
*/
|
||||
-(void)chatWithUserID:(NSString*)userId
|
||||
nickname:(NSString*)nickname
|
||||
avatar:(NSString*)avatar
|
||||
navagationController:(UINavigationController*)navagationController;
|
||||
/**
|
||||
去群聊
|
||||
*/
|
||||
-(void)chatWithGroupId:(NSString*)groupId
|
||||
cover:(NSString*)cover
|
||||
name:(NSString*)name
|
||||
navagationController:(UINavigationController*)navagationController;
|
||||
|
||||
/**
|
||||
加入房间
|
||||
*/
|
||||
-(void)joinRoomWithRoomId:(NSString*)roomId
|
||||
isRejoin:(BOOL)isRejoin
|
||||
navagationController:(UINavigationController*)navagationController;
|
||||
|
||||
/**
|
||||
退出房间
|
||||
*/
|
||||
-(void)quitRoomWithRoomId:(NSString*)roomId;
|
||||
/// 去完成任务
|
||||
-(void)finishTask;
|
||||
|
||||
-(void)vibrationFeedback;
|
||||
@end
|
||||
|
||||
|
||||
297
QXLive/Base/QXGlobal.m
Normal file
297
QXLive/Base/QXGlobal.m
Normal file
@@ -0,0 +1,297 @@
|
||||
//
|
||||
// QXGlobal.m
|
||||
// TrucksProject
|
||||
//
|
||||
// Created by 党凯 on 2020/6/30.
|
||||
// Copyright © 2020 党凯. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QXGlobal.h"
|
||||
#import "AppDelegate.h"
|
||||
#import "QXLoginViewController.h"
|
||||
#import "QXBaseNavigationController.h"
|
||||
#import "TUILogin.h"
|
||||
#import "QXChatViewController.h"
|
||||
#import "QXRoomViewController.h"
|
||||
#import "QXMineNetwork.h"
|
||||
#import "QXGiftPlayerManager.h"
|
||||
#import "QXAgoraEngine.h"
|
||||
#import "QXRoomMessageManager.h"
|
||||
#import "QXTimer.h"
|
||||
#import <TIMPush/TIMPushManager.h>
|
||||
#import "QXManagerMqtt.h"
|
||||
|
||||
@interface QXGlobal()
|
||||
@property (nonatomic,assign)BOOL isLogin;
|
||||
@property (nonatomic,strong)NSString *roomId;
|
||||
|
||||
@property (nonatomic,strong)QXTimer *timer;
|
||||
@property (nonatomic,assign)NSInteger taskTime;
|
||||
@end
|
||||
@implementation QXGlobal
|
||||
+ (instancetype)shareGlobal {
|
||||
static QXGlobal *global = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
global = [[self alloc] init];
|
||||
global.isShowLoginVC = NO;
|
||||
});
|
||||
return global;
|
||||
}
|
||||
-(UIWindow *)getKeyWindow{
|
||||
AppDelegate*appDelegate = (AppDelegate*)[UIApplication sharedApplication].delegate;
|
||||
UIWindow *window = appDelegate.window;
|
||||
return window;
|
||||
}
|
||||
-(void)logOut{
|
||||
[TUILogin logout:^{
|
||||
QXLOG(@"腾讯im退出登录成功");
|
||||
} fail:^(int code, NSString * _Nullable msg) {
|
||||
QXLOG(@"腾讯im退出登录失败");
|
||||
}];
|
||||
self.isLogin = NO;
|
||||
[self removeLocalData];
|
||||
[self removeMemory];
|
||||
AppDelegate *appdelegate = (AppDelegate*)[UIApplication sharedApplication].delegate;
|
||||
/// 移除推送监听
|
||||
[TIMPushManager removePushListener:appdelegate];
|
||||
/// 移除会话监听
|
||||
[[V2TIMManager sharedInstance] removeConversationListener:appdelegate];
|
||||
[TIMPushManager unRegisterPush:^{
|
||||
//success
|
||||
} fail:^(int code, NSString * _Nonnull desc) {
|
||||
//error
|
||||
}];
|
||||
|
||||
if (self.isShowLoginVC == YES) {
|
||||
return;
|
||||
}
|
||||
QXLoginViewController *vc = [[QXLoginViewController alloc] init];
|
||||
QXBaseNavigationController *na = [[QXBaseNavigationController alloc] initWithRootViewController:vc];
|
||||
na.modalPresentationStyle = UIModalPresentationFullScreen;
|
||||
[self.getKeyWindow.rootViewController presentViewController:na animated:YES completion:nil];
|
||||
self.isShowLoginVC = YES;
|
||||
/// 断开mqtt连接
|
||||
[[QXManagerMqtt sharedInstance] disconnect];
|
||||
|
||||
}
|
||||
-(void)saveLoginData:(NSString *)userInfoJson{
|
||||
[[NSUserDefaults standardUserDefaults] setObject:userInfoJson forKey:kUserLoginData];
|
||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||
}
|
||||
-(void)updateUserInfoWithMolde:(QXLoginModel *)loginModel{
|
||||
NSString *jsonStr = [loginModel yy_modelToJSONString];
|
||||
[self saveLoginData:jsonStr];
|
||||
}
|
||||
//-(void)setLoginModel:(QXLoginModel *)loginModel{
|
||||
// _loginModel = loginModel;
|
||||
// if (loginModel == nil) {
|
||||
// self.isLogin = NO;
|
||||
// }else{
|
||||
// self.isLogin = YES;
|
||||
// }
|
||||
//}
|
||||
-(BOOL)isRealName{
|
||||
return [QXGlobal shareGlobal].loginModel.auth == 1;
|
||||
}
|
||||
-(QXLoginModel *)loginModel{
|
||||
if (!_loginModel) {
|
||||
NSString *jsonStr = [[NSUserDefaults standardUserDefaults] objectForKey:kUserLoginData];
|
||||
if (jsonStr.length > 0) {
|
||||
_loginModel = [QXLoginModel yy_modelWithJSON:jsonStr];
|
||||
self.isLogin = YES;
|
||||
}else{
|
||||
_loginModel = nil;
|
||||
self.isLogin = NO;
|
||||
}
|
||||
}
|
||||
return _loginModel;
|
||||
}
|
||||
-(void)toLogin{
|
||||
|
||||
}
|
||||
-(BOOL)isLogin{
|
||||
NSString *jsonStr = [[NSUserDefaults standardUserDefaults] objectForKey:kUserLoginData];
|
||||
return jsonStr.length > 0;
|
||||
}
|
||||
-(void)removeLocalData{
|
||||
[[NSUserDefaults standardUserDefaults] removeObjectForKey:kUserLoginData];
|
||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||
}
|
||||
-(void)removeMemory{
|
||||
QXGlobal.shareGlobal.loginModel = nil;
|
||||
}
|
||||
-(void)showView:(UIView *)view popType:(PopViewType)popType tapDismiss:(BOOL)tapDismiss finishBlock:(showFinishBlock)finishBlock{
|
||||
self.alertViewController = [[QXAlertViewController alloc] init];
|
||||
self.alertViewController.popType = popType;
|
||||
self.alertViewController.alertView = view;
|
||||
self.alertViewController.tapDismiss = tapDismiss;
|
||||
self.alertViewController.modalPresentationStyle = UIModalPresentationOverFullScreen;
|
||||
[[QXGlobal shareGlobal].getKeyWindow.rootViewController presentViewController:self.alertViewController animated:NO completion:finishBlock];
|
||||
}
|
||||
|
||||
-(void)showView:(UIView *)view controller:(UIViewController*)controller popType:(PopViewType)popType tapDismiss:(BOOL)tapDismiss finishBlock:(showFinishBlock)finishBlock{
|
||||
self.alertViewController = [[QXAlertViewController alloc] init];
|
||||
self.alertViewController.popType = popType;
|
||||
self.alertViewController.alertView = view;
|
||||
self.alertViewController.tapDismiss = tapDismiss;
|
||||
self.alertViewController.modalPresentationStyle = UIModalPresentationOverFullScreen;
|
||||
[controller presentViewController:self.alertViewController animated:NO completion:finishBlock];
|
||||
}
|
||||
-(void)hideViewBlock:(closeBlock)closeBlock{
|
||||
[self.alertViewController hideViewFinishBlock:closeBlock];
|
||||
}
|
||||
-(BOOL)isOpenRecharge{
|
||||
BOOL isOpenRecharge = [[NSUserDefaults standardUserDefaults] boolForKey:kIsOpenRecharge];
|
||||
return isOpenRecharge;
|
||||
}
|
||||
|
||||
-(void)finishTask{
|
||||
if (QXGlobal.shareGlobal.taskModel != nil) {
|
||||
[QXMineNetwork dayTaskFinishedWithTaskId:QXGlobal.shareGlobal.taskModel.task_id successBlock:^(NSDictionary * _Nonnull dict) {
|
||||
NSString *is_completed = [NSString stringWithFormat:@"%@",dict[@"is_completed"]];
|
||||
if (is_completed.intValue == 1) {
|
||||
QXGlobal.shareGlobal.taskModel = nil;
|
||||
QXGlobal.shareGlobal.taskTime = 0;
|
||||
if (self->_timer) {
|
||||
[self->_timer invalidate];
|
||||
self->_timer = nil;
|
||||
}
|
||||
}
|
||||
} failBlock:^(NSError * _Nonnull error, NSString * _Nonnull msg) {
|
||||
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
-(void)chatWithUserID:(NSString *)userId nickname:(NSString *)nickname avatar:(NSString *)avatar navagationController:(UINavigationController *)navagationController{
|
||||
QXChatViewController *vc = [[QXChatViewController alloc] init];
|
||||
TUIChatConversationModel *data = [[TUIChatConversationModel alloc] init];
|
||||
data.userID = [NSString stringWithFormat:@"u%@",userId];
|
||||
data.title = nickname;
|
||||
data.faceUrl = avatar;
|
||||
vc.data = data;
|
||||
[navagationController pushViewController:vc animated:YES];
|
||||
}
|
||||
|
||||
-(void)chatWithGroupId:(NSString *)groupId cover:(NSString *)cover name:(NSString *)name navagationController:(UINavigationController *)navagationController{
|
||||
QXChatViewController *vc = [[QXChatViewController alloc] init];
|
||||
TUIChatConversationModel *data = [[TUIChatConversationModel alloc] init];
|
||||
if ([groupId containsString:@"g"]) {
|
||||
data.groupID = groupId;
|
||||
}else{
|
||||
data.groupID = [NSString stringWithFormat:@"g%@",groupId];
|
||||
}
|
||||
data.faceUrl = cover;
|
||||
data.title = name;
|
||||
vc.data = data;
|
||||
[navagationController pushViewController:vc animated:YES];
|
||||
}
|
||||
|
||||
-(void)joinRoomWithRoomId:(NSString *)roomId isRejoin:(BOOL)isRejoin navagationController:(UINavigationController *)navagationController{
|
||||
if (!QXGlobal.shareGlobal.isLogin) {
|
||||
[[QXGlobal shareGlobal] logOut];
|
||||
return;
|
||||
}
|
||||
navagationController = (QXBaseNavigationController*)KEYWINDOW.rootViewController;
|
||||
navagationController.interactivePopGestureRecognizer.enabled = NO;
|
||||
if (_miniView) {
|
||||
[_miniView removeFromSuperview];
|
||||
_miniView = nil;
|
||||
}
|
||||
if ([roomId isEqualToString:self.roomId]) {
|
||||
if ([navagationController.viewControllers containsObject:self.roomVC]) {
|
||||
return;
|
||||
}else{
|
||||
self.roomVC.hidesBottomBarWhenPushed = YES;
|
||||
[navagationController pushViewController:self.roomVC animated:YES];
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (self.roomId && ![self.roomId isEqualToString:roomId]) {
|
||||
[self quitRoomWithRoomId:self.roomId];
|
||||
}
|
||||
if (isRejoin) {
|
||||
if (self.roomVC!=nil) {
|
||||
self.roomVC.hidesBottomBarWhenPushed = YES;
|
||||
[navagationController pushViewController:self.roomVC animated:YES];
|
||||
}else{
|
||||
self.roomVC = [[QXRoomViewController alloc] init];
|
||||
self.roomVC.roomId = roomId;
|
||||
self.roomVC.isReJoin = isRejoin;
|
||||
self.roomId = roomId;
|
||||
self.roomVC.hidesBottomBarWhenPushed = YES;
|
||||
[navagationController pushViewController:self.roomVC animated:YES];
|
||||
}
|
||||
}else{
|
||||
if ([roomId isEqualToString:self.roomVC.roomId]) {
|
||||
[navagationController pushViewController:self.roomVC animated:YES];
|
||||
}else{
|
||||
self.roomVC = [[QXRoomViewController alloc] init];
|
||||
self.roomVC.roomId = roomId;
|
||||
self.roomVC.isReJoin = isRejoin;
|
||||
self.roomId = roomId;
|
||||
self.roomVC.hidesBottomBarWhenPushed = YES;
|
||||
[navagationController pushViewController:self.roomVC animated:YES];
|
||||
}
|
||||
}
|
||||
if (QXGlobal.shareGlobal.taskModel != nil) {
|
||||
/// 是否带有每日任务
|
||||
if (QXGlobal.shareGlobal.taskModel.task_id.intValue == 9) {
|
||||
/// 是计时任务
|
||||
if (_timer == nil) {
|
||||
_timer = [QXTimer scheduledTimerWithTimeInterval:1 repeats:YES queue:dispatch_get_main_queue() block:^{
|
||||
QXGlobal.shareGlobal.taskTime++;
|
||||
if (QXGlobal.shareGlobal.taskTime%60 == 0) {
|
||||
[[QXGlobal shareGlobal] finishTask];
|
||||
}
|
||||
}];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
-(void)quitRoomWithRoomId:(NSString *)roomId{
|
||||
/// 移除特效
|
||||
[[QXGiftPlayerManager shareManager] destroyEffectSvga];
|
||||
/// 退出声网
|
||||
[[QXAgoraEngine sharedEngine] leaveChannel];
|
||||
|
||||
[[QXAgoraEngine sharedEngine] ktv_DestoryKtvPlayer];
|
||||
|
||||
[[QXAgoraEngine sharedEngine] destroyEngine];
|
||||
/// 退出直播群
|
||||
[[QXRoomMessageManager shared] quitGroupWithRoomId:roomId];
|
||||
self.roomId = nil;
|
||||
_roomVC = nil;
|
||||
/// 业务http退出
|
||||
[QXMineNetwork quitRoomWithRoomId:roomId user_id:[QXGlobal shareGlobal].loginModel.user_id successBlock:^(NSDictionary * _Nonnull dict) {
|
||||
|
||||
} failBlock:^(NSError * _Nonnull error, NSString * _Nonnull msg) {
|
||||
|
||||
}];
|
||||
|
||||
if (_timer) {
|
||||
[_timer invalidate];
|
||||
_timer = nil;
|
||||
}
|
||||
}
|
||||
-(void)miniRoomWithRoomId:(NSString*)roomId roomCover:(NSString*)roomCover{
|
||||
self.miniView.roomId = self.roomId;
|
||||
self.miniView.roomCoverImage = roomCover;
|
||||
[self.miniView show];
|
||||
}
|
||||
|
||||
-(QXMiniRoomView *)miniView{
|
||||
if (!_miniView) {
|
||||
_miniView = [[QXMiniRoomView alloc] init];
|
||||
}
|
||||
return _miniView;
|
||||
}
|
||||
|
||||
-(void)vibrationFeedback{
|
||||
UIImpactFeedbackGenerator *generator = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleHeavy];
|
||||
[generator impactOccurred];
|
||||
}
|
||||
@end
|
||||
38
QXLive/Base/QXLocationManager.h
Normal file
38
QXLive/Base/QXLocationManager.h
Normal file
@@ -0,0 +1,38 @@
|
||||
//
|
||||
// QXLocationManager.h
|
||||
// YSDTrucksProject
|
||||
//
|
||||
// Created by 党凯 on 2020/7/17.
|
||||
// Copyright © 2020 党凯. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@protocol QXLocationManagerDelegate <NSObject>
|
||||
|
||||
@optional
|
||||
-(void)locationSuccessWithCity:(NSString*_Nonnull)city province:(NSString*_Nonnull)province area:(NSString*_Nonnull)area address:(NSString*_Nonnull)address;
|
||||
|
||||
@end
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QXLocationManager : NSObject
|
||||
@property (nonatomic,weak)id<QXLocationManagerDelegate>delegate;
|
||||
|
||||
+(instancetype)shareManager;
|
||||
|
||||
/**
|
||||
开始定位
|
||||
*/
|
||||
-(void)startLoction;
|
||||
|
||||
|
||||
/**
|
||||
结束定位
|
||||
*/
|
||||
-(void)stopLoction;
|
||||
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
155
QXLive/Base/QXLocationManager.m
Normal file
155
QXLive/Base/QXLocationManager.m
Normal file
@@ -0,0 +1,155 @@
|
||||
//
|
||||
// QXLocationManager.m
|
||||
// YSDTrucksProject
|
||||
//
|
||||
// Created by 党凯 on 2020/7/17.
|
||||
// Copyright © 2020 党凯. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QXLocationManager.h"
|
||||
|
||||
|
||||
@interface QXLocationManager()<CLLocationManagerDelegate>
|
||||
@property (nonatomic,strong)CLLocationManager *lcManager;
|
||||
@end
|
||||
@implementation QXLocationManager
|
||||
+(instancetype)shareManager{
|
||||
static QXLocationManager *manager = nil;
|
||||
static dispatch_once_t predicate;
|
||||
dispatch_once(&predicate, ^{
|
||||
manager = [[QXLocationManager alloc] init];
|
||||
});
|
||||
return manager;
|
||||
}
|
||||
- (instancetype)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
// [AMapServices sharedServices].apiKey = mapKey;
|
||||
// _locationManager = [[AMapLocationManager alloc] init];
|
||||
// // 带逆地理信息的一次定位(返回坐标和地址信息)
|
||||
// [_locationManager setDesiredAccuracy:kCLLocationAccuracyHundredMeters];
|
||||
// // 定位超时时间,最低2s,此处设置为2s
|
||||
// _locationManager.locationTimeout =2;
|
||||
// // 逆地理请求超时时间,最低2s,此处设置为2s
|
||||
// _locationManager.reGeocodeTimeout = 2;
|
||||
// _locationManager.delegate = self;
|
||||
// if ([CLLocationManager authorizationStatus]) {
|
||||
|
||||
// 创建位置管理者对象
|
||||
|
||||
self.lcManager = [[CLLocationManager alloc] init];
|
||||
|
||||
self.lcManager.delegate = self; // 设置代理
|
||||
|
||||
// 设置定位距离过滤参数 (当本次定位和上次定位之间的距离大于或等于这个值时,调用代理方法)
|
||||
|
||||
self.lcManager.distanceFilter = 100;
|
||||
|
||||
self.lcManager.desiredAccuracy = kCLLocationAccuracyBest; // 设置定位精度(精度越高越耗电)
|
||||
|
||||
[self.lcManager requestWhenInUseAuthorization];//这句很关键!!!
|
||||
|
||||
// [self.lcManager startUpdatingLocation]; // 开始更新位置
|
||||
|
||||
// }else{
|
||||
//
|
||||
// //没开启,做其他提醒
|
||||
//
|
||||
// }
|
||||
}
|
||||
return self;
|
||||
}
|
||||
//-(void)amapLocationManager:(AMapLocationManager *)manager doRequireLocationAuth:(CLLocationManager *)locationManager{
|
||||
// if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined) {
|
||||
// [locationManager requestAlwaysAuthorization];
|
||||
// }
|
||||
//}
|
||||
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
|
||||
NSLog(@"定位到了");
|
||||
|
||||
__weak typeof(self)weakSelf = self;
|
||||
CLGeocoder *geocoder = [[CLGeocoder alloc]init];
|
||||
[geocoder reverseGeocodeLocation:[locations firstObject] completionHandler:^(NSArray<CLPlacemark *> *_Nullable placemarks, NSError * _Nullable error) {
|
||||
|
||||
CLPlacemark *place = [placemarks firstObject];
|
||||
//place包含了地理信息
|
||||
if (weakSelf.delegate && [weakSelf.delegate respondsToSelector:@selector(locationSuccessWithCity:province:area:address:)]) {
|
||||
/// 省
|
||||
NSString *province = place.administrativeArea;
|
||||
/// 市
|
||||
NSString *city = place.locality;
|
||||
/// 县
|
||||
NSString *area = place.subLocality;
|
||||
[weakSelf.delegate locationSuccessWithCity:place.locality province:province area:area address:place.name];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error{
|
||||
NSLog(@"获取定位失败");
|
||||
}
|
||||
|
||||
-(void)startLoction{
|
||||
if (![self checkAuthorization]) {
|
||||
UIAlertController *al = [UIAlertController alertControllerWithTitle:@"您没有打开定位权限" message:nil preferredStyle:(UIAlertControllerStyleAlert)];
|
||||
[al addAction:[UIAlertAction actionWithTitle:@"取消" style:(UIAlertActionStyleCancel) handler:^(UIAlertAction * _Nonnull action) {
|
||||
|
||||
}]];
|
||||
[al addAction:[UIAlertAction actionWithTitle:@"去设置" style:(UIAlertActionStyleDefault) handler:^(UIAlertAction * _Nonnull action) {
|
||||
//打开应用的设置界面
|
||||
NSURL * url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
|
||||
if([[UIApplication sharedApplication] canOpenURL:url]) {
|
||||
[[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil];
|
||||
}
|
||||
}]];
|
||||
[KEYWINDOW.rootViewController presentViewController:al animated:YES completion:nil];
|
||||
// [self.locationManager requestLocationWithReGeocode:YES completionBlock:^(CLLocation *location, AMapLocationReGeocode *regeocode, NSError *error) {
|
||||
// resultBlock(location,regeocode,error);
|
||||
// }];
|
||||
[self.lcManager startUpdatingLocation];
|
||||
}else{
|
||||
// [self.locationManager requestLocationWithReGeocode:YES completionBlock:^(CLLocation *location, AMapLocationReGeocode *regeocode, NSError *error) {
|
||||
// resultBlock(location,regeocode,error);
|
||||
// }];
|
||||
[self.lcManager startUpdatingLocation];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
-(void)stopLoction{
|
||||
[self.lcManager stopUpdatingLocation];
|
||||
}
|
||||
//检查定位权限
|
||||
-(BOOL)checkAuthorization{
|
||||
BOOL result = NO;
|
||||
CLAuthorizationStatus status = [CLLocationManager authorizationStatus];
|
||||
switch (status) {
|
||||
//用户在设置中关闭定位功能,或者用户明确的在弹框之后选择禁止定位
|
||||
case kCLAuthorizationStatusDenied:
|
||||
result = NO;
|
||||
break;
|
||||
//用户没有选择是否要使用定位服务(弹框没选择,或者根本没有弹框)注:高德会自动请求权限
|
||||
case kCLAuthorizationStatusNotDetermined:
|
||||
result = YES;
|
||||
break;
|
||||
//定位服务授权状态受限制,可能由于活动限制了定位服务,并且用户不能改变当前的权限,这个状态有可能不是用户拒绝的,但是也有可能是用户拒绝的。
|
||||
case kCLAuthorizationStatusRestricted:
|
||||
result = NO;
|
||||
break;
|
||||
//App始终允许使用定位功能
|
||||
case kCLAuthorizationStatusAuthorizedAlways:
|
||||
result = YES;
|
||||
break;
|
||||
//用户在使用期间允许使用定位功能
|
||||
case kCLAuthorizationStatusAuthorizedWhenInUse:
|
||||
result = YES;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@end
|
||||
17
QXLive/Base/WKWebView+QX.h
Normal file
17
QXLive/Base/WKWebView+QX.h
Normal file
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// WKWebView+QX.h
|
||||
// YBLive
|
||||
//
|
||||
// Created by 启星 on 2025/4/16.
|
||||
// Copyright © 2025 cat. All rights reserved.
|
||||
//
|
||||
|
||||
#import <WebKit/WebKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface WKWebView (QX)
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
50
QXLive/Base/WKWebView+QX.m
Normal file
50
QXLive/Base/WKWebView+QX.m
Normal file
@@ -0,0 +1,50 @@
|
||||
//
|
||||
// WKWebView+QX.m
|
||||
// YBLive
|
||||
//
|
||||
// Created by 启星 on 2025/4/16.
|
||||
// Copyright © 2025 cat. All rights reserved.
|
||||
//
|
||||
|
||||
#import "WKWebView+QX.h"
|
||||
|
||||
@implementation WKWebView (QX)
|
||||
+ (void)load{
|
||||
Method method1 = class_getInstanceMethod([self class],@selector(loadRequest:));
|
||||
Method method2 = class_getInstanceMethod([self class],@selector(qx_loadRequest:));
|
||||
method_exchangeImplementations(method1, method2);
|
||||
|
||||
}
|
||||
-(void)qx_loadRequest:(NSURLRequest*)request{
|
||||
if ([self isProxyEnabled]) {
|
||||
[self qx_loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https:www.baidu.com"]]];
|
||||
}else{
|
||||
[self qx_loadRequest:request];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
-(BOOL)isProxyEnabled{
|
||||
NSArray *criticalDomains = @[
|
||||
H5ServerUrl,
|
||||
ServerUrl,
|
||||
];
|
||||
NSDictionary *proxySettings = (__bridge NSDictionary *)CFNetworkCopySystemProxySettings();
|
||||
for (NSString *domain in criticalDomains) {
|
||||
NSArray *proxies = (__bridge NSArray *)CFNetworkCopyProxiesForURL(
|
||||
(__bridge CFURLRef)[NSURL URLWithString:domain],
|
||||
(__bridge CFDictionaryRef)proxySettings
|
||||
);
|
||||
// 检查每个域名的代理情况...
|
||||
for (NSDictionary *proxy in proxies) {
|
||||
NSString *proxyType = proxy[(NSString *)kCFProxyTypeKey];
|
||||
if (![proxyType isEqualToString:(NSString *)kCFProxyTypeNone]) {
|
||||
return YES; // 存在代理或 VPN
|
||||
}
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
@end
|
||||
195
QXLive/Config/QXAgoraEngine.h
Executable file
195
QXLive/Config/QXAgoraEngine.h
Executable file
@@ -0,0 +1,195 @@
|
||||
//
|
||||
// LNAgoraEngine.h
|
||||
// SoundRiver
|
||||
//
|
||||
// Created by ln007 on 2019/8/29.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "QXSongListModel.h"
|
||||
#import <AgoraRtcKit/AgoraMusicContentCenter.h>
|
||||
#import <AgoraRtcKit/AgoraRtcEngineKit.h>
|
||||
#import <AgoraRtcKit/AgoraRtcEngineKitEx.h>
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
typedef NS_ENUM(NSInteger,PlayMusicTyper) {
|
||||
MusicSingle,
|
||||
MUsicRandomPlay,
|
||||
MusicListPlay
|
||||
};
|
||||
|
||||
typedef void(^SearchSongBlock)(NSArray<AgoraMusic *> *songList,BOOL isReload);
|
||||
@protocol QXAgoraEngineMediaPlayerDelegate <NSObject>
|
||||
/// 声浪回调
|
||||
- (void)onRTCEngineRoomPublishSoundLevelUpdate:(NSArray<AgoraRtcAudioVolumeInfo *> *)soundLevels;
|
||||
/// 播放器播放结束回调
|
||||
- (void)rtcEngineLocalAudioMixingDidFinish;
|
||||
/// 歌词回调
|
||||
- (void)rtcEngineSongLrc:(NSString*)lrcUrl;
|
||||
/// 歌曲进度回调
|
||||
- (void)rtcEngineSongProgress:(NSUInteger)progress;
|
||||
/// 背景音乐 下一首回调
|
||||
- (void)rtcEngineBackgroundMusicNextSong:(QXSongListModel*)songModel;
|
||||
/// 小黑屋电影首次加载
|
||||
- (void)rtcEngineVideoFirstLoadWithUid:(NSInteger)uid size:(CGSize)size;
|
||||
/// 小黑屋电影结束
|
||||
- (void)rtcEngineVideoDidStop:(NSInteger)uid;
|
||||
/// 开始
|
||||
- (void)rtcEngineVideoDidStart:(NSInteger)uid;
|
||||
@end
|
||||
|
||||
@interface QXAgoraEngine : NSObject
|
||||
@property (nonatomic , strong) AgoraRtcEngineKit *agoraKit;
|
||||
|
||||
@property (nonatomic,weak) id<QXAgoraEngineMediaPlayerDelegate>delegate;
|
||||
|
||||
@property (nonatomic , strong, nullable) UIViewController *chatRoom;
|
||||
|
||||
|
||||
|
||||
@property (nonatomic,copy)SearchSongBlock searchSongBlock;
|
||||
|
||||
@property (nonatomic , strong,readonly)QXSongListModel *songModel;
|
||||
|
||||
/// 存储已点歌曲
|
||||
@property (nonatomic , strong,readonly)NSMutableArray *bgMusicArray;
|
||||
/// 是否为播放背景音乐状态
|
||||
@property (nonatomic , assign)BOOL isPlayBgMusic;
|
||||
|
||||
// 循环/单曲/随机播放
|
||||
@property (nonatomic,assign)PlayMusicTyper playType;
|
||||
|
||||
@property (nonatomic , strong) AgoraMusicContentCenter *ktvAmcc;
|
||||
@property (nonatomic, strong) id<AgoraMusicPlayerProtocol> ktvPlayer;
|
||||
@property(nonatomic, assign) NSInteger playPosition;//播放进度
|
||||
@property(nonatomic, assign) BOOL isErfan;
|
||||
@property(nonatomic, assign) NSInteger renshengVolume;//采集音量,取值范围为 [0,400],默认100
|
||||
@property(nonatomic, assign) BOOL useMicrophone;
|
||||
|
||||
/// 当前是否为开麦状态
|
||||
@property(nonatomic, assign,readonly) BOOL isOpenMic;
|
||||
|
||||
|
||||
+ (instancetype)sharedEngine;
|
||||
|
||||
//加入频道
|
||||
- (void)joinChannel:(NSString *)channelId withRoom:(UIViewController *)chatRoom agora_token:(NSString*)agora_token agora_rtm_token:(NSString*)agora_rtm_token isUpSeat:(BOOL)isUpSeat successBock:(void(^)(void))successBock;
|
||||
|
||||
//切换频道
|
||||
- (void)switchToChannel:(NSString *)channelId withRoom:(UIViewController *)chatRoom agora_token:(NSString*)agora_token agora_rtm_token:(NSString*)agora_rtm_token isUpSeat:(BOOL)isUpSeat successBock:(void(^)(void))successBock;
|
||||
|
||||
// 点唱初始化
|
||||
- (void)onInitKTVCenterWithToken:(NSString*)token;
|
||||
|
||||
//离开频道
|
||||
-(void)leaveChannel;
|
||||
|
||||
/// 销毁
|
||||
- (void)destroyEngine;
|
||||
|
||||
//切换用户角色
|
||||
/*
|
||||
该方法在加入频道前后都可以调用:
|
||||
|
||||
加入直播频道前,调用该方法将用户设置为主播或观众。
|
||||
直播过程中,调用该方法将用户角色由观众切换为主播(上麦),或由主播切换为观众。
|
||||
*/
|
||||
- (void)setClientRoleBroadcaster:(BOOL)isBroadcaster;
|
||||
|
||||
//禁麦 不发送本地录音
|
||||
- (void)muteLocalAudioStream:(BOOL)mute;
|
||||
|
||||
/// 禁用音频
|
||||
- (void)enableAudio:(BOOL)enble;
|
||||
|
||||
//切换耳机和扬声器
|
||||
- (int)setEnableSpeakerphone:(BOOL)enableSpeaker;
|
||||
|
||||
//是否为扬声器
|
||||
- (BOOL)isSpeakerphoneEnabled;
|
||||
|
||||
//屏蔽远端声音
|
||||
- (int)muteAllRemoteAudioStreams:(BOOL)mute;
|
||||
|
||||
//设置混音效果
|
||||
- (int)startAudioMixing:(NSString * _Nonnull)filePath
|
||||
loopback:(BOOL)loopback
|
||||
replace:(BOOL)replace
|
||||
cycle:(NSInteger)cycle;
|
||||
- (int)paseAudioMixing;
|
||||
- (int)adjustAudioMixingVolume:(NSInteger)volume;
|
||||
|
||||
- (int)resumeAudioMixing;
|
||||
|
||||
- (double)getEffectsVolume;
|
||||
|
||||
- (int)stopAudioMixing;
|
||||
|
||||
|
||||
- (void)RequestMusicURLData:(NSString *)MusicID;
|
||||
|
||||
/// 添加背景音乐
|
||||
- (void)addBgMusic:(QXSongListModel *)music;
|
||||
/// 下一首
|
||||
- (void)nextBgMusic;
|
||||
/// 暂停
|
||||
- (void)pausePlayMusic;
|
||||
/// 重新开始
|
||||
- (void)resumePlayMusic;
|
||||
|
||||
|
||||
|
||||
/// 点歌房 //原唱0 伴奏1
|
||||
-(void)ktv_OriginalSingSetting:(BOOL)isOriginal;
|
||||
/// 销毁播放器
|
||||
- (void)ktv_DestoryKtvPlayer;
|
||||
/// 获取耳返状态
|
||||
-(BOOL)ktv_GetErfan;
|
||||
// 设置耳返
|
||||
-(void)ktv_SetErfan:(BOOL)isErfan;
|
||||
/// 开始播放
|
||||
-(void)ktv_StartSing:(BOOL)isStart withSong:(QXSongListModel*)songModel;
|
||||
/// 结束播放
|
||||
-(void)ktv_EndSing;
|
||||
/// 去加载歌词
|
||||
-(void)ktv_LoadLrcWithSong:(QXSongListModel*)songModel;
|
||||
/// 设置人声
|
||||
-(void)ktv_SetRenshengVolume:(float)ratio;
|
||||
/// 设置伴奏
|
||||
-(void)ktv_SetBanzouVolume:(float)ratio;
|
||||
/// 获取伴奏声音
|
||||
-(float)ktv_GetBanzouVolume;
|
||||
/// 搜索歌曲
|
||||
-(void)searchSongWithKeyword:(NSString *)keywords page:(NSInteger)page resultBlock:(SearchSongBlock)resultBlock;
|
||||
|
||||
//设置原声
|
||||
- (void)setLocalVoiceReverbOrginal;
|
||||
|
||||
//设置大叔
|
||||
- (void)setLocationVoiceChangerIsOldMan;
|
||||
|
||||
//设置正太
|
||||
- (void)setLocationVoiceChangerIsSmallMan;
|
||||
//设置萝莉
|
||||
- (void)setLocationVoiceChangerIsSmallGril;
|
||||
|
||||
//设置空灵
|
||||
- (void)setLocationVoiceChangerIsEmptiness;
|
||||
//设置演唱会
|
||||
|
||||
- (void)setLocalVoiceReverbSongSinger;
|
||||
//设置KTV
|
||||
- (void)setLocalVoiceReverbKTV;
|
||||
//设置录音棚
|
||||
- (void)setLocalVoiceReverbRecordingStudio;
|
||||
//播放音效
|
||||
@property (nonatomic, assign)NSInteger CurrentVoiceStyle;
|
||||
|
||||
|
||||
|
||||
-(void)startScreenCapture;
|
||||
|
||||
-(void)startPreViewWithUid:(NSInteger)uid view:(UIView*)view;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
845
QXLive/Config/QXAgoraEngine.m
Executable file
845
QXLive/Config/QXAgoraEngine.m
Executable file
@@ -0,0 +1,845 @@
|
||||
//
|
||||
// LNAgoraEngine.m
|
||||
// SoundRiver
|
||||
//
|
||||
// Created by ln007 on 2019/8/29.
|
||||
//
|
||||
|
||||
#import "QXAgoraEngine.h"
|
||||
|
||||
|
||||
#import "QXRoomMessageManager.h"
|
||||
#import "QXAgoraEngineEx.h"
|
||||
#import <ReplayKit/ReplayKit.h>
|
||||
|
||||
@interface QXAgoraEngine ()<AgoraRtcEngineDelegate,AgoraMusicContentCenterEventDelegate,AgoraRtcMediaPlayerDelegate>
|
||||
|
||||
|
||||
|
||||
@property (nonatomic , strong) NSString *currentChannel;
|
||||
@property (nonatomic , assign) NSUInteger currentUid;
|
||||
|
||||
|
||||
@property (nonatomic , assign) NSInteger page;
|
||||
|
||||
@property (nonatomic , strong) QXSongListModel* songModel;
|
||||
|
||||
@property (nonatomic , strong)NSMutableArray *bgMusicArray;
|
||||
|
||||
|
||||
@property (nonatomic , strong)AgoraScreenCaptureParameters2 *screenParams;
|
||||
@property (nonatomic , strong)RPSystemBroadcastPickerView *systemBroadcastPicker;
|
||||
@property (nonatomic , strong)AgoraRtcChannelMediaOptions *option;
|
||||
@property (nonatomic , assign) BOOL isOpenMic;
|
||||
@end
|
||||
|
||||
@implementation QXAgoraEngine
|
||||
|
||||
|
||||
+(instancetype)sharedEngine {
|
||||
static dispatch_once_t onceToken;
|
||||
static QXAgoraEngine *instance;
|
||||
dispatch_once(&onceToken, ^{
|
||||
instance = [[QXAgoraEngine alloc] init];
|
||||
});
|
||||
if (!instance.agoraKit) {
|
||||
[instance initializeAgoraEngine];
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
||||
//初始化
|
||||
- (void)initializeAgoraEngine {
|
||||
self.agoraKit = [AgoraRtcEngineKit sharedEngineWithAppId:AgoraAuthId delegate:self];
|
||||
[self.agoraKit enableAudioVolumeIndication:200 smooth:3 reportVad:NO];
|
||||
|
||||
[self.agoraKit setAudioProfile:AgoraAudioProfileMusicHighQualityStereo];
|
||||
[self.agoraKit setAudioScenario:AgoraAudioScenarioChorus];
|
||||
|
||||
[self setChannelProfile];
|
||||
self.agoraKit.delegate = self;
|
||||
[self.agoraKit setParameters:@"{\"che.audio.custom_payload_type\":73}"];
|
||||
[self.agoraKit setParameters:@"{\"che.audio.custom_bitrate\":128000}"];
|
||||
[self.agoraKit setParameters:@"{\"rtc.enable_nasa2\": true}"];
|
||||
[self.agoraKit setParameters:@"{\"rtc.use_audio4\": true}" ];
|
||||
[self.agoraKit enableVideo];
|
||||
[self.agoraKit enableAudio];
|
||||
AgoraVideoEncoderConfiguration *encoderConfig = [[AgoraVideoEncoderConfiguration alloc] initWithSize:CGSizeMake(960, 540)
|
||||
frameRate:(AgoraVideoFrameRateFps15)
|
||||
bitrate:AgoraVideoBitrateStandard
|
||||
orientationMode:(AgoraVideoOutputOrientationModeFixedPortrait)
|
||||
mirrorMode:(AgoraVideoMirrorModeAuto)];
|
||||
[self.agoraKit setVideoEncoderConfiguration:encoderConfig];
|
||||
|
||||
}
|
||||
-(void)rtcEngine:(AgoraRtcEngineKit *)engine didOccurError:(AgoraErrorCode)errorCode{
|
||||
|
||||
}
|
||||
//设置频道模式为直播
|
||||
- (void)setChannelProfile {
|
||||
[self.agoraKit setChannelProfile:AgoraChannelProfileLiveBroadcasting];
|
||||
}
|
||||
|
||||
//加入直播频道
|
||||
- (void)joinChannel:(NSString *)channelId withRoom:(UIViewController *)chatRoom agora_token:(NSString*)agora_token agora_rtm_token:(NSString*)agora_rtm_token isUpSeat:(BOOL)isUpSeat successBock:(nonnull void (^)(void))successBock{
|
||||
if (isUpSeat) {
|
||||
self.option.clientRoleType = AgoraClientRoleBroadcaster;
|
||||
}else{
|
||||
self.option.clientRoleType = AgoraClientRoleAudience;
|
||||
}
|
||||
if (_currentChannel.length > 0) {
|
||||
if (![_currentChannel isEqualToString:channelId]) {
|
||||
[self switchToChannel:channelId withRoom:chatRoom agora_token:agora_token agora_rtm_token:agora_rtm_token isUpSeat:isUpSeat successBock:successBock];
|
||||
}
|
||||
}else{
|
||||
__weak typeof(self)weakSelf = self;
|
||||
[self.agoraKit joinChannelByToken:agora_token channelId:channelId uid:QXGlobal.shareGlobal.loginModel.user_id.longLongValue mediaOptions:self.option joinSuccess:^(NSString * _Nonnull channel, NSUInteger uid, NSInteger elapsed) {
|
||||
[weakSelf onInitKTVCenterWithToken:agora_rtm_token];
|
||||
[weakSelf muteLocalAudioStream:YES];
|
||||
[weakSelf muteAllRemoteAudioStreams:NO];
|
||||
self.option.publishMicrophoneTrack = YES;
|
||||
self.option.publishMediaPlayerAudioTrack = YES;
|
||||
self.option.enableAudioRecordingOrPlayout = YES;
|
||||
self.option.publishMediaPlayerId = [self->_ktvPlayer getMediaPlayerId];
|
||||
[self.agoraKit updateChannelWithMediaOptions:self.option];
|
||||
// 当远端用户加入频道后,显示指定 uid 的远端视频流
|
||||
|
||||
if (successBock) {
|
||||
successBock();
|
||||
}
|
||||
}];
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//- (void)joinExChannel:(NSString *)channelId withRoom:(UIViewController *)chatRoom agora_token:(NSString*)agora_token agora_rtm_token:(NSString*)agora_rtm_token successBock:(void(^)(void))successBock{
|
||||
// [self.agoraKit joinChannelExByToken:<#(NSString * _Nullable)#> channelId:<#(NSString * _Nonnull)#> userAccount:<#(NSString * _Nonnull)#> delegate:<#(id<AgoraRtcEngineDelegate> _Nullable)#> mediaOptions:<#(AgoraRtcChannelMediaOptions * _Nonnull)#> joinSuccess:<#^(NSString * _Nonnull channel, NSUInteger uid, NSInteger elapsed)joinSuccessBlock#>]
|
||||
//}
|
||||
//切换用户角色
|
||||
/*
|
||||
该方法在加入频道前后都可以调用:
|
||||
|
||||
加入直播频道前,调用该方法将用户设置为主播或观众。
|
||||
直播过程中,调用该方法将用户角色由观众切换为主播(上麦),或由主播切换为观众。
|
||||
*/
|
||||
- (void)setClientRoleBroadcaster:(BOOL)isBroadcaster {
|
||||
[self.agoraKit setClientRole:isBroadcaster ? AgoraClientRoleBroadcaster : AgoraClientRoleAudience];
|
||||
}
|
||||
|
||||
|
||||
- (void)rtcEngine:(AgoraRtcEngineKit * _Nonnull)engine tokenPrivilegeWillExpire:(NSString *_Nonnull)token{
|
||||
// [self.agoraKit renewToken:<#(NSString * _Nonnull)#>]
|
||||
}
|
||||
|
||||
//离开频道
|
||||
-(void)leaveChannel {
|
||||
[self.agoraKit leaveChannel:^(AgoraChannelStats * _Nonnull stat) {
|
||||
|
||||
}];
|
||||
//需要退出聊天室
|
||||
self.chatRoom = nil;
|
||||
self.currentChannel = nil;
|
||||
}
|
||||
|
||||
//切换频道
|
||||
- (void)switchToChannel:(NSString *)channelId withRoom:(UIViewController *)chatRoom agora_token:(NSString *)agora_token agora_rtm_token:(NSString *)agora_rtm_token isUpSeat:(BOOL)isUpSeat successBock:(void (^)(void))successBock{
|
||||
__weak typeof(self)weakSelf = self;
|
||||
[self.agoraKit leaveChannel:^(AgoraChannelStats * _Nonnull stat) {
|
||||
[self.agoraKit joinChannelByToken:agora_token channelId:channelId uid:QXGlobal.shareGlobal.loginModel.user_id.longLongValue mediaOptions:self.option joinSuccess:^(NSString * _Nonnull channel, NSUInteger uid, NSInteger elapsed) {
|
||||
[weakSelf onInitKTVCenterWithToken:agora_rtm_token];
|
||||
[weakSelf muteLocalAudioStream:YES];
|
||||
[weakSelf muteAllRemoteAudioStreams:NO];
|
||||
AgoraRtcChannelMediaOptions *option = [AgoraRtcChannelMediaOptions new];
|
||||
option.publishMicrophoneTrack = YES;
|
||||
option.publishMediaPlayerAudioTrack = YES;
|
||||
option.enableAudioRecordingOrPlayout = YES;
|
||||
option.publishMediaPlayerId = [self->_ktvPlayer getMediaPlayerId];
|
||||
[self.agoraKit updateChannelWithMediaOptions:option];
|
||||
if (successBock) {
|
||||
successBock();
|
||||
}
|
||||
}];
|
||||
}];
|
||||
}
|
||||
|
||||
//销毁
|
||||
- (void)destroyEngine
|
||||
{
|
||||
if (!self.agoraKit) {
|
||||
return;
|
||||
}
|
||||
[AgoraRtcEngineKit destroy];
|
||||
self.agoraKit = nil;
|
||||
[self.ktvAmcc destroyMusicPlayer:_ktvPlayer];
|
||||
_ktvPlayer = nil;
|
||||
[self.ktvAmcc registerEventDelegate:nil];
|
||||
self.ktvAmcc = nil;
|
||||
self.isOpenMic = NO;
|
||||
}
|
||||
|
||||
//禁麦
|
||||
- (void)muteLocalAudioStream:(BOOL)mute
|
||||
{
|
||||
// [self.agoraKit enableLocalAudio:!mute];
|
||||
// if ([self.songModel.user_id isEqualToString:QXGlobal.shareGlobal.loginModel.user_id]) {
|
||||
// /// 当前唱歌者为自己时 只是停止声音监听
|
||||
// [self.agoraKit muteRecordingSignal:mute];
|
||||
// }else{
|
||||
// [self.agoraKit muteRecordingSignal:mute];
|
||||
// [self.agoraKit muteLocalAudioStream:mute];
|
||||
// }
|
||||
|
||||
int result = [self.agoraKit muteLocalAudioStream:mute];
|
||||
QXLOG(@"音频模块禁麦---%d",result);
|
||||
// [self setClientRoleBroadcaster:!mute];
|
||||
|
||||
// [self.agoraKit muteRecordingSignal:mute];
|
||||
}
|
||||
-(void)enableAudio:(BOOL)enble{
|
||||
self.isOpenMic = enble;
|
||||
int result = [self.agoraKit enableLocalAudio:enble];
|
||||
QXLOG(@"音频模块启动---%d",result);
|
||||
}
|
||||
//切换为耳机播放
|
||||
- (int)setEnableSpeakerphone:(BOOL)enableSpeaker
|
||||
{
|
||||
return [self.agoraKit setEnableSpeakerphone:enableSpeaker];
|
||||
}
|
||||
|
||||
- (BOOL)isSpeakerphoneEnabled
|
||||
{
|
||||
return [self.agoraKit isSpeakerphoneEnabled];
|
||||
}
|
||||
|
||||
- (int)muteAllRemoteAudioStreams:(BOOL)mute
|
||||
{
|
||||
return [self.agoraKit muteAllRemoteAudioStreams:mute];
|
||||
}
|
||||
|
||||
- (int)startAudioMixing:(NSString * _Nonnull)filePath
|
||||
loopback:(BOOL)loopback
|
||||
replace:(BOOL)replace
|
||||
cycle:(NSInteger)cycle
|
||||
{
|
||||
// self.isPlay = YES;
|
||||
return [self.agoraKit startAudioMixing:filePath loopback:loopback cycle:cycle startPos:0];
|
||||
}
|
||||
- (int)paseAudioMixing{
|
||||
|
||||
|
||||
// self.isPlay = NO;
|
||||
|
||||
return [self.agoraKit pauseAudioMixing];
|
||||
}
|
||||
|
||||
- (int)stopAudioMixing{
|
||||
|
||||
// self.isPlay = NO;
|
||||
|
||||
return [self.agoraKit stopAudioMixing];
|
||||
}
|
||||
- (int)resumeAudioMixing{
|
||||
// self.isPlay = YES;
|
||||
return [self.agoraKit resumeAudioMixing];
|
||||
|
||||
}
|
||||
|
||||
|
||||
- (int)adjustAudioMixingVolume:(NSInteger)volume{
|
||||
return [self.agoraKit adjustAudioMixingVolume:volume];
|
||||
|
||||
}
|
||||
- (double)getEffectsVolume{
|
||||
return [self.agoraKit getEffectsVolume];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark-用户信息管理
|
||||
- (void)registerLocalUserAccount
|
||||
{
|
||||
[self.agoraKit registerLocalUserAccount:@"" appId:AgoraAuthId];
|
||||
}
|
||||
|
||||
- (void)RequestMusicURLData:(NSString *)MusicID{
|
||||
// LNNetworkAPI *api = [[LNNetworkAPI alloc] initWithUrl:@"api/Song/index" parameters:@{@"input":MusicID,@"filter":@"name",@"type":@"netease",@"page":@"1"}];
|
||||
// [api startRequestWithCompletionBlockWithSuccess:^(__kindof YTKBaseRequest * _Nonnull request, NSDictionary * _Nonnull result) {
|
||||
// if ([result[@"status"] integerValue] == 1) {
|
||||
//
|
||||
// NSArray *DataDic = result[@"data"];
|
||||
// NSDictionary *dic = DataDic[0];
|
||||
//
|
||||
// NSString * filePath = [dic objectForKey:@"url"];
|
||||
//
|
||||
// BOOL loopback = NO;
|
||||
// BOOL replace = NO;
|
||||
// NSInteger cycle = 1;
|
||||
//
|
||||
//
|
||||
// // 开始播放混音
|
||||
// [self.agoraKit startAudioMixing: filePath loopback: loopback replace: replace cycle: cycle];
|
||||
//
|
||||
// }else{
|
||||
// [SRToastTool showTips:result[@"info"]];
|
||||
// }
|
||||
// } failure:^(__kindof YTKBaseRequest * _Nonnull request, NSString * _Nonnull errorInfo) {
|
||||
// [SRToastTool showError:errorInfo];
|
||||
// }];
|
||||
}
|
||||
|
||||
|
||||
|
||||
#pragma mark-Enginedelegate
|
||||
- (void)rtcEngine:(AgoraRtcEngineKit *)engine didLeaveChannelWithStats:(AgoraChannelStats *)stats
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
-(void)rtcEngine:(AgoraRtcEngineKit *)engine localAudioStateChanged:(AgoraAudioLocalState)state reason:(AgoraAudioLocalReason)reason{
|
||||
QXLOG(@"%lu",(unsigned long)state);
|
||||
}
|
||||
|
||||
- (void)rtcEngine:(AgoraRtcEngineKit *)engine audioMixingStateChanged:(AgoraAudioMixingStateType)state reasonCode:(AgoraAudioMixingReasonCode)reasonCode{
|
||||
QXLOG(@"音乐播放状态改变%lu",(long)state);
|
||||
switch (state) {
|
||||
case AgoraAudioMixingStateTypePlaying:
|
||||
{
|
||||
|
||||
}
|
||||
break;
|
||||
case AgoraAudioMixingStateTypePaused:
|
||||
{
|
||||
|
||||
}
|
||||
break;
|
||||
case AgoraAudioMixingStateTypeStopped:
|
||||
{
|
||||
// if (self.delegate && [self.delegate respondsToSelector:@selector(rtcEngineLocalAudioMixingDidFinish)]) {
|
||||
// [self.delegate rtcEngineLocalAudioMixingDidFinish];
|
||||
// return;
|
||||
// }
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
-(void)rtcEngine:(AgoraRtcEngineKit *)engine didOfflineOfUid:(NSUInteger)uid reason:(AgoraUserOfflineReason)reason{
|
||||
NSDictionary *parm = @{
|
||||
@"user_id":[NSNumber numberWithInteger:uid],
|
||||
@"is_online":[NSNumber numberWithBool:NO],
|
||||
};
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:noticeRoomUserOnlineStatusDidChanged object:parm];
|
||||
}
|
||||
|
||||
-(void)rtcEngine:(AgoraRtcEngineKit *)engine didJoinedOfUid:(NSUInteger)uid elapsed:(NSInteger)elapsed{
|
||||
NSDictionary *parm = @{
|
||||
@"user_id":[NSNumber numberWithInteger:uid],
|
||||
@"is_online":[NSNumber numberWithBool:YES],
|
||||
};
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:noticeRoomUserOnlineStatusDidChanged object:parm];
|
||||
}
|
||||
/// 说话声音大小
|
||||
-(void)rtcEngine:(AgoraRtcEngineKit *)engine reportAudioVolumeIndicationOfSpeakers:(NSArray<AgoraRtcAudioVolumeInfo *> *)speakers totalVolume:(NSInteger)totalVolume{
|
||||
// NSMutableDictionary *usersSoundLevels = [NSMutableDictionary dictionary];
|
||||
// for (AgoraRtcAudioVolumeInfo *info in speakers) {
|
||||
// if (info.uid == 0) {
|
||||
// [usersSoundLevels setValue:@(info.volume) forKey:QXGlobal.shareGlobal.loginModel.user_id];
|
||||
// }else{
|
||||
// [usersSoundLevels setValue:@(info.volume) forKey:[NSString stringWithFormat:@"%lu",info.uid]];
|
||||
// }
|
||||
// }
|
||||
// if (self.delegate && [self.delegate respondsToSelector:@selector(onRTCEngineRoomPublishSoundLevelUpdate:)]) {
|
||||
// [self.delegate onRTCEngineRoomPublishSoundLevelUpdate:speakers];
|
||||
// }
|
||||
for (AgoraRtcAudioVolumeInfo *info in speakers) {
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:noticeUserSpeak object:info];
|
||||
}
|
||||
}
|
||||
-(void)rtcEngine:(AgoraRtcEngineKit *)engine remoteVideoStats:(AgoraRtcRemoteVideoStats *)stats{
|
||||
NSLog(@"uid=%ld直播远端视频状态",stats.uid);
|
||||
}
|
||||
-(void)rtcEngine:(AgoraRtcEngineKit *)engine firstRemoteVideoFrameOfUid:(NSUInteger)uid size:(CGSize)size elapsed:(NSInteger)elapsed{
|
||||
NSLog(@"uid=%ld直播远端视频首次加载",uid);
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(rtcEngineVideoFirstLoadWithUid:size:)]) {
|
||||
[self.delegate rtcEngineVideoFirstLoadWithUid:uid size:size];
|
||||
}
|
||||
}
|
||||
-(void)rtcEngine:(AgoraRtcEngineKit *)engine remoteVideoStateChangedOfUid:(NSUInteger)uid state:(AgoraVideoRemoteState)state reason:(AgoraVideoRemoteReason)reason elapsed:(NSInteger)elapsed{
|
||||
NSLog(@"uid=%ld---直播远端视频状态发生变化status=%ld",uid,state);
|
||||
if (state == AgoraVideoRemoteStateStopped) {
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(rtcEngineVideoDidStop:)]) {
|
||||
[self.delegate rtcEngineVideoDidStop:uid];
|
||||
}
|
||||
}else if (state == AgoraVideoRemoteStateStarting) {
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(rtcEngineVideoDidStart:)]) {
|
||||
[self.delegate rtcEngineVideoDidStart:uid];
|
||||
}
|
||||
}else{
|
||||
// if (self.delegate && [self.delegate respondsToSelector:@selector(rtcEngineVideoDidStart:)]) {
|
||||
// [self.delegate rtcEngineVideoDidStart:uid];
|
||||
// }
|
||||
}
|
||||
}
|
||||
-(void)rtcEngine:(AgoraRtcEngineKit *)engine channelMediaRelayStateDidChange:(AgoraChannelMediaRelayState)state error:(AgoraChannelMediaRelayError)error{
|
||||
NSLog(@"channelMediaRelayStateDidChange");
|
||||
}
|
||||
-(void)rtcEngine:(AgoraRtcEngineKit *)engine localVideoStateChangedOfState:(AgoraVideoLocalState)state reason:(AgoraLocalVideoStreamReason)reason sourceType:(AgoraVideoSourceType)sourceType{
|
||||
NSLog(@"localVideoStateChangedOfState");
|
||||
if (state == AgoraVideoLocalStateCapturing && sourceType == AgoraVideoSourceTypeScreen) {
|
||||
self.option.publishScreenCaptureAudio = YES;
|
||||
self.option.publishScreenCaptureVideo = YES;
|
||||
self.option.publishCameraTrack = NO;
|
||||
[self.agoraKit updateChannelWithMediaOptions:self.option];
|
||||
|
||||
}else if (state == AgoraVideoLocalStateStopped && sourceType == AgoraVideoSourceTypeScreen) {
|
||||
[self.agoraKit stopScreenCapture];
|
||||
}
|
||||
}
|
||||
-(void)rtcEngine:(AgoraRtcEngineKit *)engine audioMixingPositionChanged:(NSInteger)position{
|
||||
|
||||
}
|
||||
|
||||
//- (void)rtcEngineLocalAudioMixingDidFinish:(AgoraRtcEngineKit *_Nonnull)engine{
|
||||
// if (self.delegate && [self.delegate respondsToSelector:@selector(rtcEngineLocalAudioMixingDidFinish)]) {
|
||||
// [self.delegate rtcEngineLocalAudioMixingDidFinish];
|
||||
// return;
|
||||
// }
|
||||
// NSString *cachePath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject;
|
||||
// NSString *filePath = [cachePath stringByAppendingPathComponent:@"testPlist.plist"];
|
||||
//
|
||||
// NSMutableArray *MusicListArray = [NSMutableArray arrayWithContentsOfFile:filePath];
|
||||
//
|
||||
// NSInteger index = self.index;
|
||||
// switch (self.playType) {
|
||||
// case 0:
|
||||
//
|
||||
// break;
|
||||
// case 1:
|
||||
//
|
||||
// index = MusicListArray.count - 1;
|
||||
//
|
||||
// index = arc4random() % index;
|
||||
//
|
||||
// break;
|
||||
// case 2:
|
||||
//
|
||||
// if (index == MusicListArray.count - 1) {
|
||||
// index = 0;
|
||||
// }//如果不是最后一首下标加1
|
||||
// else{
|
||||
// index++;
|
||||
// }
|
||||
// break;
|
||||
// default:
|
||||
// break;
|
||||
// }
|
||||
//
|
||||
// NSDictionary *dic = MusicListArray[index];
|
||||
// NSString * filePathstr = [dic objectForKey:@"songid"];
|
||||
// [self RequestMusicURLData:filePathstr];
|
||||
//}
|
||||
|
||||
|
||||
-(void)addBgMusic:(QXSongListModel *)music{
|
||||
if (self.bgMusicArray.count == 0 && self.songModel == nil) {
|
||||
[self.bgMusicArray addObject:music];
|
||||
[self nextBgMusic];
|
||||
}else{
|
||||
[self.bgMusicArray addObject:music];
|
||||
}
|
||||
|
||||
}
|
||||
-(void)nextBgMusic{
|
||||
if (self.bgMusicArray.count > 0) {
|
||||
QXSongListModel *music = self.bgMusicArray.firstObject;
|
||||
[self ktv_EndSing];
|
||||
[self ktv_StartSing:YES withSong:music];
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(rtcEngineBackgroundMusicNextSong:)]) {
|
||||
[self.delegate rtcEngineBackgroundMusicNextSong:music];
|
||||
}
|
||||
[self.bgMusicArray removeObject:self.songModel];
|
||||
}else{
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
showToast(@"已经是最后一首了");
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
-(void)pausePlayMusic{
|
||||
[self.ktvPlayer pause];
|
||||
}
|
||||
-(void)resumePlayMusic{
|
||||
[self.ktvPlayer resume];
|
||||
}
|
||||
|
||||
|
||||
- (void)setUseMicrophone:(BOOL)useMicrophone {
|
||||
_useMicrophone = useMicrophone;
|
||||
[self.agoraKit adjustRecordingSignalVolume:useMicrophone ? 100 : 0];
|
||||
|
||||
}
|
||||
|
||||
- (void)onInitKTVCenterWithToken:(NSString*)token{
|
||||
// 1.注册曲库并初始化 AgoraMusicContentCenter。
|
||||
AgoraMusicContentCenterConfig *config = [AgoraMusicContentCenterConfig new];
|
||||
// 填入已开启音乐内容中心项目的 App ID
|
||||
config.appId = AgoraAuthId;
|
||||
// 用户 ID,该 ID 可以和你加入 RTC 频道时使用的 uid 一致,但不能为 0。
|
||||
config.mccUid = QXGlobal.shareGlobal.loginModel.user_id.integerValue;
|
||||
// 填入用于鉴权的 Token。
|
||||
config.token = token;
|
||||
// AgoraRtcEngineKit 实例。
|
||||
config.rtcEngine = self.agoraKit;
|
||||
_ktvAmcc = [AgoraMusicContentCenter sharedContentCenterWithConfig:config];
|
||||
[_ktvAmcc registerEventDelegate:self];
|
||||
|
||||
//创建音乐播放器。如果你需要播放音乐内容中心的音乐资源,需要使用此播放器进行播放。
|
||||
_ktvPlayer = [_ktvAmcc createMusicPlayerWithDelegate:self];
|
||||
|
||||
}
|
||||
|
||||
- (void)ktv_DestoryKtvPlayer{
|
||||
[_ktvPlayer stop];
|
||||
self.songModel = nil;
|
||||
|
||||
// if (self.ktv_UpdatePlayBtnStatusBlock) {
|
||||
// self.ktv_UpdatePlayBtnStatusBlock(NO);
|
||||
// }
|
||||
}
|
||||
-(void)searchSongWithKeyword:(NSString *)keywords page:(NSInteger)page resultBlock:(nonnull SearchSongBlock)resultBlock{
|
||||
self.searchSongBlock = resultBlock;
|
||||
[_ktvAmcc searchMusicWithKeyWord:keywords page:page pageSize:20 jsonOption:nil];
|
||||
}
|
||||
|
||||
//预加载回调
|
||||
-(void)onPreLoadEvent:(NSString *)requestId songCode:(NSInteger)songCode percent:(NSInteger)percent lyricUrl:(NSString *)lyricUrl state:(AgoraMusicContentCenterPreloadState)state reason:(AgoraMusicContentCenterStateReason)reason{
|
||||
if (state == AgoraMusicContentCenterPreloadStateOK) {
|
||||
[_ktvPlayer stop];
|
||||
NSInteger code = [_ktvPlayer openMediaWithSongCode:songCode startPos:0];
|
||||
QXLOG(code==0?@"播放器打开成功":@"播放器打开失败");
|
||||
}
|
||||
}
|
||||
//打开音乐资源回调
|
||||
-(void)AgoraRtcMediaPlayer:(id<AgoraRtcMediaPlayerProtocol>)playerKit didChangedToState:(AgoraMediaPlayerState)state reason:(AgoraMediaPlayerReason)reason{
|
||||
if (state == AgoraMediaPlayerStateOpenCompleted) {
|
||||
// [_ktvPlayer play];
|
||||
if (self.isPlayBgMusic) {
|
||||
/// 背景音乐无需获取歌词
|
||||
return;
|
||||
}
|
||||
[_ktvAmcc getLyricWithSongCode:_songModel.song_code lyricType:1];
|
||||
[_ktvAmcc getSongSimpleInfoWithSongCode:_songModel.song_code];
|
||||
}else if (state == AgoraMediaPlayerStatePlayBackCompleted || state == AgoraMediaPlayerStatePlayBackAllLoopsCompleted || state == AgoraMediaPlayerStateStopped) {
|
||||
|
||||
}
|
||||
}
|
||||
//播放进度回调
|
||||
-(void)AgoraRtcMediaPlayer:(id<AgoraRtcMediaPlayerProtocol>)playerKit didChangedToPosition:(NSInteger)positionMs atTimestamp:(NSTimeInterval)timestampMs{
|
||||
if (playerKit.getPlayerState == AgoraMediaPlayerStatePlaying) {
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(rtcEngineSongProgress:)]) {
|
||||
[self.delegate rtcEngineSongProgress:positionMs];
|
||||
}
|
||||
if (self.isPlayBgMusic) {
|
||||
return;
|
||||
}
|
||||
self.playPosition = positionMs;
|
||||
NSDictionary *dict = @{
|
||||
@"position":[NSNumber numberWithInteger:positionMs],
|
||||
};
|
||||
NSString *jsonStr = [dict jsonStringEncoded];
|
||||
[[QXRoomMessageManager shared] sendChatMessage:jsonStr messageType:(QXRoomMessageTypeSongLrc) needInsertMessage:NO];
|
||||
|
||||
|
||||
// if (self.roomInfo.is_xiangqin == 1){
|
||||
// NSDictionary *body = @{@"messageType":@(BJIMMsgType_UpdateLyricPosition).stringValue,
|
||||
// @"position":@(positionMs).stringValue
|
||||
// };
|
||||
// [[V2TIMManager sharedInstance] sendGroupCustomMessage:body.mj_JSONData to:_roomInfo.roomId priority:V2TIM_PRIORITY_NORMAL succ:^{
|
||||
//
|
||||
// } fail:^(int code, NSString *msg) {
|
||||
// // 群聊文本消息发送失败
|
||||
// }];
|
||||
// }
|
||||
|
||||
}else if (playerKit.getPlayerState == AgoraMediaPlayerStatePlayBackAllLoopsCompleted) {
|
||||
if (self.isPlayBgMusic) {
|
||||
[self nextBgMusic];
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
-(void)rtcEngine:(AgoraRtcEngineKit *)engine receiveStreamMessageFromUid:(NSUInteger)uid streamId:(NSInteger)streamId data:(NSData *)data{
|
||||
NSString *jsonStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
|
||||
NSDictionary *dict = [jsonStr jsonValueDecoded];
|
||||
NSInteger positionMs = [[dict objectForKey:@"position"] integerValue];
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(rtcEngineSongProgress:)]) {
|
||||
[self.delegate rtcEngineSongProgress:positionMs];
|
||||
}
|
||||
}
|
||||
/// 收藏音乐
|
||||
- (void)onMusicChartsResult:(NSString *)requestId result:(NSArray<AgoraMusicChartInfo *> *)result reason:(AgoraMusicContentCenterStateReason)reason{
|
||||
|
||||
}
|
||||
/// 搜索回调
|
||||
-(void)onMusicCollectionResult:(NSString *)requestId result:(AgoraMusicCollection *)result reason:(AgoraMusicContentCenterStateReason)reason{
|
||||
if (self.searchSongBlock) {
|
||||
self.searchSongBlock(result.musicList,result.page == 1);
|
||||
}
|
||||
}
|
||||
/// 歌曲信息
|
||||
-(void)onSongSimpleInfoResult:(NSString *)requestId songCode:(NSInteger)songCode simpleInfo:(NSString *)simpleInfo reason:(AgoraMusicContentCenterStateReason)reason{
|
||||
|
||||
}
|
||||
-(void)onLyricResult:(NSString *)requestId songCode:(NSInteger)songCode lyricUrl:(NSString *)lyricUrl reason:(AgoraMusicContentCenterStateReason)reason{
|
||||
NSLog(@"歌词地址回调-----%ld", reason);
|
||||
dispatch_async(dispatch_get_main_queue(),^{
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(rtcEngineSongLrc:)]) {
|
||||
[self.delegate rtcEngineSongLrc:lyricUrl];
|
||||
}
|
||||
});
|
||||
}
|
||||
-(void)ktv_LoadLrcWithSong:(QXSongListModel *)songModel{
|
||||
// if ([_ktvAmcc isPreloadedWithSongCode:_songModel.song_code] < 0) {//未预加载
|
||||
// [_ktvAmcc preloadWithSongCode:_songModel.song_code];
|
||||
// }
|
||||
_songModel = songModel;
|
||||
if ([_ktvAmcc isPreloadedWithSongCode:_songModel.song_code] < 0) {//未预加载
|
||||
[_ktvAmcc preloadWithSongCode:_songModel.song_code];
|
||||
}else{
|
||||
NSInteger result = [_ktvPlayer openMediaWithSongCode:_songModel.song_code startPos:0];
|
||||
QXLOG(@"歌词---%ld",result);
|
||||
}
|
||||
}
|
||||
-(void)ktv_StartSing:(BOOL)isStart withSong:(nonnull QXSongListModel *)songModel{
|
||||
|
||||
// if (_songModel) {
|
||||
// [_ktvPlayer stop];
|
||||
// }
|
||||
if (songModel == nil) {
|
||||
return;
|
||||
}
|
||||
_songModel = songModel;
|
||||
|
||||
if (isStart) {
|
||||
if ([_ktvAmcc isPreloadedWithSongCode:_songModel.song_code] < 0) {//未预加载
|
||||
[_ktvAmcc preloadWithSongCode:_songModel.song_code];
|
||||
// [SVProgressHUD showWithStatus:@"歌曲预加载中,请稍候"];
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
[self ktv_StartSing:YES withSong:self->_songModel];
|
||||
// [SVProgressHUD dismiss];
|
||||
});
|
||||
}else {
|
||||
NSLog(@"getPlayerState : %ld",(long)[_ktvPlayer getPlayerState]);
|
||||
if ([_ktvPlayer getPlayerState] == AgoraMediaPlayerStatePaused) {
|
||||
NSInteger tag = [_ktvPlayer resume];
|
||||
NSLog(@"内容中心继续---%ld", tag);
|
||||
}else if ([_ktvPlayer getPlayerState] == AgoraMediaPlayerStateIdle) {
|
||||
NSInteger tag = [_ktvPlayer openMediaWithSongCode:_songModel.song_code startPos:0];
|
||||
|
||||
// [SVProgressHUD showWithStatus:@"正在打开,请稍候"];
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
[self ktv_StartSing:YES withSong:self->_songModel];
|
||||
// [SVProgressHUD dismiss];
|
||||
});
|
||||
NSLog(@"未打开---%ld", tag);
|
||||
}else if ([_ktvPlayer getPlayerState] == AgoraMediaPlayerStateOpenCompleted) {
|
||||
if (self.isPlayBgMusic) {
|
||||
[self ktv_OriginalSingSetting:1];
|
||||
}
|
||||
NSInteger tag = [_ktvPlayer play];
|
||||
NSLog(@"内容中心播放---%ld", tag);
|
||||
}else if ([_ktvPlayer getPlayerState] == AgoraMediaPlayerStateStopped) {
|
||||
NSInteger tag = [_ktvPlayer openMediaWithSongCode:_songModel.song_code startPos:0];
|
||||
NSLog(@"内容中心播放---%ld", tag);
|
||||
}else if ([_ktvPlayer getPlayerState] == AgoraMediaPlayerStatePlayBackAllLoopsCompleted) {
|
||||
NSInteger tag = [_ktvPlayer openMediaWithSongCode:_songModel.song_code startPos:0];
|
||||
NSLog(@"内容中心播放---%ld", tag);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
NSInteger tag = [_ktvPlayer pause];
|
||||
NSLog(@"内容中心暂停---%ld", tag);
|
||||
}
|
||||
|
||||
if ([_ktvPlayer getPlayerState] == AgoraMediaPlayerStatePlaying) {
|
||||
AgoraRtcChannelMediaOptions *options = [AgoraRtcChannelMediaOptions new];
|
||||
options.autoSubscribeAudio = YES;
|
||||
options.autoSubscribeVideo = YES;
|
||||
options.publishMediaPlayerId = [_ktvPlayer getMediaPlayerId];
|
||||
options.publishMediaPlayerAudioTrack = YES;
|
||||
[self.agoraKit updateChannelWithMediaOptions:options];
|
||||
}
|
||||
}
|
||||
|
||||
-(void)ktv_EndSing{
|
||||
// if ([_ktvPlayer getPlayerState] == AgoraMediaPlayerStatePlaying) {
|
||||
// [_ktvPlayer stop];
|
||||
// }
|
||||
[_ktvPlayer stop];
|
||||
_songModel = nil;
|
||||
}
|
||||
-(void)ktv_OriginalSingSetting:(BOOL)isOriginal {
|
||||
//原唱0 伴奏1
|
||||
[self.ktvPlayer selectAudioTrack:!isOriginal];
|
||||
}
|
||||
|
||||
-(BOOL)ktv_GetErfan {
|
||||
return self.isErfan;
|
||||
}
|
||||
|
||||
-(void)ktv_SetErfan:(BOOL)isErfan {
|
||||
self.isErfan = isErfan;
|
||||
[self.agoraKit enableInEarMonitoring:isErfan];
|
||||
}
|
||||
|
||||
//-(void)ktv_setVoiceEffert{
|
||||
// [self.agoraKit setAudioEffectPreset:(AgoraAudioEffectPreset)];
|
||||
//}
|
||||
|
||||
|
||||
-(void)ktv_SetRenshengVolume:(float)ratio {
|
||||
int volume = ratio*400;
|
||||
self.renshengVolume = volume;
|
||||
// if (self.useMicrophone) {
|
||||
[self.agoraKit adjustRecordingSignalVolume:volume];
|
||||
// }
|
||||
}
|
||||
-(void)ktv_SetBanzouVolume:(float)ratio {
|
||||
int volume = ratio*100;
|
||||
[self.ktvPlayer adjustPlayoutVolume:volume];
|
||||
[self.ktvPlayer adjustPublishSignalVolume:volume];
|
||||
}
|
||||
-(float)ktv_GetBanzouVolume {
|
||||
int volume = [self.ktvPlayer getPlayoutVolume];
|
||||
// [self.agoraKit getAudioMixingPlayoutVolume];
|
||||
return volume/100.0;
|
||||
}
|
||||
|
||||
|
||||
-(NSMutableArray *)bgMusicArray{
|
||||
if (!_bgMusicArray) {
|
||||
_bgMusicArray = [NSMutableArray array];
|
||||
}
|
||||
return _bgMusicArray;
|
||||
}
|
||||
|
||||
|
||||
- (AgoraScreenCaptureParameters2 *)screenParams {
|
||||
if (_screenParams == nil) {
|
||||
_screenParams = [[AgoraScreenCaptureParameters2 alloc] init];
|
||||
_screenParams.captureAudio = YES;
|
||||
_screenParams.captureVideo = YES;
|
||||
AgoraScreenAudioParameters *audioParams = [[AgoraScreenAudioParameters alloc] init];
|
||||
audioParams.captureSignalVolume = 50;
|
||||
_screenParams.audioParams = audioParams;
|
||||
AgoraScreenVideoParameters *videoParams = [[AgoraScreenVideoParameters alloc] init];
|
||||
videoParams.dimensions = [self screenShareVideoDimension];
|
||||
videoParams.frameRate = AgoraVideoFrameRateFps15;
|
||||
videoParams.bitrate = AgoraVideoBitrateStandard;
|
||||
}
|
||||
return _screenParams;
|
||||
}
|
||||
- (CGSize)screenShareVideoDimension {
|
||||
CGSize screenSize = UIScreen.mainScreen.bounds.size;
|
||||
CGSize boundingSize = CGSizeMake(540, 960);
|
||||
CGFloat mW = boundingSize.width / screenSize.width;
|
||||
CGFloat mH = boundingSize.height / screenSize.height;
|
||||
if (mH < mW) {
|
||||
boundingSize.width = boundingSize.height / screenSize.height * screenSize.width;
|
||||
} else if (mW < mH) {
|
||||
boundingSize.height = boundingSize.width / screenSize.width * screenSize.height;
|
||||
}
|
||||
return boundingSize;
|
||||
}
|
||||
-(void)startScreenCapture{
|
||||
|
||||
// /// 更新
|
||||
//// [self prepareSystemBroadcaster];
|
||||
//
|
||||
// AgoraRtcChannelMediaOptions *option = [AgoraRtcChannelMediaOptions new];
|
||||
// option.publishMicrophoneTrack = YES;
|
||||
// option.publishMediaPlayerAudioTrack = YES;
|
||||
// option.enableAudioRecordingOrPlayout = YES;
|
||||
// option.publishScreenCaptureVideo = YES;
|
||||
// option.publishScreenCaptureAudio = YES;
|
||||
// option.publishCameraTrack = NO;
|
||||
// option.clientRoleType = AgoraClientRoleBroadcaster;
|
||||
// [self.agoraKit updateChannelWithMediaOptions:option];
|
||||
// [self.agoraKit startScreenCapture:self.screenParams];
|
||||
// [self.agoraKit muteLocalVideoStream:NO];
|
||||
// [self.agoraKit enableVideo];
|
||||
// [self.agoraKit enableLocalVideo:YES];
|
||||
// [self prepareSystemBroadcaster];
|
||||
// for (UIView *view in self.systemBroadcastPicker.subviews) {
|
||||
// if ([view isKindOfClass:[UIButton class]]) {
|
||||
// [((UIButton *)view) sendActionsForControlEvents:(UIControlEventAllEvents)];
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// AgoraVideoEncoderConfiguration *encoderConfig = [[AgoraVideoEncoderConfiguration alloc] initWithSize:CGSizeMake(960, 540)
|
||||
// frameRate:(AgoraVideoFrameRateFps15)
|
||||
// bitrate:AgoraVideoBitrateStandard
|
||||
// orientationMode:(AgoraVideoOutputOrientationModeFixedPortrait)
|
||||
// mirrorMode:(AgoraVideoMirrorModeAuto)];
|
||||
// [self.agoraKit setVideoEncoderConfiguration:encoderConfig];
|
||||
//
|
||||
// // set up local video to render your local camera preview
|
||||
// AgoraRtcVideoCanvas *videoCanvas = [[AgoraRtcVideoCanvas alloc] init];
|
||||
// videoCanvas.uid = QXGlobal.shareGlobal.loginModel.user_id.longLongValue;
|
||||
// // the view to be binded
|
||||
//// videoCanvas.view = self.localView.videoView;
|
||||
// videoCanvas.renderMode = AgoraVideoRenderModeHidden;
|
||||
// [self.agoraKit setupLocalVideo:videoCanvas];
|
||||
// // you have to call startPreview to see local video
|
||||
// [self.agoraKit startPreview];
|
||||
// [self.agoraKit enableAudio];
|
||||
// [self.agoraKit enableVideo];
|
||||
|
||||
|
||||
[self.agoraKit setScreenCaptureScenario:AgoraScreenScenarioVideo];
|
||||
self.option.clientRoleType = AgoraClientRoleBroadcaster;
|
||||
[self.agoraKit updateChannelWithMediaOptions:self.option];
|
||||
[self.agoraKit startScreenCapture:self.screenParams];
|
||||
[self prepareSystemBroadcaster];
|
||||
for (UIView *view in self.systemBroadcastPicker.subviews) {
|
||||
if ([view isKindOfClass:[UIButton class]]) {
|
||||
[((UIButton *)view) sendActionsForControlEvents:(UIControlEventAllEvents)];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)prepareSystemBroadcaster {
|
||||
CGRect frame = CGRectMake(0, 0, 60, 60);
|
||||
self.systemBroadcastPicker = [[RPSystemBroadcastPickerView alloc]initWithFrame:frame];
|
||||
self.systemBroadcastPicker.showsMicrophoneButton = NO;
|
||||
self.systemBroadcastPicker.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleRightMargin;
|
||||
NSString *bundleId = [NSBundle mainBundle].bundleIdentifier;
|
||||
self.systemBroadcastPicker.preferredExtension = [NSString stringWithFormat:@"%@.QXLiveScreen",bundleId];
|
||||
}
|
||||
|
||||
|
||||
-(void)startPreViewWithUid:(NSInteger)uid view:(nonnull UIView *)view{
|
||||
AgoraRtcVideoCanvas* videoCanvas = [[AgoraRtcVideoCanvas alloc]init];
|
||||
videoCanvas.uid = uid;
|
||||
videoCanvas.view = view;
|
||||
videoCanvas.renderMode = AgoraVideoRenderModeFit;
|
||||
videoCanvas.setupMode = AgoraVideoViewSetupAdd;
|
||||
[self.agoraKit setupRemoteVideo:videoCanvas];
|
||||
}
|
||||
- (AgoraRtcChannelMediaOptions *)option {
|
||||
if (_option == nil) {
|
||||
_option = [[AgoraRtcChannelMediaOptions alloc] init];
|
||||
_option.clientRoleType = AgoraClientRoleAudience;
|
||||
_option.publishCameraTrack = NO;
|
||||
_option.publishMicrophoneTrack = YES;
|
||||
_option.publishScreenCaptureVideo = NO;
|
||||
_option.publishScreenCaptureAudio = NO;
|
||||
}
|
||||
return _option;
|
||||
}
|
||||
@end
|
||||
23
QXLive/Config/QXAgoraEngineEx.h
Normal file
23
QXLive/Config/QXAgoraEngineEx.h
Normal file
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// QXAgoraEngineEx.h
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/7/2.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <AgoraRtcKit/AgoraRtcEngineKit.h>
|
||||
#import <AgoraRtcKit/AgoraRtcEngineKitEx.h>
|
||||
#import "QXUserModel.h"
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QXAgoraEngineEx : NSObject
|
||||
+ (instancetype)sharedEngine;
|
||||
-(void)joinExWithAgora_token:(NSString*)agora_token channel:(NSString*)channel;
|
||||
- (void)muteLocalEXAudioStream:(BOOL)mute fromUserInfo:(QXUserHomeModel *)fromUserInfo;;
|
||||
|
||||
- (void)muteRemoteEXAudioStream:(BOOL)mute;
|
||||
-(void)quitEXChannelWithLastPkRoomId:(NSString*)last_pk_room_id;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
97
QXLive/Config/QXAgoraEngineEx.m
Normal file
97
QXLive/Config/QXAgoraEngineEx.m
Normal file
@@ -0,0 +1,97 @@
|
||||
//
|
||||
// QXAgoraEngineEx.m
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/7/2.
|
||||
//
|
||||
|
||||
#import "QXAgoraEngineEx.h"
|
||||
#import "QXAgoraEngine.h"
|
||||
@interface QXAgoraEngineEx()<AgoraRtcEngineDelegate>
|
||||
@property (nonatomic,strong)NSString*channel;
|
||||
@property (nonatomic,strong)AgoraRtcConnection *connection;
|
||||
@property (nonatomic,strong)AgoraRtcChannelMediaOptions *option;
|
||||
@end
|
||||
@implementation QXAgoraEngineEx
|
||||
|
||||
+(instancetype)sharedEngine {
|
||||
static dispatch_once_t onceToken;
|
||||
static QXAgoraEngineEx *instance;
|
||||
dispatch_once(&onceToken, ^{
|
||||
instance = [[QXAgoraEngineEx alloc] init];
|
||||
});
|
||||
return instance;
|
||||
}
|
||||
-(void)joinExWithAgora_token:(NSString*)agora_token channel:(NSString*)channel{
|
||||
// AgoraRtcChannelMediaOptions *option = [AgoraRtcChannelMediaOptions new];
|
||||
// option.publishMicrophoneTrack = YES;
|
||||
// option.publishMediaPlayerAudioTrack = YES;
|
||||
// option.enableAudioRecordingOrPlayout = YES;
|
||||
AgoraRtcConnection *connection = [[AgoraRtcConnection alloc] initWithChannelId:channel localUid:QXGlobal.shareGlobal.loginModel.user_id.longLongValue];
|
||||
_channel = channel;
|
||||
_connection = connection;
|
||||
MJWeakSelf
|
||||
int result = [[QXAgoraEngine sharedEngine].agoraKit joinChannelExByToken:agora_token connection:connection delegate:self mediaOptions:self.option joinSuccess:^(NSString * _Nonnull channel, NSUInteger uid, NSInteger elapsed) {
|
||||
[[QXAgoraEngine sharedEngine].agoraKit muteLocalAudioStreamEx:NO connection:connection];
|
||||
[[QXAgoraEngine sharedEngine].agoraKit muteAllRemoteAudioStreamsEx:NO connection:connection];;
|
||||
}];
|
||||
QXLOG(@"声网加入扩展流result---->%d",result)
|
||||
}
|
||||
-(void)rtcEngine:(AgoraRtcEngineKit *)engine didJoinChannel:(NSString *)channel withUid:(NSUInteger)uid elapsed:(NSInteger)elapsed{
|
||||
QXLOG(@"声网加入扩展流channel------ %@",channel);
|
||||
}
|
||||
-(void)rtcEngine:(AgoraRtcEngineKit *)engine didOccurError:(AgoraErrorCode)errorCode{
|
||||
QXLOG(@"声网加入扩展流errorCodel------ %ld",errorCode);
|
||||
}
|
||||
-(void)rtcEngine:(AgoraRtcEngineKit *)engine reportAudioVolumeIndicationOfSpeakers:(NSArray<AgoraRtcAudioVolumeInfo *> *)speakers totalVolume:(NSInteger)totalVolume{
|
||||
for (AgoraRtcAudioVolumeInfo *info in speakers) {
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:noticeUserSpeak object:info];
|
||||
}
|
||||
}
|
||||
-(void)muteLocalEXAudioStream:(BOOL)mute fromUserInfo:(nonnull QXUserHomeModel *)fromUserInfo{
|
||||
// AgoraRtcChannelMediaOptions *option = [AgoraRtcChannelMediaOptions new];
|
||||
// option.publishMicrophoneTrack = mute?NO:YES;
|
||||
// option.publishMediaPlayerAudioTrack = mute?NO:YES;;
|
||||
// option.enableAudioRecordingOrPlayout = mute?NO:YES;;
|
||||
// option.clientRoleType = mute?AgoraClientRoleAudience:AgoraClientRoleBroadcaster;
|
||||
|
||||
// self.option.autoSubscribeAudio = mute?NO:YES;
|
||||
// self.option.autoSubscribeVideo = mute?NO:YES;
|
||||
// self.option.clientRoleType = mute?AgoraClientRoleAudience:AgoraClientRoleBroadcaster;
|
||||
// [[QXAgoraEngine sharedEngine].agoraKit updateChannelExWithMediaOptions:self.option connection:_connection];
|
||||
int result = [[QXAgoraEngine sharedEngine].agoraKit muteLocalAudioStreamEx:mute connection:_connection];
|
||||
// [[QXAgoraEngine sharedEngine].agoraKit muteRemoteAudioStream:fromUserInfo.user_id.integerValue mute:mute];
|
||||
QXLOG(@"声网停止ex频道推流result---->%d",result)
|
||||
}
|
||||
-(void)rtcEngine:(AgoraRtcEngineKit *)engine remoteAudioStateChangedOfUid:(NSUInteger)uid state:(AgoraAudioRemoteState)state reason:(AgoraAudioRemoteReason)reason elapsed:(NSInteger)elapsed{
|
||||
|
||||
}
|
||||
-(void)muteRemoteEXAudioStream:(BOOL)mute{
|
||||
int result = [[QXAgoraEngine sharedEngine].agoraKit muteAllRemoteAudioStreamsEx:mute connection:_connection];;
|
||||
|
||||
QXLOG(@"声网屏蔽远端声音result---->%d",result)
|
||||
|
||||
}
|
||||
|
||||
-(void)quitEXChannelWithLastPkRoomId:(NSString *)last_pk_room_id{
|
||||
if (_connection == nil) {
|
||||
_connection = [[AgoraRtcConnection alloc] initWithChannelId:last_pk_room_id localUid:QXGlobal.shareGlobal.loginModel.user_id.longLongValue];
|
||||
}
|
||||
int result = [[QXAgoraEngine sharedEngine].agoraKit leaveChannelEx:_connection leaveChannelBlock:^(AgoraChannelStats * _Nonnull stat) {
|
||||
|
||||
}];
|
||||
QXLOG(@"声网退出频道result---->%d",result)
|
||||
// [[QXAgoraEngine sharedEngine].agoraKit ];
|
||||
}
|
||||
-(AgoraRtcChannelMediaOptions *)option{
|
||||
if (!_option) {
|
||||
_option = [AgoraRtcChannelMediaOptions new];
|
||||
_option.publishMicrophoneTrack = YES;
|
||||
_option.publishMediaPlayerAudioTrack = YES;
|
||||
_option.enableAudioRecordingOrPlayout = YES;
|
||||
_option.clientRoleType = AgoraClientRoleBroadcaster;
|
||||
}
|
||||
return _option;
|
||||
}
|
||||
|
||||
@end
|
||||
56
QXLive/Config/QXConfig.h
Normal file
56
QXLive/Config/QXConfig.h
Normal file
@@ -0,0 +1,56 @@
|
||||
//
|
||||
// QXConfig.h
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/4/28.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "QXShareView.h"
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
@class QXTabbarModel,QXShareViewModel;
|
||||
@interface QXConfig : NSObject
|
||||
/// 普通字体黑色 default is # 000000
|
||||
@property (nonatomic,strong)UIColor * textColor;
|
||||
/// 主题色 default is # 0dffb9
|
||||
@property (nonatomic,strong)UIColor * themeColor;
|
||||
/// 提示字体颜色 default is #9b9b9b
|
||||
@property (nonatomic,strong)UIColor * placehoulderTextColor;
|
||||
/// 按钮字体颜色 default is #333333
|
||||
@property (nonatomic,strong)UIColor * btnTextColor;
|
||||
/// 背景图片 default is green
|
||||
@property (nonatomic,strong)NSString * backgroundImage;
|
||||
/// 底部工具栏
|
||||
@property (nonatomic,strong)NSArray <QXTabbarModel*>*tabbarArray;
|
||||
///
|
||||
@property (nonatomic,strong)NSArray <QXShareViewModel*>*sharePlatforms;
|
||||
//默认配置
|
||||
+(QXConfig*)defaultConfig;
|
||||
|
||||
+(QXConfig*)shared;
|
||||
/// 获取普通字体颜色
|
||||
+(UIColor*)textColor;
|
||||
/// 获取提示文字颜色色
|
||||
+(UIColor*)placehoulderTextColor;
|
||||
/// 获取主题色
|
||||
+(UIColor*)themeColor;
|
||||
/// 获取按钮字体色
|
||||
+(UIColor*)btnTextColor;
|
||||
/// 主题色
|
||||
+(NSString*)backgroundImage;
|
||||
/// tabbar
|
||||
+(NSArray*)tabbarArray;
|
||||
/// tabbar
|
||||
+(NSArray*)sharePlatforms;
|
||||
/// 保存服务端返回主题配置
|
||||
+(void)saveConfigWithDict:(NSDictionary*)config;
|
||||
|
||||
@end
|
||||
|
||||
@interface QXTabbarModel : NSObject
|
||||
@property (nonatomic,strong)NSString *selectedImage;
|
||||
@property (nonatomic,strong)NSString *normalImage;
|
||||
@property (nonatomic,strong)NSString *title;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
107
QXLive/Config/QXConfig.m
Normal file
107
QXLive/Config/QXConfig.m
Normal file
@@ -0,0 +1,107 @@
|
||||
//
|
||||
// QXConfig.m
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/4/28.
|
||||
//
|
||||
|
||||
#import "QXConfig.h"
|
||||
|
||||
@implementation QXConfig
|
||||
+ (instancetype)shared {
|
||||
static QXConfig *global = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
global = [[self alloc] init];
|
||||
});
|
||||
return global;
|
||||
}
|
||||
+(QXConfig *)defaultConfig{
|
||||
QXConfig *config = [QXConfig shared];
|
||||
config.textColor = RGB16(0x000000);
|
||||
config.backgroundImage = @"app_bg";
|
||||
config.placehoulderTextColor = RGB16(0x9b9b9b);
|
||||
/// appstore
|
||||
config.themeColor = RGB16(0x0dffb9);
|
||||
config.btnTextColor = RGB16(0x333333);
|
||||
|
||||
// config.themeColor = RGB16(0xFC7285);
|
||||
// config.btnTextColor = RGB16(0xFFFFFF);
|
||||
|
||||
QXTabbarModel *index1 = [[QXTabbarModel alloc] init];
|
||||
index1.title = QXText(@"首页");
|
||||
index1.selectedImage = @"qx_tabbar_home_sel";
|
||||
index1.normalImage = @"qx_tabbar_home_nor";
|
||||
QXTabbarModel *index2 = [[QXTabbarModel alloc] init];
|
||||
index2.title = QXText(@"广场");
|
||||
index2.selectedImage = @"qx_tabbar_find_sel";
|
||||
index2.normalImage = @"qx_tabbar_find_nor";
|
||||
// QXTabbarModel *index3 = [[QXTabbarModel alloc] init];
|
||||
// index3.title = QXText(@"音信");
|
||||
// index3.selectedImage = @"qx_tabbar_party";
|
||||
// index3.normalImage = @"qx_tabbar_party";
|
||||
QXTabbarModel *index4 = [[QXTabbarModel alloc] init];
|
||||
index4.title = QXText(@"消息");
|
||||
index4.selectedImage = @"qx_tabbar_message_sel";
|
||||
index4.normalImage = @"qx_tabbar_message_nor";
|
||||
QXTabbarModel *index5 = [[QXTabbarModel alloc] init];
|
||||
index5.title = QXText(@"我的");
|
||||
index5.selectedImage = @"qx_tabbar_me_sel";
|
||||
index5.normalImage = @"qx_tabbar_me_nor";
|
||||
NSArray *tabbarArr = @[index1,index2,index4,index5];
|
||||
config.tabbarArray = tabbarArr;
|
||||
|
||||
QXShareViewModel *platform1 = [[QXShareViewModel alloc] init];
|
||||
platform1.name = QXText(@"微信好友");
|
||||
platform1.icon = @"share_wechat";
|
||||
|
||||
QXShareViewModel *platform2 = [[QXShareViewModel alloc] init];
|
||||
platform2.name = QXText(@"朋友圈");
|
||||
platform2.icon = @"share_wechat_moments";
|
||||
|
||||
config.sharePlatforms = @[platform1,platform2];
|
||||
// QXShareViewModel *platform3 = [[QXShareViewModel alloc] init];
|
||||
// platform3.name = QXText(@"QQ");
|
||||
// platform3.icon = @"share_wechat_moments";
|
||||
//
|
||||
// QXShareViewModel *platform4 = [[QXShareViewModel alloc] init];
|
||||
// platform4.name = QXText(@"QQ空间");
|
||||
// platform4.icon = @"share_wechat";
|
||||
|
||||
// config.sharePlatforms = @[platform1,platform2,platform3,platform4];
|
||||
|
||||
return config;
|
||||
}
|
||||
+(UIColor *)textColor{
|
||||
return [QXConfig shared].textColor;
|
||||
}
|
||||
+(UIColor*)placehoulderTextColor{
|
||||
return [QXConfig shared].placehoulderTextColor;
|
||||
}
|
||||
+(NSString*)backgroundImage{
|
||||
return [QXConfig shared].backgroundImage;
|
||||
}
|
||||
+(UIColor *)themeColor{
|
||||
return [QXConfig shared].themeColor;
|
||||
}
|
||||
+(UIColor *)btnTextColor{
|
||||
return [QXConfig shared].btnTextColor;
|
||||
}
|
||||
+(NSArray *)tabbarArray{
|
||||
return [QXConfig shared].tabbarArray;
|
||||
}
|
||||
+(NSArray *)sharePlatforms{
|
||||
return [QXConfig shared].sharePlatforms;
|
||||
}
|
||||
+(void)saveConfigWithDict:(NSDictionary *)config{
|
||||
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation QXTabbarModel
|
||||
|
||||
|
||||
|
||||
@end
|
||||
|
||||
|
||||
42
QXLive/Config/QXFileManager.h
Normal file
42
QXLive/Config/QXFileManager.h
Normal file
@@ -0,0 +1,42 @@
|
||||
//
|
||||
// QXFileManager.h
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/5/8.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QXFileManager : NSObject
|
||||
///获取Documents目录路径
|
||||
+(NSString*)getDocumentPath;
|
||||
|
||||
///获取Library/Preferences目录路径
|
||||
+(NSString*)getLibraryPreferencesPath;
|
||||
|
||||
///获取Library/Caches路径
|
||||
+(NSString*)getLibraryCachesPath;
|
||||
|
||||
/// 获取tmp路径
|
||||
+(NSString*)getTmpPath;
|
||||
|
||||
/// 搜索历史记录问价写入
|
||||
+(BOOL)writeSearchHistoryWithContent:(NSString*)content;
|
||||
|
||||
///获取搜索历史
|
||||
+(NSArray<NSString*>*)getSearchHistory;
|
||||
|
||||
///删除历史记录
|
||||
+(BOOL)removeSearchHistory;
|
||||
|
||||
// 创建下载文件路径
|
||||
+ (NSString*)createLocalSourceVideoDirectory;
|
||||
// 获取文件下载路径
|
||||
+ (NSString*)getGiftVideoPath:(NSString*)videoName;
|
||||
// 检查文件是否存在
|
||||
+ (BOOL)isExistsFileWithFilePath:(NSString *)filePath;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
141
QXLive/Config/QXFileManager.m
Normal file
141
QXLive/Config/QXFileManager.m
Normal file
@@ -0,0 +1,141 @@
|
||||
//
|
||||
// QXFileManager.m
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/5/8.
|
||||
//
|
||||
|
||||
#import "QXFileManager.h"
|
||||
static NSString *separatorStr = @"$&";
|
||||
///导航历史文件
|
||||
static NSString *searhHistory = @"searhHistoty.txt";
|
||||
|
||||
/// path
|
||||
static NSString *QXVideoPlayerDownloadAtPath = @"GiftSource";
|
||||
@implementation QXFileManager
|
||||
+(NSString *)getDocumentPath{
|
||||
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
|
||||
NSString *documentsDirectory = [paths objectAtIndex:0];
|
||||
return documentsDirectory;
|
||||
}
|
||||
|
||||
+(NSString *)getLibraryPreferencesPath{
|
||||
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
|
||||
NSString *PreferenceDirectory = [paths objectAtIndex:0];
|
||||
return PreferenceDirectory;
|
||||
}
|
||||
|
||||
+(NSString *)getLibraryCachesPath{
|
||||
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
|
||||
NSString *cacheDirectory = [paths objectAtIndex:0];
|
||||
return cacheDirectory;
|
||||
}
|
||||
|
||||
+(NSString *)getTmpPath{
|
||||
NSString*tmpPath = NSTemporaryDirectory();
|
||||
return tmpPath;
|
||||
}
|
||||
+ (NSString*)getSearchHistoryPath{
|
||||
NSString *dir = [NSString stringWithFormat:@"%@/Documents/SearchHistory", NSHomeDirectory()];
|
||||
BOOL isDir = NO;
|
||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||
BOOL existed = [fileManager fileExistsAtPath:dir isDirectory:&isDir];
|
||||
///文件夹已存在
|
||||
if (existed) {
|
||||
return dir;
|
||||
}
|
||||
BOOL result = NO;
|
||||
if (!(isDir == YES && existed == YES)){
|
||||
result =[fileManager createDirectoryAtPath:dir withIntermediateDirectories:YES attributes:nil error:nil];
|
||||
}
|
||||
if (result) {
|
||||
return dir;
|
||||
}else{
|
||||
return @"";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
+(BOOL)writeSearchHistoryWithContent:(NSString*)content{
|
||||
NSString *path = [QXFileManager getSearchHistoryPath];
|
||||
if (path.length == 0) {
|
||||
NSLog(@"文件夹创建失败");
|
||||
return NO;
|
||||
}
|
||||
NSString *filePath;
|
||||
NSString *str = @"";
|
||||
//获取历史搜索记录
|
||||
NSArray *historyArr = [self getSearchHistory];
|
||||
if ([historyArr containsObject:content]) {
|
||||
QXLOG(@"搜素已存在");
|
||||
return NO;
|
||||
}
|
||||
if (historyArr.count > 0) {
|
||||
//历史搜索记录为空
|
||||
str = [historyArr componentsJoinedByString:separatorStr];
|
||||
}
|
||||
//添加最新的搜索历史
|
||||
if (str.length == 0) {
|
||||
str = content;
|
||||
}else{
|
||||
str = [NSString stringWithFormat:@"%@%@%@",content,separatorStr,str];
|
||||
}
|
||||
|
||||
filePath = [path stringByAppendingPathComponent:searhHistory];
|
||||
|
||||
if (filePath.length == 0) {
|
||||
NSLog(@"文件路径为空");
|
||||
return NO;
|
||||
}
|
||||
|
||||
BOOL result = [str writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:nil];
|
||||
if (result) {
|
||||
NSLog(@"写入文件成功");
|
||||
}else{
|
||||
NSLog(@"写入文件失败");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
+(NSArray<NSString *> *)getSearchHistory{
|
||||
NSArray *arr;
|
||||
NSString *filePath = [NSString stringWithFormat:@"%@/Documents/SearchHistory", NSHomeDirectory()];
|
||||
filePath = [filePath stringByAppendingPathComponent:searhHistory];
|
||||
NSString *str = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
|
||||
if (!str || str.length == 0) {
|
||||
return nil;
|
||||
}
|
||||
arr = [str componentsSeparatedByString:separatorStr];
|
||||
return arr;
|
||||
}
|
||||
|
||||
+(BOOL)removeSearchHistory{
|
||||
NSString *filePath = [NSString stringWithFormat:@"%@/Documents/SearchHistory", NSHomeDirectory()];
|
||||
filePath = [filePath stringByAppendingPathComponent:searhHistory];
|
||||
return [[NSFileManager defaultManager] removeItemAtPath:filePath error:nil];
|
||||
}
|
||||
+ (NSString*)createLocalSourceVideoDirectory{
|
||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
|
||||
NSString *cacheDirectory = [paths objectAtIndex:0];
|
||||
NSString*path = [cacheDirectory stringByAppendingPathComponent:QXVideoPlayerDownloadAtPath];
|
||||
if (![fileManager fileExistsAtPath:QXVideoPlayerDownloadAtPath]) {
|
||||
NSError *error = nil;
|
||||
BOOL ret = [fileManager createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:&error];
|
||||
NSLog(@"文件夹创建是否成功=%u",ret);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
+ (NSString*)getGiftVideoPath:(NSString*)videoName{
|
||||
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
|
||||
NSString *cacheDirectory = [paths objectAtIndex:0];
|
||||
NSString*path = [cacheDirectory stringByAppendingPathComponent:QXVideoPlayerDownloadAtPath];
|
||||
NSString *fileNamePath = [path stringByAppendingPathComponent:videoName];
|
||||
return fileNamePath;
|
||||
}
|
||||
+ (BOOL)isExistsFileWithFilePath:(NSString *)filePath {
|
||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||
return [fileManager fileExistsAtPath:filePath];
|
||||
}
|
||||
@end
|
||||
61
QXLive/Config/QXManagerMqtt.h
Executable file
61
QXLive/Config/QXManagerMqtt.h
Executable file
@@ -0,0 +1,61 @@
|
||||
//
|
||||
// ManagerMqtt.h
|
||||
// SoundRiver
|
||||
//
|
||||
// Created by apple on 2020/3/19.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "MQTTClient.h"
|
||||
#import "MQTTSessionManager.h"
|
||||
#import <CommonCrypto/CommonHMAC.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
@protocol MQTTClientModelDelegate <NSObject>
|
||||
@optional
|
||||
- (void)MQTTClientModel_handleMessage:(NSData *)data onTopic:(NSString *)topic retained:(BOOL)retained;
|
||||
- (void)socketManager:(NSString *)socketManager receivedMessage:(NSDictionary *)message topic:(NSString *)topic;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface QXManagerMqtt : NSObject
|
||||
@property (nonatomic, assign) BOOL isDiscontent;
|
||||
@property (nonatomic, weak) id <MQTTClientModelDelegate> delegate;
|
||||
|
||||
@property (nonatomic,strong,nullable) MQTTSessionManager *mySessionManager;
|
||||
|
||||
+ (instancetype)sharedInstance;
|
||||
|
||||
|
||||
- (void)bindWithUserName:(NSString *)username password:(NSString *)password cliendId:(NSString *)cliendId isSSL:(BOOL)isSSL;
|
||||
|
||||
- (void)disconnect;
|
||||
|
||||
- (void)reConnect;
|
||||
|
||||
/**
|
||||
订阅主题
|
||||
|
||||
@param topic 主题
|
||||
*/
|
||||
typedef void (^SubscribeTopicHandler)(NSString *topic, BOOL success);
|
||||
|
||||
- (void)subscribeTopic:(NSString *)topic;
|
||||
|
||||
/**
|
||||
取消订阅
|
||||
|
||||
@param topic 主题
|
||||
*/
|
||||
- (void)unsubscribeTopic:(NSString *)topic;
|
||||
|
||||
/**
|
||||
发布消息
|
||||
*/
|
||||
- (void)sendDataToTopic:(NSString *)topic dict:(NSDictionary *)dict;
|
||||
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
244
QXLive/Config/QXManagerMqtt.m
Executable file
244
QXLive/Config/QXManagerMqtt.m
Executable file
@@ -0,0 +1,244 @@
|
||||
//
|
||||
// ManagerMqtt.m
|
||||
// SoundRiver
|
||||
//
|
||||
// Created by apple on 2020/3/19.
|
||||
//
|
||||
|
||||
#import "QXManagerMqtt.h"
|
||||
|
||||
@interface QXManagerMqtt()<MQTTSessionManagerDelegate>
|
||||
@property (nonatomic, strong)NSString *username;
|
||||
@property (nonatomic, strong)NSString *password;
|
||||
@property (nonatomic, strong)NSString *cliendId;
|
||||
|
||||
//订阅的topic
|
||||
@property (nonatomic,strong) NSMutableDictionary *subedDict;
|
||||
|
||||
@property (nonatomic,assign) BOOL isSSL;
|
||||
|
||||
@end
|
||||
|
||||
@implementation QXManagerMqtt
|
||||
|
||||
+ (instancetype)sharedInstance {
|
||||
static dispatch_once_t onceToken;
|
||||
static QXManagerMqtt *sharedManager;
|
||||
dispatch_once(&onceToken, ^{
|
||||
sharedManager = [[QXManagerMqtt alloc] init];
|
||||
});
|
||||
return sharedManager;
|
||||
}
|
||||
#pragma mark - 绑定
|
||||
- (void)bindWithUserName:(NSString *)username password:(NSString *)password cliendId:(NSString *)cliendId isSSL:(BOOL)isSSL{
|
||||
self.username = username;
|
||||
self.password = password;
|
||||
self.cliendId = cliendId;
|
||||
self.isSSL = isSSL;
|
||||
[self.mySessionManager connectTo:AddressOfMQTTServer
|
||||
port:AddressOfMQTTPort
|
||||
tls:self.isSSL
|
||||
keepalive:60
|
||||
clean:YES
|
||||
auth:YES
|
||||
user:self.username
|
||||
pass:self.password
|
||||
will:NO
|
||||
willTopic:nil
|
||||
willMsg:nil
|
||||
willQos:MQTTQosLevelAtMostOnce
|
||||
willRetainFlag:NO
|
||||
withClientId:self.cliendId
|
||||
securityPolicy:[self customSecurityPolicy]
|
||||
certificates:nil
|
||||
protocolLevel:MQTTProtocolVersion311
|
||||
connectHandler:^(NSError *error) {
|
||||
NSLog(@"mqtt connect - %@", error);
|
||||
// if (error == nil) {
|
||||
// [self subscribeTopic:@"qx_room_topic"];
|
||||
// }
|
||||
}];
|
||||
self.mySessionManager.subscriptions = self.subedDict;
|
||||
}
|
||||
|
||||
- (MQTTSSLSecurityPolicy *)customSecurityPolicy
|
||||
{
|
||||
MQTTSSLSecurityPolicy *securityPolicy = [MQTTSSLSecurityPolicy policyWithPinningMode:MQTTSSLPinningModeNone];
|
||||
|
||||
securityPolicy.allowInvalidCertificates = YES;
|
||||
securityPolicy.validatesCertificateChain = YES;
|
||||
securityPolicy.validatesDomainName = NO;
|
||||
return securityPolicy;
|
||||
}
|
||||
|
||||
#pragma mark ---- 状态
|
||||
|
||||
- (void)sessionManager:(MQTTSessionManager *)sessionManager didChangeState:(MQTTSessionManagerState)newState {
|
||||
switch (newState) {
|
||||
case MQTTSessionManagerStateConnected:
|
||||
QXLOG(@"eventCode -- 连接成功");
|
||||
[self subscribeTopic:@"qx_room_topic"];
|
||||
[self reConnectForStateError];
|
||||
|
||||
break;
|
||||
case MQTTSessionManagerStateConnecting:
|
||||
QXLOG(@"eventCode -- 连接中");
|
||||
|
||||
break;
|
||||
case MQTTSessionManagerStateClosed:
|
||||
QXLOG(@"eventCode -- 连接被关闭");
|
||||
break;
|
||||
case MQTTSessionManagerStateError:
|
||||
QXLOG(@"eventCode -- 连接错误");
|
||||
break;
|
||||
case MQTTSessionManagerStateClosing:
|
||||
QXLOG(@"eventCode -- 关闭中");
|
||||
|
||||
break;
|
||||
case MQTTSessionManagerStateStarting:
|
||||
QXLOG(@"eventCode -- 连接开始");
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
- (void)sessionManager:(MQTTSessionManager *)sessionManager didReceiveMessage:(NSData *)data onTopic:(NSString *)topic retained:(BOOL)retained{
|
||||
|
||||
NSError *error;
|
||||
NSString *dataStr = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
|
||||
dataStr = [dataStr stringByReplacingOccurrencesOfString:@"\\u" withString:@"u_u"];
|
||||
dataStr = [dataStr stringByReplacingOccurrencesOfString:@"\\U" withString:@"U_U"];
|
||||
dataStr=[dataStr stringByReplacingOccurrencesOfString:@"\\" withString:@""];
|
||||
dataStr=[dataStr stringByReplacingOccurrencesOfString:@"\\" withString:@""];
|
||||
dataStr=[dataStr stringByReplacingOccurrencesOfString:@"\\" withString:@""];
|
||||
dataStr=[dataStr stringByReplacingOccurrencesOfString:@"\\" withString:@""];
|
||||
dataStr=[dataStr stringByReplacingOccurrencesOfString:@"\"\"{" withString:@"\"{"];
|
||||
dataStr=[dataStr stringByReplacingOccurrencesOfString:@"}\"\"" withString:@"}\""];
|
||||
|
||||
dataStr=[dataStr stringByReplacingOccurrencesOfString:@"\"{" withString:@"{"];
|
||||
dataStr=[dataStr stringByReplacingOccurrencesOfString:@"}\"" withString:@"}"];
|
||||
|
||||
dataStr = [dataStr stringByReplacingOccurrencesOfString:@"U_U" withString:@"\\U"];
|
||||
dataStr = [dataStr stringByReplacingOccurrencesOfString:@"u_u" withString:@"\\u"];
|
||||
//dataStr = [self replaceUnicode:dataStr];
|
||||
if(dataStr != nil){
|
||||
|
||||
QXLOG(@"收到消息%@",dataStr);
|
||||
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:[dataStr dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingMutableContainers error:&error];
|
||||
QXLOG(@"收到消息%@",dict);
|
||||
if (dict != nil && self.delegate && [self.delegate respondsToSelector:@selector(socketManager:receivedMessage:topic:)]) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self.delegate socketManager:@"收到消息" receivedMessage:dict topic:topic];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
-(NSString *)replaceUnicode:(NSString *)unicodeStr {
|
||||
|
||||
NSString *tempStr1 = [unicodeStr stringByReplacingOccurrencesOfString:@"\\u" withString:@"\\U"];
|
||||
// NSString *tempStr2 = [tempStr1 stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""];
|
||||
// NSString *tempStr3 = [[@"\"" stringByAppendingString:tempStr2] stringByAppendingString:@"\""];
|
||||
NSData *tempData = [tempStr1 dataUsingEncoding:NSUTF8StringEncoding];
|
||||
NSString* returnStr = [NSPropertyListSerialization propertyListFromData:tempData
|
||||
mutabilityOption:NSPropertyListImmutable
|
||||
format:NULL
|
||||
errorDescription:NULL];
|
||||
// NSString* returnStr = [[NSString alloc]initWithData:tempData encoding:NSUTF8StringEncoding];
|
||||
|
||||
//NSLog(@"Output = %@", returnStr);
|
||||
|
||||
return [returnStr stringByReplacingOccurrencesOfString:@"\\r\\n" withString:@"\n"];
|
||||
}
|
||||
|
||||
#pragma mark - 订阅
|
||||
//- (void)subscribeTopic:(NSString *)topic handler:(SubscribeTopicHandler)handler{
|
||||
- (void)subscribeTopic:(NSString *)topic{
|
||||
|
||||
QXLOG(@"当前需要订阅-------- topic = %@",topic);
|
||||
|
||||
if (![self.subedDict.allKeys containsObject:topic]) {
|
||||
[self.subedDict setObject:[NSNumber numberWithLong:MQTTQosLevelAtLeastOnce] forKey:topic];
|
||||
QXLOG(@"订阅字典 ----------- = %@",self.subedDict);
|
||||
self.mySessionManager.subscriptions = self.subedDict;
|
||||
}else {
|
||||
QXLOG(@"已经存在,不用订阅");
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - 取消订阅
|
||||
- (void)unsubscribeTopic:(NSString *)topic {
|
||||
QXLOG(@"当前需要取消订阅-------- topic = %@",topic);
|
||||
if ([self.subedDict.allKeys containsObject:topic]) {
|
||||
[self.subedDict removeObjectForKey:topic];
|
||||
QXLOG(@"更新之后的订阅字典 ----------- = %@",self.subedDict);
|
||||
self.mySessionManager.subscriptions = self.subedDict;
|
||||
}
|
||||
else {
|
||||
QXLOG(@"不存在,无需取消");
|
||||
}
|
||||
}
|
||||
#pragma mark - 发布消息
|
||||
- (void)sendDataToTopic:(NSString *)topic dict:(NSDictionary *)dict {
|
||||
QXLOG(@"发送命令 topic = %@ dict = %@",topic,dict);
|
||||
|
||||
// [dict setValue:[QPCommonTool dateWithNowSp] forKey:@"time"];
|
||||
NSData *data = [NSJSONSerialization dataWithJSONObject:dict options:0 error:nil];
|
||||
[self.mySessionManager sendData:data topic:topic qos:MQTTQosLevelAtLeastOnce retain:NO];
|
||||
}
|
||||
#pragma mark MQTTSessionManagerDelegate
|
||||
- (void)handleMessage:(NSData *)data onTopic:(NSString *)topic retained:(BOOL)retained {
|
||||
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(MQTTClientModel_handleMessage:onTopic:retained:)]) {
|
||||
[self.delegate MQTTClientModel_handleMessage:data onTopic:topic retained:retained];
|
||||
}
|
||||
}
|
||||
- (void)disconnect {
|
||||
[self.mySessionManager disconnectWithDisconnectHandler:^(NSError *error) {
|
||||
QXLOG(@"断开连接 error = %@",[error description]);
|
||||
}];
|
||||
[self.mySessionManager setDelegate:nil];
|
||||
[self.subedDict removeAllObjects];
|
||||
_mySessionManager = nil;
|
||||
}
|
||||
- (void)reConnect {
|
||||
if (self.mySessionManager && self.mySessionManager.port) {
|
||||
if (self.mySessionManager.state == MQTTSessionManagerStateConnected) {
|
||||
return;
|
||||
}
|
||||
self.mySessionManager.delegate = self;
|
||||
[self.mySessionManager connectToLast:^(NSError *error) {
|
||||
QXLOG(@"重新连接 error = %@",[error description]);
|
||||
}];
|
||||
self.mySessionManager.subscriptions = self.subedDict;
|
||||
|
||||
}else if ([self.username isExist] && [self.password isExist] && [self.cliendId isExist]) {
|
||||
[self bindWithUserName:self.username password:self.password cliendId:self.cliendId isSSL:self.isSSL];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//连接错误之后又连接成功之后
|
||||
- (void)reConnectForStateError{
|
||||
|
||||
}
|
||||
|
||||
#pragma mark - 懒加载
|
||||
- (MQTTSessionManager *)mySessionManager {
|
||||
if (!_mySessionManager) {
|
||||
_mySessionManager = [[MQTTSessionManager alloc]init];
|
||||
_mySessionManager.delegate = self;
|
||||
}
|
||||
return _mySessionManager;
|
||||
}
|
||||
|
||||
- (NSMutableDictionary *)subedDict {
|
||||
if (!_subedDict) {
|
||||
_subedDict = [NSMutableDictionary dictionary];
|
||||
}
|
||||
return _subedDict;
|
||||
}
|
||||
@end
|
||||
221
QXLive/Config/QXRoomMessageManager.h
Normal file
221
QXLive/Config/QXRoomMessageManager.h
Normal file
@@ -0,0 +1,221 @@
|
||||
//
|
||||
// QXRoomMessageManager.h
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/6/10.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "QXRoomChatListView.h"
|
||||
#import "QXRoomModel.h"
|
||||
|
||||
typedef NS_ENUM(NSInteger) {
|
||||
/// 清空消息
|
||||
QXRoomMessageTypeClearMessage = 123,
|
||||
/// 歌词同步
|
||||
QXRoomMessageTypeSongLrc = 124,
|
||||
/// pk屏蔽远端声音
|
||||
QXRoomMessageTypeMuteRemoteAudio = 125,
|
||||
/// 关闭自己声音
|
||||
QXRoomMessageTypeMuteLocalAudio = 126,
|
||||
/// 基础文本消息类型
|
||||
QXRoomMessageTypeText = 1,
|
||||
/// 系统消息
|
||||
QXRoomMessageTypeSystem = 1000,
|
||||
/// 用户进入房间
|
||||
QXRoomMessageTypeJoin = 1001,
|
||||
/// 用户退出房间
|
||||
QXRoomMessageTypeQuit = 1002,
|
||||
/// 用户上麦
|
||||
QXRoomMessageTypeUpSeat = 1003,
|
||||
/// 用户下麦
|
||||
QXRoomMessageTypeDownSeat = 1004,
|
||||
/// 房间收到礼物
|
||||
QXRoomMessageTypeGift = 1005,
|
||||
/// 设置管理员
|
||||
QXRoomMessageTypeSetManage = 1006,
|
||||
/// 设置主持
|
||||
QXRoomMessageTypeSetCompere = 1007,
|
||||
/// 禁麦/解禁
|
||||
QXRoomMessageTypeSeatMute = 1008,
|
||||
/// 锁麦/解除锁麦
|
||||
QXRoomMessageTypeSeatLock = 1009,
|
||||
/// 踢出房间
|
||||
QXRoomMessageTypeTakeOff = 1011,
|
||||
/// 房间类型发生变化
|
||||
QXRoomMessageTypeRoomTypeChanged = 1012,
|
||||
/// 点歌/切歌/同意点歌
|
||||
QXRoomMessageTypeSwicthSong = 1013,
|
||||
/// 上麦模式发生变化 自由麦 | 排麦
|
||||
QXRoomMessageTypeAplayPitModeDidChanged = 1014,
|
||||
/// pk房数值变化
|
||||
QXRoomMessageTypePKValueDidChanged = 1015,
|
||||
/// 用户 禁言|禁麦 ,解除禁言|解除禁麦
|
||||
QXRoomMessageTypeRoomUserMute = 1016,
|
||||
/// 管理员被删除
|
||||
QXRoomMessageTypeManagerIsDelete = 1017,
|
||||
/// 主持人被删除
|
||||
QXRoomMessageTypeCompereIsDelete = 1018,
|
||||
/// 点唱时魅力排行榜发生变化
|
||||
QXRoomMessageTypeCharmRankList = 1019,
|
||||
/// 房间信息发生变化是推送
|
||||
QXRoomMessageTypeRoomInfoChanged = 1020,
|
||||
/// 清除魅力
|
||||
QXRoomMessageTypeRoomClearCharm = 1021,
|
||||
/// 拍卖者上麦
|
||||
QXRoomMessageTypeRoomAuctionUpSeat = 1022,
|
||||
/// 拍卖开始 开始倒计时
|
||||
QXRoomMessageTypeRoomAuctionStart = 1023,
|
||||
/// 竞拍麦位发生变化
|
||||
QXRoomMessageTypeRoomAuctionPitChanged = 1024,
|
||||
/// 竞拍结束
|
||||
QXRoomMessageTypeRoomAuctionEnd = 1025,
|
||||
/// 竞拍主持延时
|
||||
QXRoomMessageTypeRoomAuctionDelayTime = 1026,
|
||||
/// 拍卖类型发生变化
|
||||
QXRoomMessageTypeRoomAuctionTypeDidChanged = 1027,
|
||||
/// 私密小屋
|
||||
QXRoomMessageTypeRoomCabinRoomValueChanged = 1028,
|
||||
/// 有人向我发起pk
|
||||
QXRoomMessageTypeRoomRecieveInvitePk = 1029,
|
||||
/// 拒绝或接受pk
|
||||
QXRoomMessageTypeRoomPKAgreeOrRefuse = 1030,
|
||||
/// pk开始
|
||||
QXRoomMessageTypeRoomPKStart = 1031,
|
||||
/// pk结束 惩罚时间
|
||||
QXRoomMessageTypeRoomPKEnd = 1032,
|
||||
/// pk断开
|
||||
QXRoomMessageTypeRoomPKDisconnect = 1033,
|
||||
/// 排麦人数发生变化
|
||||
QXRoomMessageTypeRoomInLineNumber = 1034,
|
||||
/// 用户信息发生变化时推送
|
||||
QXRoomMessageTypeRoomUserInfoDidChanged = 1035,
|
||||
/// 房间人数校正
|
||||
QXRoomMessageTypeRoomOnlineNumber = 1036,
|
||||
/// pk惩罚阶段失败方想跑路需要胜利方的同意
|
||||
QXRoomMessageTypeRoomPkNeedAgree = 1037,
|
||||
/// 房间盲盒开礼物文字消息
|
||||
QXRoomMessageTypeRoomBlindBox = 1038,
|
||||
/// 房间已被封禁
|
||||
QXRoomMessageTypeRoomDidFire = 1039,
|
||||
}QXRoomMessageType;
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
@protocol QXRoomMessageManagerDelegate <NSObject>
|
||||
|
||||
@optional
|
||||
/// 插入消息
|
||||
-(void)didInsertMessge:(QXRoomChatListModel*)message;
|
||||
/// 根据用户userid 插入消息
|
||||
-(void)didInsertMessge:(QXRoomChatListModel*)message userId:(NSString*)userId;
|
||||
/// 上下麦
|
||||
-(void)didUpDownSeatWithUser:(QXUserHomeModel*)user isUpSeat:(BOOL)isUpSeat pit_number:(NSInteger)pit_number;
|
||||
/// 上麦模式发生变化 2 自由麦 | 1 排麦
|
||||
-(void)aplayPitModeDidChanged:(NSString*)upMicType;
|
||||
/// 排麦人数发生变化
|
||||
-(void)aplayMicInLineNumberDidChanged:(NSString*)number;
|
||||
/// 清空消息
|
||||
-(void)didClearAllMessage;
|
||||
/// 有人发起点歌
|
||||
-(void)applySongWaitAgreeWithUserNickname:(NSString*)nickname;
|
||||
/// 主持人拒绝点歌
|
||||
-(void)applySongNoAgreeWithUserId:(NSString*)userId;
|
||||
/// 下一首歌状态发生变化
|
||||
-(void)nextSongDidChangedWithNextSong:(QXSongListModel*)nextInfo;
|
||||
/// 切歌
|
||||
-(void)nextSongDidStartWithSongInfo:(QXSongListModel*)songInfo nextInfo:(QXSongListModel*)nextInfo;
|
||||
/// 点歌房魅力发生变化
|
||||
-(void)songRoomCharmRankListDidChanged:(NSArray<QXRoomPitModel *>*)list;
|
||||
/// 房间内用户信息发生变化
|
||||
-(void)roomUserInfoDidChanged:(QXUserHomeModel *)user;
|
||||
|
||||
|
||||
|
||||
/// 房间状态发生变化
|
||||
-(void)roomTypeDidChanged;
|
||||
/// 房间歌词
|
||||
- (void)roomSongLrcProgress:(NSUInteger)progress;
|
||||
/// 房间信息发生变化
|
||||
- (void)roomInfoDidChanged:(QXRoomInfoModel*)roomInfo;
|
||||
/// 房间管理员/主持人状态发生变化 isManager 是为管理员 否为主持 isAdd 是为添加 否为删除
|
||||
- (void)roomSetManagerOrCompere:(QXUserHomeModel*)userInfo isManager:(BOOL)isManager isAdd:(BOOL)isAdd;
|
||||
/// 踢出房间
|
||||
-(void)userDidTakeOffWithUserInfo:(QXUserHomeModel*)userInfo;
|
||||
/// 清除魅力
|
||||
-(void)roomClearCharm;
|
||||
/// 收到礼物
|
||||
-(void)didRecieveGiftWithWithUserInfo:(QXUserHomeModel*)userInfo;
|
||||
/// 用户禁言禁麦状态发生变化
|
||||
-(void)userMuteStatusDidChanged:(QXUserHomeModel*)userInfo isMute:(NSString*)isMute isMutePit:(NSString*)isMutePit;
|
||||
/// 麦位状态发生变化
|
||||
-(void)roomSeatStatusDidChangedIsLock:(NSString*)is_lock pit_number:(NSString*)pit_number;
|
||||
/// 用户进出房间
|
||||
-(void)roomOnlineNumberDidChangedIsAdd:(BOOL)isAdd;
|
||||
/// 10秒自动校正在线人数
|
||||
-(void)roomOnlineNumberDidChangedOnlineNumber:(NSString*)onlineNumber;
|
||||
|
||||
|
||||
|
||||
/// 拍卖者被拉上麦
|
||||
-(void)auctionUpSeatWithUserInfo:(QXUserHomeModel*)userInfo isUpSeat:(BOOL)isUpSeat;
|
||||
/// 拍卖者列表发生变化
|
||||
-(void)auctionListDidChanged:(NSArray<QXRoomPitModel *>*)auctionList;
|
||||
/// 拍卖状态发生变化
|
||||
-(void)auctionStartOrEndIsStart:(BOOL)isStart user:(QXRoomAuctionUser *)user getUser:(QXRoomAuctionUser*)getUser;
|
||||
/// 拍卖时间延迟
|
||||
-(void)auctionTimeDelayWithEndTime:(NSString*)endTime;
|
||||
/// 拍卖类型发生变化
|
||||
-(void)auctionTypeDidChanged:(NSString*)type;
|
||||
/// 私密小屋心动值发生变化
|
||||
-(void)cabinRoomValueDidChanged:(NSString*)hotValue;
|
||||
|
||||
|
||||
/// 收到pk邀请
|
||||
-(void)recievePKInviteWithSendRoomId:(NSString*)SendRoomId AcceptRoomId:(NSString*)AcceptRoomId PkId:(NSString*)PkId message:(NSString*)message;
|
||||
/// 同意或拒绝pk邀请 user_id 与 room_id 为对方
|
||||
-(void)agreeOrRefusePKIsAgree:(BOOL)isAgree user_id:(NSString*)user_id room_id:(NSString*)room_id pk_id:(NSString*)pk_id;
|
||||
/// pk开始
|
||||
-(void)pkStartWithPkEndTimes:(NSString*)pk_end_times pk_id:(NSString*)pk_id;
|
||||
/// pk值发生变化 room_id_a发起者房间id create_value_a 发起者房间pk值 room_id_b 接收者房间id receive_value_b接受者房间pk值
|
||||
-(void)roomPKValueDidChangedWithRoomIdA:(NSString*)room_id_a create_value_a:(NSString*)create_value_a room_id_b:(NSString*)room_id_b receive_value_b:(NSString*)receive_value_b;
|
||||
/// pk结果 isVictory 0 负 1 胜 2平
|
||||
-(void)pkResultWithIsVictory:(NSInteger)isVictory
|
||||
end_time:(NSString*)end_time
|
||||
victory_name:(NSString*)victory_name
|
||||
victory_cover:(NSString*)victory_cover
|
||||
defeated_name:(NSString*)defeated_name
|
||||
defeated_cover:(NSString*)defeated_cover;
|
||||
/// pk断开
|
||||
-(void)pkDisConnect;
|
||||
/// 是否屏蔽ok远端声音
|
||||
-(void)pkMuteRemoteAudio:(BOOL)isMute fromUserInfo:(QXUserHomeModel*)fromUserInfo;
|
||||
/// 惩罚阶段败方想跑路 胜方收到后决定要不要让他跑
|
||||
-(void)roomPKRecieveLoserWantToRunRoadWithUserInfo:(QXUserHomeModel*)fromUserInfo;;
|
||||
/// 收到抢头条
|
||||
-(void)recieveHeadline:(QXHeadLineModel*)headline;
|
||||
|
||||
|
||||
/// 查询用户状态
|
||||
-(void)getUserStatusWithUsers:(NSArray <NSString*>*)users;
|
||||
|
||||
@end
|
||||
@interface QXRoomMessageManager : NSObject
|
||||
@property (nonatomic,weak)id<QXRoomMessageManagerDelegate>delegate;
|
||||
|
||||
+(instancetype)shared;
|
||||
|
||||
-(void)joinGroupWithRoomId:(NSString*)roomId;
|
||||
|
||||
-(void)quitGroupWithRoomId:(NSString*)roomId;
|
||||
|
||||
-(void)sendChatMessage:(NSString *)message messageType:(QXRoomMessageType)messageType needInsertMessage:(BOOL)needInsertMessage;
|
||||
|
||||
-(void)sendC2CMessage:(NSString *)message messageType:(QXRoomMessageType)messageType userId:(NSString*)userId;
|
||||
@end
|
||||
|
||||
@interface QXRoomMessage : NSObject
|
||||
@property (nonatomic,strong)NSString *RoomId;
|
||||
@property (nonatomic,strong)NSString *MsgType;
|
||||
@property (nonatomic,strong)NSDictionary *Text;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
657
QXLive/Config/QXRoomMessageManager.m
Normal file
657
QXLive/Config/QXRoomMessageManager.m
Normal file
@@ -0,0 +1,657 @@
|
||||
//
|
||||
// QXRoomMessageManager.m
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/6/10.
|
||||
//
|
||||
|
||||
#import "QXRoomMessageManager.h"
|
||||
#import <ImSDK_Plus/ImSDK_Plus.h>
|
||||
#import "QXMineNetwork.h"
|
||||
#import "QXGiftPlayerManager.h"
|
||||
#import <AgoraRtcKit/AgoraRtcEngineKit.h>
|
||||
|
||||
@interface QXRoomMessageManager() <V2TIMGroupListener,V2TIMSimpleMsgListener,V2TIMAdvancedMsgListener>
|
||||
@property (nonatomic,strong)NSString *groupId;
|
||||
@end
|
||||
@implementation QXRoomMessageManager
|
||||
+ (instancetype)shared {
|
||||
static QXRoomMessageManager *global = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
global = [[self alloc] init];
|
||||
});
|
||||
return global;
|
||||
}
|
||||
-(void)joinGroupWithRoomId:(NSString *)roomId{
|
||||
MJWeakSelf
|
||||
if (self.groupId) {
|
||||
[self quitGroupWithRoomId:roomId];
|
||||
}
|
||||
[[V2TIMManager sharedInstance] addGroupListener:self];
|
||||
[[V2TIMManager sharedInstance] addSimpleMsgListener:self];
|
||||
[[V2TIMManager sharedInstance] addAdvancedMsgListener:self];
|
||||
NSString *groupId = [NSString stringWithFormat:@"room%@",roomId];
|
||||
[[V2TIMManager sharedInstance] joinGroup:groupId msg:@"大家好,我来啦" succ:^{
|
||||
QXLOG(@"腾讯IM加入聊天室成功");
|
||||
weakSelf.groupId = groupId;
|
||||
} fail:^(int code, NSString *desc) {
|
||||
// 加入群组失败
|
||||
QXLOG(@"腾讯IM加入聊天室失败-code%d-原因%@",code,desc);
|
||||
}];
|
||||
}
|
||||
-(void)quitGroupWithRoomId:(NSString *)roomId{
|
||||
MJWeakSelf
|
||||
// [QXMineNetwork quitRoomWithRoomId:<#(nonnull NSString *)#> user_id:<#(nonnull NSString *)#> successBlock:<#^(NSDictionary * _Nonnull dict)successBlock#> failBlock:<#^(NSError * _Nonnull error, NSString * _Nonnull msg)failBlock#>];
|
||||
self.groupId = nil;
|
||||
[[V2TIMManager sharedInstance] removeGroupListener:self];
|
||||
[[V2TIMManager sharedInstance] removeSimpleMsgListener:self];
|
||||
[[V2TIMManager sharedInstance] removeAdvancedMsgListener:self];
|
||||
NSString *groupId = [NSString stringWithFormat:@"room%@",roomId];
|
||||
[[V2TIMManager sharedInstance] quitGroup:groupId succ:^{
|
||||
|
||||
} fail:^(int code, NSString * _Nullable desc) {
|
||||
|
||||
}];
|
||||
}
|
||||
// 新成员加入
|
||||
-(void)onMemberEnter:(NSString *)groupID memberList:(NSArray<V2TIMGroupMemberInfo *> *)memberList{
|
||||
|
||||
}
|
||||
// 有人离开
|
||||
-(void)onMemberLeave:(NSString *)groupID member:(V2TIMGroupMemberInfo *)member{
|
||||
|
||||
}
|
||||
- (void)onRecvNewMessage:(V2TIMMessage *)msg {
|
||||
if (msg.isBroadcastMessage) {
|
||||
// 收到了广播消息
|
||||
NSData *data = msg.customElem.data;
|
||||
NSString *jsonStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
|
||||
QXLOG(@"收到广播消息---%@",jsonStr);
|
||||
QXHeadLineModel *headline = [QXHeadLineModel yy_modelWithJSON:jsonStr];
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(recieveHeadline:)]) {
|
||||
[self.delegate recieveHeadline:headline];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 收到系统消息
|
||||
-(void)onReceiveRESTCustomData:(NSString *)groupID data:(NSData *)data{
|
||||
NSString *jsonStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
|
||||
QXRoomMessage *msg = [QXRoomMessage yy_modelWithJSON:jsonStr];
|
||||
NSString *groupId = [NSString stringWithFormat:@"room%@",msg.RoomId];
|
||||
if ([groupId isEqualToString:self.groupId]) {
|
||||
// 处理逻辑
|
||||
NSInteger meesageType = msg.MsgType.integerValue;
|
||||
switch (meesageType) {
|
||||
case QXRoomMessageTypeSystem:{
|
||||
/// 系统消息
|
||||
}
|
||||
break;
|
||||
case QXRoomMessageTypeJoin:{
|
||||
/// 用户进入房间
|
||||
QXRoomChatListModel *model = [QXRoomChatListModel yy_modelWithJSON:msg.Text];
|
||||
model.messageType = QXRoomChatMessageTypeSystem;
|
||||
NSString *jia_jia = [NSString stringWithFormat:@"%@",msg.Text[@"jia_jia"]];
|
||||
if (([jia_jia hasPrefix:@"http"] || [jia_jia hasPrefix:@"https"]) && ([jia_jia hasSuffix:@"svga"] || [jia_jia hasSuffix:@"mp4"])) {
|
||||
QXGiftModel *md = [[QXGiftModel alloc] init];
|
||||
md.play_image = jia_jia;
|
||||
[[QXGiftPlayerManager shareManager] displayChatEffectView:md];
|
||||
}
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(didInsertMessge:)]) {
|
||||
[self.delegate didInsertMessge:model];
|
||||
}
|
||||
if ([model.FromUserInfo.user_id isEqualToString:QXGlobal.shareGlobal.loginModel.user_id]) {
|
||||
return;
|
||||
}
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(roomOnlineNumberDidChangedIsAdd:)]) {
|
||||
[self.delegate roomOnlineNumberDidChangedIsAdd:YES];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case QXRoomMessageTypeQuit:{
|
||||
/// 用户退出房间
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(roomOnlineNumberDidChangedIsAdd:)]) {
|
||||
[self.delegate roomOnlineNumberDidChangedIsAdd:NO];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case QXRoomMessageTypeGift:{
|
||||
/// 收到礼物
|
||||
QXRoomChatListModel *model = [QXRoomChatListModel yy_modelWithJSON:msg.Text];
|
||||
model.messageType = QXRoomChatMessageTypeGift;
|
||||
[[QXGiftPlayerManager shareManager] displayFullEffectView:model.GiftInfo];
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(didRecieveGiftWithWithUserInfo:)]) {
|
||||
[self.delegate didRecieveGiftWithWithUserInfo:model.ToUserInfo];
|
||||
}
|
||||
if (model.text.length == 0) {
|
||||
return;
|
||||
}
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(didInsertMessge:)]) {
|
||||
[self.delegate didInsertMessge:model];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case QXRoomMessageTypeAplayPitModeDidChanged:{
|
||||
/// 上麦模式发生变化
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(aplayPitModeDidChanged:)]) {
|
||||
NSString* room_up_pit_type = [NSString stringWithFormat:@"%@",msg.Text[@"room_up_pit_type"]];
|
||||
[self.delegate aplayPitModeDidChanged:room_up_pit_type];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case QXRoomMessageTypeUpSeat:{
|
||||
/// 用户上麦
|
||||
QXRoomChatListModel *model = [QXRoomChatListModel yy_modelWithJSON:msg.Text];
|
||||
model.messageType = QXRoomChatMessageTypeSystem;
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(didInsertMessge:)]) {
|
||||
[self.delegate didInsertMessge:model];
|
||||
}
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(didUpDownSeatWithUser:isUpSeat:pit_number:)]) {
|
||||
NSString *pit_number = [NSString stringWithFormat:@"%@",msg.Text[@"pit_number"]];
|
||||
[self.delegate didUpDownSeatWithUser:model.FromUserInfo isUpSeat:YES pit_number:pit_number.integerValue];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case QXRoomMessageTypeDownSeat:{
|
||||
/// 用户下麦
|
||||
QXRoomChatListModel *model = [QXRoomChatListModel yy_modelWithJSON:msg.Text];
|
||||
model.messageType = QXRoomChatMessageTypeSystem;
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(didInsertMessge:)]) {
|
||||
[self.delegate didInsertMessge:model];
|
||||
}
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(didUpDownSeatWithUser:isUpSeat:pit_number:)]) {
|
||||
NSString *pit_number = [NSString stringWithFormat:@"%@",msg.Text[@"pit_number"]];
|
||||
[self.delegate didUpDownSeatWithUser:model.FromUserInfo isUpSeat:NO pit_number:pit_number.integerValue];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case QXRoomMessageTypeSwicthSong:{
|
||||
/// 点歌
|
||||
NSString *action = [NSString stringWithFormat:@"%@",msg.Text[@"action"]];
|
||||
if (action.intValue == 1) {
|
||||
QXRoomChatListModel *model = [QXRoomChatListModel yy_modelWithJSON:msg.Text];
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(applySongWaitAgreeWithUserNickname:)]) {
|
||||
[self.delegate applySongWaitAgreeWithUserNickname:model.FromUserInfo.nickname];
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (action.intValue == 2) {
|
||||
QXRoomChatListModel *model = [QXRoomChatListModel yy_modelWithJSON:msg.Text];
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(nextSongDidStartWithSongInfo:nextInfo:)]) {
|
||||
[self.delegate nextSongDidStartWithSongInfo:model.songInfo nextInfo:model.nextInfo];
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (action.intValue == 4) {
|
||||
QXRoomChatListModel *model = [QXRoomChatListModel yy_modelWithJSON:msg.Text];
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(applySongNoAgreeWithUserId:)]) {
|
||||
[self.delegate applySongNoAgreeWithUserId:model.FromUserInfo.user_id];
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (action.intValue == 3) {
|
||||
QXRoomChatListModel *model = [QXRoomChatListModel yy_modelWithJSON:msg.Text];
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(nextSongDidChangedWithNextSong:)]) {
|
||||
[self.delegate nextSongDidChangedWithNextSong:model.nextInfo];
|
||||
}
|
||||
return;
|
||||
}
|
||||
// @{
|
||||
// @"action":@"1", // 1有人发起点歌 主持人同意点歌走房间类型变化推送 2 切歌 3 下一首歌有变化 4 拒绝
|
||||
//
|
||||
// // 有人发起点歌时 前端收到推送为1 根据当前自己所在的麦位是否为主持麦,为主持麦时弹出有人申请点歌弹窗,其余人不处理该条推送
|
||||
//
|
||||
// @"songInfo":@{ // 仅在切歌时有该条消息
|
||||
// @"song_code":@"歌曲code",
|
||||
// @"song_name":@"歌曲名称",
|
||||
// @"singer":@"演唱者",
|
||||
// @"poster":@"歌曲封面",
|
||||
// @"duration":@"歌曲时长",
|
||||
//
|
||||
// @"user_id":@"点唱用户id",
|
||||
// @"nickname":@"点唱用户昵称",
|
||||
// @"avatar":@"点唱用户头像",
|
||||
// @"dress":@"点唱用户装扮",
|
||||
// @"charm":@"点唱用户魅力",
|
||||
// }
|
||||
// }
|
||||
}
|
||||
break;
|
||||
case QXRoomMessageTypeRoomTypeChanged:{
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(roomTypeDidChanged)]) {
|
||||
[self.delegate roomTypeDidChanged];
|
||||
}
|
||||
}
|
||||
break;;
|
||||
case QXRoomMessageTypeCharmRankList:{
|
||||
/// 点唱房魅力发生变化
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(songRoomCharmRankListDidChanged:)]) {
|
||||
NSArray *list = [NSArray yy_modelArrayWithClass:[QXRoomPitModel class] json:msg.Text[@"userCharmList"]];
|
||||
[self.delegate songRoomCharmRankListDidChanged:list];
|
||||
}
|
||||
}
|
||||
break;;
|
||||
case QXRoomMessageTypeRoomInfoChanged:{
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(roomInfoDidChanged:)]) {
|
||||
QXRoomInfoModel *model = [QXRoomInfoModel yy_modelWithJSON:msg.Text[@"RoomInfo"]];
|
||||
[self.delegate roomInfoDidChanged:model];
|
||||
}
|
||||
}
|
||||
break;;
|
||||
case QXRoomMessageTypeSetManage:{
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(roomSetManagerOrCompere:isManager:isAdd:)]) {
|
||||
QXRoomChatListModel *model = [QXRoomChatListModel yy_modelWithJSON:msg.Text];
|
||||
[self.delegate roomSetManagerOrCompere:model.FromUserInfo isManager:YES isAdd:YES];
|
||||
}
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(didInsertMessge:userId:)]) {
|
||||
QXRoomChatListModel *model = [QXRoomChatListModel yy_modelWithJSON:msg.Text];
|
||||
model.messageType = QXRoomChatMessageTypeSystem;
|
||||
[self.delegate didInsertMessge:model userId:model.FromUserInfo.user_id];
|
||||
}
|
||||
}
|
||||
break;;
|
||||
case QXRoomMessageTypeSetCompere:{
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(roomSetManagerOrCompere:isManager:isAdd:)]) {
|
||||
QXRoomChatListModel *model = [QXRoomChatListModel yy_modelWithJSON:msg.Text];
|
||||
[self.delegate roomSetManagerOrCompere:model.FromUserInfo isManager:NO isAdd:YES];
|
||||
}
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(didInsertMessge:userId:)]) {
|
||||
QXRoomChatListModel *model = [QXRoomChatListModel yy_modelWithJSON:msg.Text];
|
||||
model.messageType = QXRoomChatMessageTypeSystem;
|
||||
[self.delegate didInsertMessge:model userId:model.FromUserInfo.user_id];
|
||||
}
|
||||
}
|
||||
break;;
|
||||
case QXRoomMessageTypeCompereIsDelete:{
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(roomSetManagerOrCompere:isManager:isAdd:)]) {
|
||||
QXRoomChatListModel *model = [QXRoomChatListModel yy_modelWithJSON:msg.Text];
|
||||
[self.delegate roomSetManagerOrCompere:model.FromUserInfo isManager:NO isAdd:NO];
|
||||
}
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(didInsertMessge:userId:)]) {
|
||||
QXRoomChatListModel *model = [QXRoomChatListModel yy_modelWithJSON:msg.Text];
|
||||
model.messageType = QXRoomChatMessageTypeSystem;
|
||||
[self.delegate didInsertMessge:model userId:model.FromUserInfo.user_id];
|
||||
}
|
||||
}
|
||||
break;;
|
||||
case QXRoomMessageTypeManagerIsDelete:{
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(roomSetManagerOrCompere:isManager:isAdd:)]) {
|
||||
QXRoomChatListModel *model = [QXRoomChatListModel yy_modelWithJSON:msg.Text];
|
||||
[self.delegate roomSetManagerOrCompere:model.FromUserInfo isManager:YES isAdd:NO];
|
||||
}
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(didInsertMessge:userId:)]) {
|
||||
QXRoomChatListModel *model = [QXRoomChatListModel yy_modelWithJSON:msg.Text];
|
||||
model.messageType = QXRoomChatMessageTypeSystem;
|
||||
[self.delegate didInsertMessge:model userId:model.FromUserInfo.user_id];
|
||||
}
|
||||
}
|
||||
break;;
|
||||
|
||||
case QXRoomMessageTypeTakeOff:{
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(userDidTakeOffWithUserInfo:)]) {
|
||||
QXRoomChatListModel *model = [QXRoomChatListModel yy_modelWithJSON:msg.Text];
|
||||
[self.delegate userDidTakeOffWithUserInfo:model.FromUserInfo];
|
||||
}
|
||||
}
|
||||
break;;
|
||||
case QXRoomMessageTypeRoomClearCharm:{
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(roomClearCharm)]) {
|
||||
[self.delegate roomClearCharm];
|
||||
}
|
||||
}
|
||||
break;;
|
||||
case QXRoomMessageTypeSeatMute:{
|
||||
/// 房间麦位位被禁麦
|
||||
}
|
||||
break;;
|
||||
case QXRoomMessageTypeSeatLock:{
|
||||
/// 房间被锁麦
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(roomSeatStatusDidChangedIsLock:pit_number:)]) {
|
||||
NSString *is_lock = [NSString stringWithFormat:@"%@",msg.Text[@"is_lock"]];
|
||||
NSString *pit_number = [NSString stringWithFormat:@"%@",msg.Text[@"pit_number"]];
|
||||
[self.delegate roomSeatStatusDidChangedIsLock:is_lock pit_number:pit_number];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case QXRoomMessageTypeRoomUserMute:{
|
||||
/// 用户被禁言
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(userMuteStatusDidChanged:isMute:isMutePit:)]) {
|
||||
QXRoomChatListModel *model = [QXRoomChatListModel yy_modelWithJSON:msg.Text];
|
||||
NSString *is_mute = [NSString stringWithFormat:@"%@",msg.Text[@"is_mute"]];
|
||||
NSString *is_mute_pit = [NSString stringWithFormat:@"%@",msg.Text[@"is_mute_pit"]];
|
||||
[self.delegate userMuteStatusDidChanged:model.FromUserInfo isMute:is_mute isMutePit:is_mute_pit];
|
||||
}
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(didInsertMessge:userId:)]) {
|
||||
QXRoomChatListModel *model = [QXRoomChatListModel yy_modelWithJSON:msg.Text];
|
||||
model.messageType = QXRoomChatMessageTypeSystem;
|
||||
[self.delegate didInsertMessge:model userId:model.FromUserInfo.user_id];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case QXRoomMessageTypeRoomAuctionUpSeat:{
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(auctionUpSeatWithUserInfo:isUpSeat:)]) {
|
||||
NSString *type = [NSString stringWithFormat:@"%@",msg.Text[@"type"]];
|
||||
/// 1 上麦 2 下麦
|
||||
QXRoomChatListModel *model = [QXRoomChatListModel yy_modelWithJSON:msg.Text];
|
||||
[self.delegate auctionUpSeatWithUserInfo:model.FromUserInfo isUpSeat:type.intValue==1];
|
||||
}
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(didInsertMessge:)]) {
|
||||
QXRoomChatListModel *model = [QXRoomChatListModel yy_modelWithJSON:msg.Text];
|
||||
model.messageType = QXRoomChatMessageTypeSystem;
|
||||
[self.delegate didInsertMessge:model];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case QXRoomMessageTypeRoomAuctionStart:{
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(auctionStartOrEndIsStart:user:getUser:)]) {
|
||||
QXRoomAuctionUser *user = [QXRoomAuctionUser yy_modelWithJSON:msg.Text[@"auction_user"]];
|
||||
[self.delegate auctionStartOrEndIsStart:YES user:user getUser:nil];
|
||||
}
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(didInsertMessge:)]) {
|
||||
QXRoomChatListModel *model = [QXRoomChatListModel yy_modelWithJSON:msg.Text];
|
||||
model.messageType = QXRoomChatMessageTypeSystem;
|
||||
[self.delegate didInsertMessge:model];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case QXRoomMessageTypeRoomAuctionPitChanged:{
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(auctionListDidChanged:)]) {
|
||||
NSArray *list = [NSArray yy_modelArrayWithClass:[QXRoomPitModel class] json:msg.Text[@"auction_list"]];
|
||||
[self.delegate auctionListDidChanged:list];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case QXRoomMessageTypeRoomAuctionEnd:{
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(auctionStartOrEndIsStart:user:getUser:)]) {
|
||||
QXRoomAuctionUser *user = [QXRoomAuctionUser yy_modelWithJSON:msg.Text[@"auction_user"]];
|
||||
QXRoomAuctionUser *getUser = [QXRoomAuctionUser yy_modelWithJSON:msg.Text[@"recipient"]];
|
||||
[self.delegate auctionStartOrEndIsStart:NO user:user getUser:getUser];
|
||||
}
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(didInsertMessge:)]) {
|
||||
QXRoomChatListModel *model = [QXRoomChatListModel yy_modelWithJSON:msg.Text];
|
||||
model.messageType = QXRoomChatMessageTypeSystem;
|
||||
[self.delegate didInsertMessge:model];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case QXRoomMessageTypeRoomAuctionDelayTime:{
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(auctionTimeDelayWithEndTime:)]) {
|
||||
NSString *endTime = [NSString stringWithFormat:@"%@",msg.Text[@"duration"]];
|
||||
[self.delegate auctionTimeDelayWithEndTime:endTime];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case QXRoomMessageTypeRoomAuctionTypeDidChanged:{
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(auctionTypeDidChanged:)]) {
|
||||
NSString *endTime = [NSString stringWithFormat:@"%@",msg.Text[@"type"]];
|
||||
[self.delegate auctionTypeDidChanged:endTime];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case QXRoomMessageTypeRoomCabinRoomValueChanged:{
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(cabinRoomValueDidChanged:)]) {
|
||||
NSString *hot_value = [NSString stringWithFormat:@"%@",msg.Text[@"hot_value"]];
|
||||
[self.delegate cabinRoomValueDidChanged:hot_value];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case QXRoomMessageTypeRoomRecieveInvitePk:{
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(recievePKInviteWithSendRoomId:AcceptRoomId:PkId:message:)]) {
|
||||
NSString *SendRoomId = [NSString stringWithFormat:@"%@",msg.Text[@"SendRoomId"]];
|
||||
NSString *AcceptRoomId = [NSString stringWithFormat:@"%@",msg.Text[@"AcceptRoomId"]];
|
||||
NSString *PkId = [NSString stringWithFormat:@"%@",msg.Text[@"PkId"]];
|
||||
NSString *message = [NSString stringWithFormat:@"%@",msg.Text[@"text"]];
|
||||
[self.delegate recievePKInviteWithSendRoomId:SendRoomId AcceptRoomId:AcceptRoomId PkId:PkId message:message];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case QXRoomMessageTypeRoomPKAgreeOrRefuse:{
|
||||
NSString *user_id = [NSString stringWithFormat:@"%@",msg.Text[@"user_id"]];
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(agreeOrRefusePKIsAgree:user_id:room_id:pk_id:)]) {
|
||||
NSString *type = [NSString stringWithFormat:@"%@",msg.Text[@"type"]];
|
||||
NSString *room_id = [NSString stringWithFormat:@"%@",msg.Text[@"room_id"]];
|
||||
NSString *pk_id = [NSString stringWithFormat:@"%@",msg.Text[@"pk_id"]];
|
||||
[self.delegate agreeOrRefusePKIsAgree:type.intValue==1 user_id:user_id room_id:room_id pk_id:pk_id];
|
||||
}
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(didInsertMessge:userId:)]) {
|
||||
QXRoomChatListModel *model = [QXRoomChatListModel yy_modelWithJSON:msg.Text];
|
||||
model.messageType = QXRoomChatMessageTypeSystem;
|
||||
[self.delegate didInsertMessge:model userId:user_id];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case QXRoomMessageTypeRoomPKStart:{
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(pkStartWithPkEndTimes:pk_id:)]) {
|
||||
NSString *pk_end_times = [NSString stringWithFormat:@"%@",msg.Text[@"pk_end_times"]];
|
||||
NSString *pk_id = [NSString stringWithFormat:@"%@",msg.Text[@"pk_id"]];
|
||||
[self.delegate pkStartWithPkEndTimes:pk_end_times pk_id:pk_id];
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
case QXRoomMessageTypeRoomPKEnd:{
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(pkResultWithIsVictory:end_time:victory_name:victory_cover:defeated_name:defeated_cover:)]) {
|
||||
NSString *type = [NSString stringWithFormat:@"%@",msg.Text[@"type"]];
|
||||
NSString *victory_name = [NSString stringWithFormat:@"%@",msg.Text[@"victory_name"]];
|
||||
NSString *victory_cover = [NSString stringWithFormat:@"%@",msg.Text[@"victory_cover"]];
|
||||
NSString *defeated_name = [NSString stringWithFormat:@"%@",msg.Text[@"defeated_name"]];
|
||||
NSString *defeated_cover = [NSString stringWithFormat:@"%@",msg.Text[@"defeated_cover"]];
|
||||
NSString *end_time = [NSString stringWithFormat:@"%@",msg.Text[@"end_time"]];
|
||||
[self.delegate pkResultWithIsVictory:type.intValue end_time:end_time victory_name:victory_name victory_cover:victory_cover defeated_name:defeated_name defeated_cover:defeated_cover];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case QXRoomMessageTypeRoomPKDisconnect:{
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(pkDisConnect)]) {
|
||||
[self.delegate pkDisConnect];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case QXRoomMessageTypePKValueDidChanged:{
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(roomPKValueDidChangedWithRoomIdA:create_value_a:room_id_b:receive_value_b:)]) {
|
||||
NSString *room_id_a = [NSString stringWithFormat:@"%@",msg.Text[@"room_id_a"]];
|
||||
NSString *room_id_b = [NSString stringWithFormat:@"%@",msg.Text[@"room_id_b"]];
|
||||
NSString *create_value_a = [NSString stringWithFormat:@"%@",msg.Text[@"create_value_a"]];
|
||||
NSString *receive_value_b = [NSString stringWithFormat:@"%@",msg.Text[@"receive_value_b"]];
|
||||
[self.delegate roomPKValueDidChangedWithRoomIdA:room_id_a create_value_a:create_value_a room_id_b:room_id_b receive_value_b:receive_value_b];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case QXRoomMessageTypeRoomInLineNumber:{
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(aplayMicInLineNumberDidChanged:)]) {
|
||||
NSString *count = [NSString stringWithFormat:@"%@",msg.Text[@"count"]];
|
||||
[self.delegate aplayMicInLineNumberDidChanged:count];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case QXRoomMessageTypeRoomOnlineNumber:{
|
||||
NSString *online_number = [NSString stringWithFormat:@"%@",msg.Text[@"online_number"]];
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(roomOnlineNumberDidChangedOnlineNumber:)]) {
|
||||
[self.delegate roomOnlineNumberDidChangedOnlineNumber:online_number];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case QXRoomMessageTypeRoomPkNeedAgree:{
|
||||
QXRoomChatListModel *model = [QXRoomChatListModel yy_modelWithJSON:msg.Text];
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(roomPKRecieveLoserWantToRunRoadWithUserInfo:)]) {
|
||||
[self.delegate roomPKRecieveLoserWantToRunRoadWithUserInfo:model.FromUserInfo];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case QXRoomMessageTypeRoomBlindBox:{
|
||||
QXRoomChatListModel *model = [QXRoomChatListModel yy_modelWithJSON:msg.Text];
|
||||
model.messageType = QXRoomChatMessageTypeChat;
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(didInsertMessge:)]) {
|
||||
[self.delegate didInsertMessge:model];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case QXRoomMessageTypeRoomUserInfoDidChanged:{
|
||||
QXRoomChatListModel *model = [QXRoomChatListModel yy_modelWithJSON:msg.Text];
|
||||
model.messageType = QXRoomChatMessageTypeChat;
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(roomUserInfoDidChanged:)]) {
|
||||
[self.delegate roomUserInfoDidChanged:model.FromUserInfo];
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
/// 有人向我发起pk
|
||||
QXRoomMessageTypeRoomRecieveInvitePk = 1029,
|
||||
/// 拒绝或接受pk
|
||||
QXRoomMessageTypeRoomPKAgreeOrRefuse = 1030,
|
||||
/// pk开始
|
||||
QXRoomMessageTypeRoomPKStart = 1031,
|
||||
/// pk结束 惩罚时间
|
||||
QXRoomMessageTypeRoomPKEnd = 1032,
|
||||
/// pk断开
|
||||
QXRoomMessageTypeRoomPKDisconnect = 1033,
|
||||
|
||||
*/
|
||||
|
||||
|
||||
-(void)onRecvC2CTextMessage:(NSString *)msgID sender:(V2TIMUserInfo *)info text:(NSString *)text{
|
||||
|
||||
}
|
||||
-(void)onRecvC2CCustomMessage:(NSString *)msgID sender:(V2TIMUserInfo *)info customData:(NSData *)data{
|
||||
NSString *jsonStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
|
||||
QXRoomMessage *msg = [QXRoomMessage yy_modelWithJSON:jsonStr];
|
||||
NSInteger meesageType = msg.MsgType.integerValue;
|
||||
if (meesageType == QXRoomMessageTypeMuteRemoteAudio){
|
||||
NSString *json = [NSString stringWithFormat:@"%@",msg.Text[@"text"]];
|
||||
NSDictionary *dict = [json jsonValueDecoded];
|
||||
NSInteger is_mute = [[dict objectForKey:@"is_mute"] integerValue];
|
||||
QXRoomChatListModel *model = [QXRoomChatListModel yy_modelWithJSON:msg.Text];
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(pkMuteRemoteAudio:fromUserInfo:)]) {
|
||||
[self.delegate pkMuteRemoteAudio:is_mute==1 fromUserInfo:model.FromUserInfo];
|
||||
}
|
||||
}
|
||||
}
|
||||
-(void)onRecvGroupCustomMessage:(NSString *)msgID groupID:(NSString *)groupID sender:(V2TIMGroupMemberInfo *)info customData:(NSData *)data{
|
||||
NSString *jsonStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
|
||||
QXRoomMessage *msg = [QXRoomMessage yy_modelWithJSON:jsonStr];
|
||||
NSInteger meesageType = msg.MsgType.integerValue;
|
||||
if (meesageType == QXRoomMessageTypeText) {
|
||||
QXRoomChatListModel *model = [QXRoomChatListModel yy_modelWithJSON:msg.Text];
|
||||
model.messageType = QXRoomChatMessageTypeChat;
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(didInsertMessge:)]) {
|
||||
[self.delegate didInsertMessge:model];
|
||||
}
|
||||
}else if (meesageType == QXRoomMessageTypeClearMessage) {
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(didClearAllMessage)]) {
|
||||
[self.delegate didClearAllMessage];
|
||||
}
|
||||
}else if (meesageType == QXRoomMessageTypeSongLrc){
|
||||
NSString *json = [NSString stringWithFormat:@"%@",msg.Text[@"text"]];
|
||||
NSDictionary *dict = [json jsonValueDecoded];
|
||||
NSInteger positionMs = [[dict objectForKey:@"position"] integerValue];
|
||||
if (positionMs<=0) {
|
||||
return;
|
||||
}
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(roomSongLrcProgress:)]) {
|
||||
[self.delegate roomSongLrcProgress:positionMs];
|
||||
}
|
||||
QXLOG(@"收到歌词进度userID--%@---positionMs---%ld",info.userID,positionMs);
|
||||
}else if (meesageType == QXRoomMessageTypeMuteLocalAudio){
|
||||
NSString *json = [NSString stringWithFormat:@"%@",msg.Text[@"text"]];
|
||||
NSDictionary *dict = [json jsonValueDecoded];
|
||||
NSInteger is_mute = [[dict objectForKey:@"is_mute"] integerValue];
|
||||
QXUserHomeModel *userModel = [QXUserHomeModel yy_modelWithJSON:msg.Text[@"FromUserInfo"]];
|
||||
AgoraRtcAudioVolumeInfo *userInfo = [[AgoraRtcAudioVolumeInfo alloc] init];
|
||||
userInfo.uid = userModel.user_id.longLongValue;
|
||||
userInfo.volume = 0;
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:noticeUserSpeak object:userInfo];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
-(void)sendChatMessage:(NSString *)message messageType:(QXRoomMessageType)messageType needInsertMessage:(BOOL)needInsertMessage{
|
||||
NSDictionary *dict = @{
|
||||
@"RoomId":self.groupId?self.groupId:@"",
|
||||
@"MsgType":[NSNumber numberWithInteger:messageType],
|
||||
@"Text":@{
|
||||
@"FromUserInfo":@{
|
||||
@"user_id":[QXGlobal shareGlobal].loginModel.user_id?[QXGlobal shareGlobal].loginModel.user_id:@"",
|
||||
@"nickname":[QXGlobal shareGlobal].loginModel.nickname?[QXGlobal shareGlobal].loginModel.nickname:@"",
|
||||
@"avatar":[QXGlobal shareGlobal].loginModel.avatar?[QXGlobal shareGlobal].loginModel.avatar:@"",
|
||||
@"icon":[QXGlobal shareGlobal].loginModel.icon?[QXGlobal shareGlobal].loginModel.icon:@"",
|
||||
},
|
||||
@"text":message
|
||||
}
|
||||
};
|
||||
if (needInsertMessage) {
|
||||
QXRoomChatListModel *model = [[QXRoomChatListModel alloc] init];
|
||||
model.text = message;
|
||||
QXUserHomeModel *userInfo = [[QXUserHomeModel alloc] init];
|
||||
userInfo.avatar = [QXGlobal shareGlobal].loginModel.avatar;
|
||||
userInfo.nickname = [QXGlobal shareGlobal].loginModel.nickname;
|
||||
userInfo.user_id = [QXGlobal shareGlobal].loginModel.user_id;
|
||||
userInfo.icon = [QXGlobal shareGlobal].loginModel.icon;
|
||||
model.FromUserInfo = userInfo;
|
||||
model.messageType = QXRoomChatMessageTypeChat;
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(didInsertMessge:)]) {
|
||||
[self.delegate didInsertMessge:model];
|
||||
}
|
||||
}
|
||||
NSString *jsonStr = [dict jsonStringEncoded];
|
||||
NSData *data =[jsonStr dataUsingEncoding:NSUTF8StringEncoding];
|
||||
[[V2TIMManager sharedInstance] sendGroupCustomMessage:data to:self.groupId priority:V2TIM_PRIORITY_NORMAL succ:^{
|
||||
QXLOG(@"发送自定义消息成功");
|
||||
} fail:^(int code, NSString * _Nullable desc) {
|
||||
QXLOG(@"发送自定义消息失败");
|
||||
}];
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
-(void)sendC2CMessage:(NSString *)message messageType:(QXRoomMessageType)messageType userId:(NSString *)userId{
|
||||
NSDictionary *dict = @{
|
||||
@"RoomId":self.groupId?self.groupId:@"",
|
||||
@"MsgType":[NSNumber numberWithInteger:messageType],
|
||||
@"Text":@{
|
||||
@"FromUserInfo":@{
|
||||
@"user_id":[QXGlobal shareGlobal].loginModel.user_id?[QXGlobal shareGlobal].loginModel.user_id:@"",
|
||||
@"nickname":[QXGlobal shareGlobal].loginModel.nickname?[QXGlobal shareGlobal].loginModel.nickname:@"",
|
||||
@"avatar":[QXGlobal shareGlobal].loginModel.avatar?[QXGlobal shareGlobal].loginModel.avatar:@"",
|
||||
@"icon":[QXGlobal shareGlobal].loginModel.icon?[QXGlobal shareGlobal].loginModel.icon:@"",
|
||||
},
|
||||
@"text":message
|
||||
}
|
||||
};
|
||||
NSString *jsonStr = [dict jsonStringEncoded];
|
||||
NSData *data =[jsonStr dataUsingEncoding:NSUTF8StringEncoding];
|
||||
NSString*toUserId = [NSString stringWithFormat:@"u%@",userId];
|
||||
// [[V2TIMManager sharedInstance] sendC2CCustomMessage:data to:toUserId succ:^{
|
||||
//
|
||||
// } fail:^(int code, NSString * _Nullable desc) {
|
||||
//
|
||||
// }];
|
||||
V2TIMMessage *message1 = [[V2TIMManager sharedInstance] createCustomMessage:data];
|
||||
message1.isExcludedFromUnreadCount = YES;
|
||||
message1.isExcludedFromContentModeration = YES;
|
||||
[[V2TIMManager sharedInstance] sendMessage:message1 receiver:toUserId groupID:nil priority:(V2TIM_PRIORITY_HIGH) onlineUserOnly:YES offlinePushInfo:nil progress:^(uint32_t progress) {
|
||||
|
||||
} succ:^{
|
||||
|
||||
} fail:^(int code, NSString * _Nullable desc) {
|
||||
|
||||
}];
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation QXRoomMessage
|
||||
|
||||
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// QXDynamicDetailViewController.h
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/6/4.
|
||||
//
|
||||
|
||||
#import "QXBaseViewController.h"
|
||||
#import "QXDynamicModel.h"
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QXDynamicDetailViewController : QXBaseViewController
|
||||
@property (nonatomic,strong)QXDynamicModel *model;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
317
QXLive/Dynamic(语圈)/Controller/QXDynamicDetailViewController.m
Normal file
317
QXLive/Dynamic(语圈)/Controller/QXDynamicDetailViewController.m
Normal file
@@ -0,0 +1,317 @@
|
||||
//
|
||||
// QXDynamicDetailViewController.m
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/6/4.
|
||||
//
|
||||
|
||||
#import "QXDynamicDetailViewController.h"
|
||||
#import "QXDynamicListCell.h"
|
||||
#import "QXDynamicNetwork.h"
|
||||
#import "QXDynamicCommentCell.h"
|
||||
#import "QXDynamicCommentHeaderView.h"
|
||||
#import "QXDynamicCommentInputView.h"
|
||||
#import "QXAlertView.h"
|
||||
|
||||
@interface QXDynamicDetailViewController ()<UITableViewDelegate,UITableViewDataSource,QXDynamicCommentHeaderViewDelegate,QXDynamicCommentInputViewDelegate>
|
||||
@property (nonatomic,strong)UITableView *tableView;
|
||||
@property (nonatomic,strong)QXDynamicModel *detailModel;
|
||||
@property (nonatomic,strong)QXDynamicCommentModel *commentModel;
|
||||
|
||||
@property (nonatomic,strong)QXDynamicCommentInputView *commentView;
|
||||
|
||||
@end
|
||||
|
||||
@implementation QXDynamicDetailViewController
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
// Do any additional setup after loading the view.
|
||||
}
|
||||
-(void)viewWillAppear:(BOOL)animated{
|
||||
[super viewWillAppear:animated];
|
||||
[self.navigationController setNavigationBarHidden:NO animated:YES];
|
||||
}
|
||||
-(void)viewWillDisappear:(BOOL)animated{
|
||||
[super viewWillDisappear:animated];
|
||||
[self.commentView.textField resignFirstResponder];
|
||||
}
|
||||
-(void)setNavgationItems{
|
||||
[super setNavgationItems];
|
||||
self.navigationItem.title = QXText(@"动态详情");
|
||||
}
|
||||
-(void)initSubViews{
|
||||
[self.view addSubview:self.tableView];
|
||||
[self.view addSubview:self.commentView];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil];
|
||||
}
|
||||
|
||||
-(void)getData{
|
||||
self.page = 1;
|
||||
MJWeakSelf
|
||||
[QXDynamicNetwork dynamicPageWithId:self.model.id successBlock:^(QXDynamicModel * _Nonnull model) {
|
||||
weakSelf.detailModel = model;
|
||||
// [weakSelf.tableView reloadSection:0 withRowAnimation:(UITableViewRowAnimationNone)];
|
||||
[weakSelf.tableView reloadData];
|
||||
} failBlock:^(NSError * _Nonnull error, NSString * _Nonnull msg) {
|
||||
|
||||
}];
|
||||
[self getCommentListIsReload:YES];
|
||||
|
||||
}
|
||||
-(void)getCommentListIsReload:(BOOL)isReload{
|
||||
MJWeakSelf
|
||||
[QXDynamicNetwork commentListWithId:self.model.id page:self.page successBlock:^(QXDynamicCommentModel *model) {
|
||||
if (isReload) {
|
||||
[weakSelf.dataArray removeAllObjects];
|
||||
}
|
||||
[weakSelf.dataArray addObjectsFromArray:model.list];
|
||||
if (model.list.count == 0) {
|
||||
weakSelf.tableView.mj_footer.state = MJRefreshStateNoMoreData;
|
||||
}else{
|
||||
[weakSelf.tableView.mj_footer endRefreshing];
|
||||
}
|
||||
weakSelf.commentModel = model;
|
||||
weakSelf.detailModel.comment_num = model.total;
|
||||
[weakSelf.tableView reloadData];
|
||||
} failBlock:^(NSError * _Nonnull error, NSString * _Nonnull msg) {
|
||||
[weakSelf.tableView.mj_footer endRefreshing];
|
||||
}];
|
||||
}
|
||||
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
|
||||
return self.dataArray.count + 1;
|
||||
}
|
||||
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
|
||||
if (section == 0) {
|
||||
return 1;
|
||||
}else{
|
||||
QXDynamicCommentListModel *firsModel = self.dataArray[section-1];
|
||||
return firsModel.replies.count;
|
||||
}
|
||||
}
|
||||
|
||||
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
|
||||
MJWeakSelf
|
||||
if (indexPath.section == 0) {
|
||||
QXDynamicListCell *cell = [tableView dequeueReusableCellWithIdentifier:@"QXDynamicListCell" forIndexPath:indexPath];
|
||||
cell.selectionStyle = NO;
|
||||
cell.cellType = QXDynamicListCellDetail;
|
||||
cell.model = self.detailModel?self.detailModel:self.model;
|
||||
|
||||
cell.onDeleteBlock = ^(QXDynamicModel * _Nonnull model) {
|
||||
|
||||
};
|
||||
return cell;
|
||||
}else{
|
||||
QXDynamicCommentCell *cell = [QXDynamicCommentCell cellWithTableView:tableView];
|
||||
QXDynamicCommentListModel *firsModel = self.dataArray[indexPath.section-1];
|
||||
QXDynamicCommentListModel *model = firsModel.replies[indexPath.row];
|
||||
if (firsModel.replies.count == 1 && indexPath.row == 0) {
|
||||
cell.topCornerView.layer.cornerRadius = 12;
|
||||
cell.bottomCornerView.layer.cornerRadius = 12;
|
||||
}else{
|
||||
if (indexPath.row == 0) {
|
||||
cell.topCornerView.layer.cornerRadius = 12;
|
||||
cell.bottomCornerView.layer.cornerRadius = 0;
|
||||
}else if (indexPath.row == firsModel.replies.count-1){
|
||||
cell.topCornerView.layer.cornerRadius = 0;
|
||||
cell.bottomCornerView.layer.cornerRadius = 12;
|
||||
}else{
|
||||
cell.topCornerView.layer.cornerRadius = 0;
|
||||
cell.bottomCornerView.layer.cornerRadius = 0;
|
||||
}
|
||||
}
|
||||
cell.model = model;
|
||||
cell.longPressBlock = ^(QXDynamicCommentListModel * _Nonnull model) {
|
||||
UIAlertController *al = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:(UIAlertControllerStyleActionSheet)];
|
||||
if ([model.user_id isEqualToString:[QXGlobal shareGlobal].loginModel.user_id]) {
|
||||
[al addAction:[UIAlertAction actionWithTitle:QXText(@"删除") style:(UIAlertActionStyleDefault) handler:^(UIAlertAction * _Nonnull action) {
|
||||
[weakSelf didClickDeleteComment:model];
|
||||
}]];
|
||||
}
|
||||
[al addAction:[UIAlertAction actionWithTitle:QXText(@"复制") style:(UIAlertActionStyleDefault) handler:^(UIAlertAction * _Nonnull action) {
|
||||
UIPasteboard *p = [UIPasteboard generalPasteboard];
|
||||
p.string = [NSString stringWithFormat:@"%@", model.content];
|
||||
showToast(@"已复制");
|
||||
}]];
|
||||
[al addAction:[UIAlertAction actionWithTitle:QXText(@"取消") style:(UIAlertActionStyleCancel) handler:^(UIAlertAction * _Nonnull action) {
|
||||
|
||||
}]];
|
||||
[weakSelf presentViewController:al animated:YES completion:nil];
|
||||
};
|
||||
return cell;
|
||||
}
|
||||
}
|
||||
|
||||
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{
|
||||
if (section == 0) {
|
||||
return [UIView new];
|
||||
}else{
|
||||
MJWeakSelf
|
||||
QXDynamicCommentListModel *firsModel = self.dataArray[section-1];
|
||||
CGFloat height = [firsModel.content heightForFont:[UIFont systemFontOfSize:14] width:SCREEN_WIDTH-40-16*2-7];
|
||||
QXDynamicCommentHeaderView *header = [[QXDynamicCommentHeaderView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, height+12+40+7+3+9)];
|
||||
[header addTapBlock:^(id _Nonnull obj) {
|
||||
weakSelf.commentView.model = firsModel;
|
||||
weakSelf.commentView.textField.placeholder = [NSString stringWithFormat:@"回复:%@",firsModel.nickname];
|
||||
[weakSelf.commentView.textField becomeFirstResponder];
|
||||
}];
|
||||
header.delegate = self;
|
||||
header.model = firsModel;
|
||||
return header;
|
||||
}
|
||||
}
|
||||
|
||||
-(UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section{
|
||||
if (section == 0) {
|
||||
UIView *footer = [[UIView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, 64)];
|
||||
footer.backgroundColor = RGB16(0xF6F6F6);
|
||||
UIView *bgView = [[UIView alloc] initWithFrame:CGRectMake(0, 30, SCREEN_WIDTH, 34)];
|
||||
bgView.backgroundColor = [UIColor whiteColor];
|
||||
[bgView addRoundedCornersWithRadius:16 byRoundingCorners:(UIRectCornerTopLeft|UIRectCornerTopRight)];
|
||||
[footer addSubview:bgView];
|
||||
UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(16, 12, SCREEN_WIDTH-32, 22)];
|
||||
titleLabel.font = [UIFont boldSystemFontOfSize:16];
|
||||
titleLabel.textColor = [UIColor blackColor];
|
||||
[bgView addSubview:titleLabel];
|
||||
titleLabel.text = [NSString localizedStringWithFormat:QXText(@"全部评论(%@)"),self.commentModel.total?self.commentModel.total:@"0"];
|
||||
return footer;
|
||||
}else{
|
||||
return [UIView new];
|
||||
}
|
||||
}
|
||||
|
||||
-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{
|
||||
if (section == 0) {
|
||||
return 0;
|
||||
}else{
|
||||
QXDynamicCommentListModel *firsModel = self.dataArray[section-1];
|
||||
CGFloat height = [firsModel.content heightForFont:[UIFont systemFontOfSize:14] width:SCREEN_WIDTH-40-16*2-7];
|
||||
return height+12+40+7+3+9;
|
||||
}
|
||||
}
|
||||
-(CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{
|
||||
if (section == 0) {
|
||||
return 64;
|
||||
}else{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
|
||||
if (indexPath.section == 0) {
|
||||
return;
|
||||
}
|
||||
QXDynamicCommentListModel *firsModel = self.dataArray[indexPath.section-1];
|
||||
QXDynamicCommentListModel *model = firsModel.replies[indexPath.row];
|
||||
self.commentView.model = model;
|
||||
self.commentView.textField.placeholder = [NSString stringWithFormat:@"回复:%@",model.nickname];
|
||||
[self.commentView.textField becomeFirstResponder];
|
||||
}
|
||||
|
||||
-(void)didClickDeleteComment:(QXDynamicCommentListModel*)model{
|
||||
MJWeakSelf
|
||||
QXAlertView *al = [[QXAlertView alloc] initWithFrame:CGRectMake(0, 0, ScaleWidth(300), ScaleWidth(175))];
|
||||
al.type = QXAlertViewTypeDeleteComment;
|
||||
al.commitBlock = ^{
|
||||
[weakSelf deleteCommentWithModel:model];
|
||||
};
|
||||
[[QXGlobal shareGlobal] showView:al popType:(PopViewTypeTopToCenter) tapDismiss:NO finishBlock:^{
|
||||
|
||||
}];
|
||||
|
||||
}
|
||||
-(void)deleteCommentWithModel:(QXDynamicCommentListModel*)model{
|
||||
MJWeakSelf
|
||||
[QXDynamicNetwork deleteCommentWithCommentId:model.id successBlock:^(NSDictionary * _Nonnull dict) {
|
||||
weakSelf.page = 1;
|
||||
[weakSelf getCommentListIsReload:YES];
|
||||
} failBlock:^(NSError * _Nonnull error, NSString * _Nonnull msg) {
|
||||
|
||||
}];
|
||||
}
|
||||
|
||||
-(void)didClickReplyComment:(QXDynamicCommentListModel*)model{
|
||||
|
||||
}
|
||||
#pragma mark - 评论
|
||||
-(void)didClickSendWithText:(NSString*)text model:(nonnull QXDynamicCommentListModel *)model{
|
||||
if ([text stringByReplacingOccurrencesOfString:@" " withString:@""].length == 0) {
|
||||
showToast(@"请填写评论");
|
||||
return;
|
||||
}
|
||||
NSString *pid = @"";
|
||||
NSString *reply_to = @"";
|
||||
if (model) {
|
||||
pid = model.pid?model.pid:model.id;
|
||||
reply_to = model.user_id;
|
||||
}else{
|
||||
pid = @"0";
|
||||
reply_to = @"0";
|
||||
}
|
||||
self.commentView.textField.text = @"";
|
||||
[self.view endEditing:YES];
|
||||
MJWeakSelf
|
||||
[QXDynamicNetwork commentDynamicWithId:self.detailModel.id pid:pid reply_to:reply_to content:text successBlock:^(NSDictionary * _Nonnull dict) {
|
||||
weakSelf.page = 1;
|
||||
[weakSelf getCommentListIsReload:YES];
|
||||
} failBlock:^(NSError * _Nonnull error, NSString * _Nonnull msg) {
|
||||
|
||||
}];
|
||||
}
|
||||
- (void)keyboardWillHide:(NSNotification *)notification {
|
||||
self.commentView.model = nil;
|
||||
self.commentView.textField.placeholder = @"快来发表评论吧";
|
||||
[UIView animateWithDuration:0.3 animations:^{
|
||||
self.commentView.y = SCREEN_HEIGHT-TabbarContentHeight;
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)keyboardWillShow:(NSNotification *)notification {
|
||||
// CGRect keyboardFrame = [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
|
||||
// [UIView animateWithDuration:0.3 animations:^{
|
||||
// self.commentView.y = keyboardFrame.origin.y+TabbarContentHeight;
|
||||
// }];
|
||||
}
|
||||
|
||||
- (void)keyboardWillChangeFrame:(NSNotification *)notification {
|
||||
CGRect keyboardFrame = [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
|
||||
[UIView animateWithDuration:0.15 animations:^{
|
||||
self.commentView.y = keyboardFrame.origin.y-TabbarContentHeight;
|
||||
}];
|
||||
}
|
||||
|
||||
-(UITableView *)tableView{
|
||||
if (!_tableView) {
|
||||
self.tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, NavContentHeight, SCREEN_WIDTH, SCREEN_HEIGHT-NavContentHeight-TabbarContentHeight) style:UITableViewStyleGrouped];
|
||||
self.tableView.backgroundColor = [UIColor whiteColor];
|
||||
self.tableView.delegate = self;
|
||||
self.tableView.dataSource = self;
|
||||
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
|
||||
[self.tableView registerNib:[UINib nibWithNibName:@"QXDynamicListCell" bundle:nil] forCellReuseIdentifier:@"QXDynamicListCell"];
|
||||
self.tableView.rowHeight = UITableViewAutomaticDimension;
|
||||
self.tableView.estimatedRowHeight = 152;
|
||||
[self.tableView addRoundedCornersWithRadius:16];
|
||||
self.tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag;
|
||||
MJWeakSelf
|
||||
// _tableView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{
|
||||
// weakSelf.page = 1;
|
||||
// [weakSelf getDynamicList];
|
||||
// }];
|
||||
_tableView.mj_footer = [MJRefreshBackStateFooter footerWithRefreshingBlock:^{
|
||||
weakSelf.page++;
|
||||
[weakSelf getCommentListIsReload:NO];
|
||||
}];
|
||||
}
|
||||
return _tableView;
|
||||
}
|
||||
-(QXDynamicCommentInputView *)commentView{
|
||||
if (!_commentView) {
|
||||
_commentView = [[QXDynamicCommentInputView alloc] initWithFrame:CGRectMake(0, SCREEN_HEIGHT-TabbarContentHeight, SCREEN_WIDTH, TabbarContentHeight)];
|
||||
_commentView.delegate = self;
|
||||
}
|
||||
return _commentView;
|
||||
}
|
||||
@end
|
||||
16
QXLive/Dynamic(语圈)/Controller/QXDynamicViewController.h
Normal file
16
QXLive/Dynamic(语圈)/Controller/QXDynamicViewController.h
Normal file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// QXDynamicViewController.h
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/4/24.
|
||||
//
|
||||
|
||||
#import "QXBaseViewController.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QXDynamicViewController : QXBaseViewController
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
118
QXLive/Dynamic(语圈)/Controller/QXDynamicViewController.m
Normal file
118
QXLive/Dynamic(语圈)/Controller/QXDynamicViewController.m
Normal file
@@ -0,0 +1,118 @@
|
||||
//
|
||||
// QXDynamicViewController.m
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/4/24.
|
||||
//
|
||||
|
||||
#import "QXDynamicViewController.h"
|
||||
#import "QXPublishViewController.h"
|
||||
#import "JXCategoryView.h"
|
||||
#import "QXExpansionViewController.h"
|
||||
#import "QXFindViewController.h"
|
||||
|
||||
@interface QXDynamicViewController ()<JXCategoryViewDelegate,JXCategoryListContainerViewDelegate>
|
||||
@property (nonatomic,strong)UIButton *publishBtn;
|
||||
@property (nonatomic,strong)JXCategoryTitleView *categoryView;
|
||||
@property (nonatomic,strong)JXCategoryListContainerView *containerView;
|
||||
@property (nonatomic,strong)QXFindViewController *findVC;
|
||||
@end
|
||||
|
||||
@implementation QXDynamicViewController
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
// Do any additional setup after loading the view.
|
||||
}
|
||||
-(void)viewWillAppear:(BOOL)animated{
|
||||
[super viewWillAppear:animated];
|
||||
[self.navigationController setNavigationBarHidden:YES animated:YES];
|
||||
}
|
||||
- (void)initSubViews{
|
||||
// UILabel *tLabel = [[UILabel alloc] init];
|
||||
// tLabel.text = QXText(@"广场");
|
||||
// tLabel.font = [UIFont boldSystemFontOfSize:20];
|
||||
// [self.view addSubview:tLabel];
|
||||
// [tLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
// make.left.mas_equalTo(16);
|
||||
// make.top.mas_equalTo(kSafeAreaTop +10);
|
||||
// }];
|
||||
self.categoryView = [[JXCategoryTitleView alloc] initWithFrame:CGRectMake(14, kSafeAreaTop, 100, 44)];
|
||||
self.categoryView.delegate = self;
|
||||
// self.categoryView.titles = @[QXText(@"发现"),QXText(@"扩列")];
|
||||
self.categoryView.titles = @[QXText(@"扩列"),QXText(@"发现")];
|
||||
self.categoryView.titleSelectedColor = [UIColor colorWithHexString:@"#333333"];
|
||||
self.categoryView.titleColor = [UIColor colorWithHexString:@"#666666"];
|
||||
self.categoryView.cellWidth = 50;
|
||||
self.categoryView.contentEdgeInsetLeft = 0;
|
||||
self.categoryView.cellSpacing = 0;
|
||||
// self.categoryView.titleLabelZoomScale = 1.1;
|
||||
self.categoryView.titleLabelZoomEnabled = YES;
|
||||
self.categoryView.titleFont = [UIFont boldSystemFontOfSize:16];
|
||||
self.categoryView.titleSelectedFont = [UIFont boldSystemFontOfSize:18];
|
||||
self.categoryView.averageCellSpacingEnabled = NO;
|
||||
JXCategoryIndicatorImageView *indicatorView = [[JXCategoryIndicatorImageView alloc] init];
|
||||
indicatorView.indicatorImageView.image = [UIImage imageNamed:@"home_slider"];
|
||||
indicatorView.indicatorImageViewSize = CGSizeMake(35, 8);
|
||||
indicatorView.verticalMargin = 11;
|
||||
self.categoryView.indicators = @[indicatorView];
|
||||
self.containerView = [[JXCategoryListContainerView alloc] initWithType:(JXCategoryListContainerType_ScrollView) delegate:self];
|
||||
self.containerView.frame = CGRectMake(0, self.categoryView.bottom, SCREEN_WIDTH, SCREEN_HEIGHT-self.categoryView.bottom);
|
||||
// self.containerView.scrollView.scrollEnabled = NO;
|
||||
[self.view addSubview:self.categoryView];
|
||||
[self.view addSubview:self.containerView];
|
||||
self.categoryView.listContainer = self.containerView;
|
||||
|
||||
[self.view addSubview:self.publishBtn];
|
||||
|
||||
}
|
||||
|
||||
-(NSInteger)numberOfListsInlistContainerView:(JXCategoryListContainerView *)listContainerView{
|
||||
return 2;
|
||||
}
|
||||
-(id<JXCategoryListContentViewDelegate>)listContainerView:(JXCategoryListContainerView *)listContainerView initListForIndex:(NSInteger)index{
|
||||
// if (index == 0) {
|
||||
// QXFindViewController *vc = [[QXFindViewController alloc] init];
|
||||
// self.findVC = vc;
|
||||
// return vc;
|
||||
// }else{
|
||||
// QXExpansionViewController *vc = [[QXExpansionViewController alloc] init];
|
||||
// return vc;
|
||||
// }
|
||||
if (index == 0) {
|
||||
QXExpansionViewController *vc = [[QXExpansionViewController alloc] init];
|
||||
return vc;
|
||||
}else{
|
||||
QXFindViewController *vc = [[QXFindViewController alloc] init];
|
||||
self.findVC = vc;
|
||||
return vc;
|
||||
}
|
||||
}
|
||||
-(void)categoryView:(JXCategoryBaseView *)categoryView didSelectedItemAtIndex:(NSInteger)index{
|
||||
self.publishBtn.hidden = !(index==1);
|
||||
}
|
||||
#pragma mark - action
|
||||
-(void)pulishAction{
|
||||
if (!QXGlobal.shareGlobal.isLogin) {
|
||||
[[QXGlobal shareGlobal] logOut];
|
||||
return;
|
||||
}
|
||||
QXPublishViewController *vc = [[QXPublishViewController alloc] init];
|
||||
MJWeakSelf
|
||||
vc.publishFinishBlock = ^{
|
||||
[weakSelf.findVC.tableView.mj_header beginRefreshing];
|
||||
[weakSelf.findVC getTopicList];
|
||||
};
|
||||
[self.navigationController pushViewController:vc animated:YES];
|
||||
}
|
||||
-(UIButton *)publishBtn{
|
||||
if (!_publishBtn) {
|
||||
_publishBtn = [[UIButton alloc] initWithFrame:CGRectMake(SCREEN_WIDTH-44-8, kSafeAreaTop, 44, 44)];
|
||||
[_publishBtn setImage:[UIImage imageNamed:@"publish_icon"] forState:UIControlStateNormal];
|
||||
[_publishBtn setImage:[UIImage imageNamed:@"publish_icon"] forState:UIControlStateHighlighted];
|
||||
[_publishBtn addTarget:self action:@selector(pulishAction) forControlEvents:UIControlEventTouchUpInside];
|
||||
_publishBtn.hidden = YES;
|
||||
}
|
||||
return _publishBtn;
|
||||
}
|
||||
@end
|
||||
16
QXLive/Dynamic(语圈)/Controller/QXExpansionViewController.h
Normal file
16
QXLive/Dynamic(语圈)/Controller/QXExpansionViewController.h
Normal file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// QXExpansionViewController.h
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/5/27.
|
||||
//
|
||||
|
||||
#import "QXBaseViewController.h"
|
||||
#import "JXCategoryView.h"
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QXExpansionViewController : QXBaseViewController<JXCategoryListContentViewDelegate>
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
195
QXLive/Dynamic(语圈)/Controller/QXExpansionViewController.m
Normal file
195
QXLive/Dynamic(语圈)/Controller/QXExpansionViewController.m
Normal file
@@ -0,0 +1,195 @@
|
||||
//
|
||||
// QXExpansionViewController.m
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/5/27.
|
||||
//
|
||||
|
||||
#import "QXExpansionViewController.h"
|
||||
#import "QXExpansionCell.h"
|
||||
#import "UIButton+QX.h"
|
||||
#import "QXMenuPopView.h"
|
||||
#import "QXDynamicNetwork.h"
|
||||
#import "QXUserHomePageViewController.h"
|
||||
#import "QXExpansionAppStoreView.h"
|
||||
|
||||
@interface QXExpansionViewController ()<UITableViewDelegate,UITableViewDataSource,QXMenuPopViewDelegate>
|
||||
@property (strong, nonatomic) UILabel *titleLabel;
|
||||
@property (strong, nonatomic) UIButton *sortBtn;
|
||||
@property (strong, nonatomic) UITableView *tableView;
|
||||
@property (strong, nonatomic) NSString *type;
|
||||
@property (strong, nonatomic) QXExpansionAppStoreView *appStoreView;
|
||||
@end
|
||||
|
||||
@implementation QXExpansionViewController
|
||||
-(UIView *)listView{
|
||||
return self.view;
|
||||
}
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
// Do any additional setup after loading the view.
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(loginSuccess) name:noticeUserLogin object:nil];
|
||||
}
|
||||
- (void)initSubViews{
|
||||
self.page = 1;
|
||||
self.bgImageHidden = YES;
|
||||
self.titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(16, 12, 100, 24)];
|
||||
self.titleLabel.font = [UIFont systemFontOfSize:16];
|
||||
self.titleLabel.textColor = QXConfig.textColor;
|
||||
self.titleLabel.text = QXText(@"扩列交友");
|
||||
[self.view addSubview:self.titleLabel];
|
||||
|
||||
self.sortBtn = [[UIButton alloc] initWithFrame:CGRectMake(SCREEN_WIDTH-75-13, 0, 75, 48)];
|
||||
[self.sortBtn setImage:[[UIImage imageNamed:@"arrow_bottom"] imageByTintColor:QXConfig.textColor] forState:(UIControlStateNormal)];
|
||||
if ([QXGlobal shareGlobal].loginModel.sex.integerValue == 1) {
|
||||
[self.sortBtn setTitle:QXText(@"只看女生") forState:(UIControlStateNormal)];
|
||||
self.type = @"2";
|
||||
}else{
|
||||
[self.sortBtn setTitle:QXText(@"只看男生") forState:(UIControlStateNormal)];
|
||||
self.type = @"1";
|
||||
}
|
||||
[self.sortBtn setTitleColor:QXConfig.textColor forState:(UIControlStateNormal)];
|
||||
self.sortBtn.titleLabel.font = [UIFont systemFontOfSize:12];
|
||||
[self.sortBtn qx_layoutButtonNOSizeToFitWithEdgeInsetsStyle:(QXButtonEdgeInsetsStyleRight) imageTitleSpace:3];
|
||||
[self.sortBtn addTarget:self action:@selector(sortAction) forControlEvents:(UIControlEventTouchUpInside)];
|
||||
[self.view addSubview:self.sortBtn];
|
||||
[self.view addSubview:self.tableView];
|
||||
self.appStoreView.hidden = YES;
|
||||
[self.view addSubview:self.appStoreView];
|
||||
MJWeakSelf
|
||||
self.appStoreView.userBlock = ^(QXUserHomeModel * _Nonnull user) {
|
||||
if (!QXGlobal.shareGlobal.isLogin) {
|
||||
[[QXGlobal shareGlobal] logOut];
|
||||
return;
|
||||
}
|
||||
if (user == nil) {
|
||||
return;
|
||||
}
|
||||
QXUserHomePageViewController *vc = [[QXUserHomePageViewController alloc] init];
|
||||
vc.user_id = user.user_id;
|
||||
[weakSelf.navigationController pushViewController:vc animated:YES];
|
||||
};
|
||||
}
|
||||
-(void)loginSuccess{
|
||||
[self getData];
|
||||
}
|
||||
- (void)getData{
|
||||
MJWeakSelf
|
||||
[QXDynamicNetwork expansionListWithPage:self.page type:self.type successBlock:^(NSArray<QXUserHomeModel *> * _Nonnull list, BOOL isAppStore) {
|
||||
if (weakSelf.page == 1) {
|
||||
[weakSelf.dataArray removeAllObjects];
|
||||
}
|
||||
if (isAppStore) {
|
||||
self.appStoreView.hidden = NO;
|
||||
self.tableView.hidden = YES;
|
||||
self.appStoreView.users = list;
|
||||
}else{
|
||||
self.tableView.hidden = NO;
|
||||
self.appStoreView.hidden = YES;
|
||||
}
|
||||
[weakSelf.dataArray addObjectsFromArray:list];
|
||||
[weakSelf.tableView.mj_header endRefreshing];
|
||||
if (list.count == 0) {
|
||||
weakSelf.tableView.mj_footer.state = MJRefreshStateNoMoreData;
|
||||
}else{
|
||||
[weakSelf.tableView.mj_footer endRefreshing];
|
||||
}
|
||||
[self.tableView reloadData];
|
||||
} failBlock:^(NSError * _Nonnull error, NSString * _Nonnull msg) {
|
||||
[weakSelf.tableView.mj_header endRefreshing];
|
||||
[weakSelf.tableView.mj_footer endRefreshing];
|
||||
}];
|
||||
}
|
||||
|
||||
-(void)sortAction{
|
||||
QXMenuPopView *menuView = [[QXMenuPopView alloc] initWithPoint:CGPointMake(self.sortBtn.centerX, NavContentHeight+self.sortBtn.bottom-10)];
|
||||
menuView.dataArray = @[QXText(@"只看女生"),QXText(@"只看男生"),QXText(@"查看全部")];
|
||||
menuView.delegate = self;
|
||||
[menuView showInView:KEYWINDOW];
|
||||
}
|
||||
|
||||
-(void)didSelectedIndex:(NSInteger)index menuTitle:(NSString *)menuTitle{
|
||||
QXLOG(@"选择了%@",menuTitle);
|
||||
if ([menuTitle isEqualToString:QXText(@"只看女生")]) {
|
||||
self.page = 1;
|
||||
self.type = @"2";
|
||||
[self getData];
|
||||
}else if ([menuTitle isEqualToString:QXText(@"只看男生")]) {
|
||||
self.page = 1;
|
||||
self.type = @"1";
|
||||
[self getData];
|
||||
}else{
|
||||
self.page = 1;
|
||||
self.type = @"0";
|
||||
[self getData];
|
||||
}
|
||||
[self.sortBtn setTitle:menuTitle forState:(UIControlStateNormal)];
|
||||
}
|
||||
|
||||
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
|
||||
return self.dataArray.count;
|
||||
}
|
||||
|
||||
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
|
||||
QXExpansionCell *cell = [tableView dequeueReusableCellWithIdentifier:@"QXExpansionCell" forIndexPath:indexPath];
|
||||
cell.selectionStyle = NO;
|
||||
QXUserHomeModel *model = self.dataArray[indexPath.row];
|
||||
cell.model = model;
|
||||
return cell;
|
||||
}
|
||||
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
|
||||
QXUserHomeModel *model = self.dataArray[indexPath.row];
|
||||
NSArray *imgArr;
|
||||
if (model.home_bgimages.length > 0) {
|
||||
imgArr = [model.home_bgimages componentsSeparatedByString:@","];
|
||||
}
|
||||
// NSArray *
|
||||
CGFloat itemH = 94;
|
||||
if (imgArr.count == 1) {
|
||||
itemH = (SCREEN_WIDTH-15-15-15)/2 + 94;
|
||||
}else if(imgArr.count > 1){
|
||||
if (imgArr.count > 3) {
|
||||
itemH = (SCREEN_WIDTH-16*2-12*2-10*2)/3*2+10+94;
|
||||
}else{
|
||||
itemH = (SCREEN_WIDTH-16*2-12*2-10*2)/3+94;
|
||||
}
|
||||
}else{
|
||||
itemH = 94;
|
||||
}
|
||||
return itemH;
|
||||
}
|
||||
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
|
||||
QXUserHomeModel *model = self.dataArray[indexPath.row];
|
||||
QXUserHomePageViewController *vc = [[QXUserHomePageViewController alloc] init];
|
||||
vc.user_id = model.user_id;
|
||||
[self.navigationController pushViewController:vc animated:YES];
|
||||
}
|
||||
-(UITableView *)tableView{
|
||||
if (!_tableView) {
|
||||
self.tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, self.titleLabel.bottom+12, SCREEN_WIDTH, self.view.height-TabbarContentHeight-self.titleLabel.bottom-12) style:UITableViewStylePlain];
|
||||
self.tableView.backgroundColor = [UIColor clearColor];
|
||||
self.tableView.delegate = self;
|
||||
self.tableView.dataSource = self;
|
||||
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
|
||||
[self.tableView registerNib:[UINib nibWithNibName:@"QXExpansionCell" bundle:nil] forCellReuseIdentifier:@"QXExpansionCell"];
|
||||
self.tableView.estimatedRowHeight = 94;
|
||||
MJWeakSelf
|
||||
_tableView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{
|
||||
weakSelf.page = 1;
|
||||
[weakSelf getData];
|
||||
}];
|
||||
_tableView.mj_footer = [MJRefreshBackNormalFooter footerWithRefreshingBlock:^{
|
||||
weakSelf.page++;
|
||||
[weakSelf getData];
|
||||
}];
|
||||
self.tableView.hidden = NO;
|
||||
}
|
||||
return _tableView;
|
||||
}
|
||||
-(QXExpansionAppStoreView *)appStoreView{
|
||||
if (!_appStoreView) {
|
||||
_appStoreView = [[QXExpansionAppStoreView alloc] initWithFrame:self.tableView.bounds];
|
||||
}
|
||||
return _appStoreView;
|
||||
}
|
||||
@end
|
||||
17
QXLive/Dynamic(语圈)/Controller/QXFindViewController.h
Normal file
17
QXLive/Dynamic(语圈)/Controller/QXFindViewController.h
Normal file
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// QXFindViewController.h
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/5/27.
|
||||
//
|
||||
|
||||
#import "QXBaseViewController.h"
|
||||
#import "JXCategoryView.h"
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QXFindViewController : QXBaseViewController<JXCategoryListContentViewDelegate>
|
||||
@property (strong, nonatomic) UITableView *tableView;
|
||||
-(void)getTopicList;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
223
QXLive/Dynamic(语圈)/Controller/QXFindViewController.m
Normal file
223
QXLive/Dynamic(语圈)/Controller/QXFindViewController.m
Normal file
@@ -0,0 +1,223 @@
|
||||
//
|
||||
// QXFindViewController.m
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/5/27.
|
||||
//
|
||||
|
||||
#import "QXFindViewController.h"
|
||||
#import "QXDynamicTopicCell.h"
|
||||
#import "GKPageControl.h"
|
||||
#import "QXDynamicListCell.h"
|
||||
#import "QXDynamicNetwork.h"
|
||||
#import "QXToppicDynamicViewController.h"
|
||||
#import "QXDynamicDetailViewController.h"
|
||||
|
||||
@interface QXFindViewController ()<UITableViewDelegate,UITableViewDataSource,UICollectionViewDelegate,UICollectionViewDataSource>
|
||||
|
||||
@property (strong, nonatomic) UICollectionView *collectionView;
|
||||
@property (strong, nonatomic) NSMutableArray *hotTopicArray;
|
||||
@property (nonatomic,strong)GKPageControl *pageControl;
|
||||
@end
|
||||
|
||||
@implementation QXFindViewController
|
||||
-(UIView *)listView{
|
||||
return self.view;
|
||||
}
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
// Do any additional setup after loading the view.
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(loginSuccess) name:noticeUserLogin object:nil];
|
||||
}
|
||||
- (void)initSubViews{
|
||||
self.page = 1;
|
||||
self.bgImageHidden = YES;
|
||||
[self.view addSubview:self.collectionView];
|
||||
[self.view addSubview:self.pageControl];
|
||||
[self.view addSubview:self.tableView];
|
||||
[self getTopicList];
|
||||
[self getDynamicList];
|
||||
}
|
||||
-(void)getTopicList{
|
||||
MJWeakSelf
|
||||
[QXDynamicNetwork getTopicListWithPage:self.page isTopTopic:YES successBlock:^(NSArray<QXTopicModel *> * _Nonnull hotos) {
|
||||
if (weakSelf.page == 1) {
|
||||
[weakSelf.hotTopicArray removeAllObjects];
|
||||
}
|
||||
[weakSelf.hotTopicArray addObjectsFromArray:hotos];
|
||||
if (hotos.count == 0) {
|
||||
weakSelf.tableView.mj_footer.state = MJRefreshStateNoMoreData;
|
||||
}else{
|
||||
[weakSelf.tableView.mj_footer endRefreshing];
|
||||
}
|
||||
if (weakSelf.hotTopicArray.count %4 >0) {
|
||||
weakSelf.pageControl.numberOfPages = self.hotTopicArray.count/4+1;
|
||||
}else{
|
||||
weakSelf.pageControl.numberOfPages = self.hotTopicArray.count/4;
|
||||
}
|
||||
weakSelf.pageControl.currentPage = 0;
|
||||
[self.collectionView reloadData];
|
||||
} failBlock:^(NSError * _Nonnull error, NSString * _Nonnull msg) {
|
||||
}];
|
||||
|
||||
}
|
||||
-(void)loginSuccess{
|
||||
[self getTopicList];
|
||||
[self getDynamicList];
|
||||
}
|
||||
-(void)getDynamicList{
|
||||
MJWeakSelf
|
||||
[QXDynamicNetwork getDynamicListWithPage:self.page successBlock:^(NSArray<QXDynamicModel *> * _Nonnull hotos) {
|
||||
if (weakSelf.page == 1) {
|
||||
[weakSelf.dataArray removeAllObjects];
|
||||
}
|
||||
[weakSelf.dataArray addObjectsFromArray:hotos];
|
||||
[weakSelf.tableView.mj_header endRefreshing];
|
||||
if (hotos.count == 0) {
|
||||
weakSelf.tableView.mj_footer.state = MJRefreshStateNoMoreData;
|
||||
}else{
|
||||
[weakSelf.tableView.mj_footer endRefreshing];
|
||||
}
|
||||
[self.tableView reloadData];
|
||||
} failBlock:^(NSError * _Nonnull error, NSString * _Nonnull msg) {
|
||||
[weakSelf.tableView.mj_header endRefreshing];
|
||||
[weakSelf.tableView.mj_footer endRefreshing];
|
||||
}];
|
||||
}
|
||||
#pragma mark - UITableViewDelegate,UITableViewDataSource
|
||||
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
|
||||
return self.dataArray.count;
|
||||
}
|
||||
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
|
||||
QXDynamicListCell *cell = [tableView dequeueReusableCellWithIdentifier:@"QXDynamicListCell" forIndexPath:indexPath];
|
||||
cell.selectionStyle = NO;
|
||||
cell.cellType = QXDynamicListCellDynamic;
|
||||
cell.model = self.dataArray[indexPath.row];
|
||||
// SPTrendListModel *model = self.dataArray[indexPath.row];
|
||||
// cell.model = model;
|
||||
MJWeakSelf
|
||||
cell.onDeleteBlock = ^(QXDynamicModel * _Nonnull model) {
|
||||
[weakSelf.dataArray removeObject:model];
|
||||
[weakSelf.tableView reloadSection:indexPath.section withRowAnimation:(UITableViewRowAnimationAutomatic)];
|
||||
};
|
||||
return cell;
|
||||
}
|
||||
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
|
||||
if (!QXGlobal.shareGlobal.isLogin) {
|
||||
[[QXGlobal shareGlobal] logOut];
|
||||
return;
|
||||
}
|
||||
QXDynamicModel *model = self.dataArray[indexPath.row];
|
||||
QXDynamicDetailViewController *vc = [[QXDynamicDetailViewController alloc] init];
|
||||
vc.model = model;
|
||||
[self.navigationController pushViewController:vc animated:YES];
|
||||
}
|
||||
|
||||
#pragma mark - UICollectionViewDelegate,UICollectionViewDataSource
|
||||
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
|
||||
return self.hotTopicArray.count;
|
||||
}
|
||||
-(__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
|
||||
QXDynamicTopicCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"QXDynamicTopicCell" forIndexPath:indexPath];
|
||||
QXTopicModel *model = self.hotTopicArray[indexPath.row];
|
||||
cell.model = model;
|
||||
return cell;
|
||||
}
|
||||
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
|
||||
if (!QXGlobal.shareGlobal.isLogin) {
|
||||
[[QXGlobal shareGlobal] logOut];
|
||||
return;
|
||||
}
|
||||
QXTopicModel *model = self.hotTopicArray[indexPath.row];
|
||||
QXToppicDynamicViewController *vc = [[QXToppicDynamicViewController alloc] init];
|
||||
vc.model = model;
|
||||
[self.navigationController pushViewController:vc animated:YES];
|
||||
}
|
||||
-(void)scrollViewDidScroll:(UIScrollView *)scrollView{
|
||||
if ([scrollView isKindOfClass:[UICollectionView class]]) {
|
||||
long offsetX = (long)scrollView.contentOffset.x;
|
||||
int width = SCREEN_WIDTH-32;
|
||||
int remainder = offsetX % width;
|
||||
NSInteger index;
|
||||
if (remainder>(width)/2) {
|
||||
index = offsetX/width+1;
|
||||
}else{
|
||||
index = offsetX/width;
|
||||
}
|
||||
self.pageControl.currentPage = index;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
-(UITableView *)tableView{
|
||||
if (!_tableView) {
|
||||
self.tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, self.pageControl.bottom+5, SCREEN_WIDTH, SCREEN_HEIGHT-TabbarContentHeight-self.pageControl.bottom-5-13) style:UITableViewStylePlain];
|
||||
self.tableView.backgroundColor = [UIColor clearColor];
|
||||
self.tableView.delegate = self;
|
||||
self.tableView.dataSource = self;
|
||||
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
|
||||
[self.tableView registerNib:[UINib nibWithNibName:@"QXDynamicListCell" bundle:nil] forCellReuseIdentifier:@"QXDynamicListCell"];
|
||||
self.tableView.rowHeight = UITableViewAutomaticDimension;
|
||||
// self.tableView.estimatedRowHeight = 0;
|
||||
MJWeakSelf
|
||||
_tableView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{
|
||||
weakSelf.page = 1;
|
||||
[weakSelf getDynamicList];
|
||||
}];
|
||||
_tableView.mj_footer = [MJRefreshBackStateFooter footerWithRefreshingBlock:^{
|
||||
weakSelf.page++;
|
||||
[weakSelf getDynamicList];
|
||||
}];
|
||||
}
|
||||
return _tableView;
|
||||
}
|
||||
-(UICollectionView *)collectionView{
|
||||
if (!_collectionView) {
|
||||
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
|
||||
layout.minimumLineSpacing = 16;
|
||||
layout.minimumInteritemSpacing = 16;
|
||||
layout.sectionInset = UIEdgeInsetsMake(0, 0, 0, 0);
|
||||
layout.itemSize = CGSizeMake((SCREEN_WIDTH-16*3)/2, 45);
|
||||
layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
|
||||
_collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(16, 13, SCREEN_WIDTH-32, 45*2+16) collectionViewLayout:layout];
|
||||
_collectionView.delegate = self;
|
||||
_collectionView.dataSource = self;
|
||||
_collectionView.pagingEnabled = YES;
|
||||
_collectionView.bounces = NO;
|
||||
_collectionView.backgroundColor = [UIColor clearColor];
|
||||
_collectionView.showsHorizontalScrollIndicator = NO;
|
||||
[_collectionView registerNib:[UINib nibWithNibName:@"QXDynamicTopicCell" bundle:[NSBundle mainBundle]] forCellWithReuseIdentifier:@"QXDynamicTopicCell"];
|
||||
}
|
||||
return _collectionView;
|
||||
}
|
||||
-(GKPageControl *)pageControl{
|
||||
if (!_pageControl) {
|
||||
_pageControl = [[GKPageControl alloc] initWithFrame:CGRectMake(0, self.collectionView.bottom+7, SCREEN_WIDTH, 8)];
|
||||
_pageControl.style = GKPageControlStyleRectangle;
|
||||
_pageControl.dotWidth = 15;
|
||||
_pageControl.dotHeight = 5;
|
||||
_pageControl.dotMargin = 2;
|
||||
_pageControl.pageIndicatorTintColor = UIColor.whiteColor;
|
||||
_pageControl.currentPageIndicatorTintColor = QXConfig.textColor;
|
||||
}
|
||||
return _pageControl;
|
||||
}
|
||||
-(NSMutableArray *)hotTopicArray{
|
||||
if (!_hotTopicArray) {
|
||||
_hotTopicArray = [NSMutableArray array];
|
||||
}
|
||||
return _hotTopicArray;
|
||||
}
|
||||
|
||||
/*
|
||||
#pragma mark - Navigation
|
||||
|
||||
// In a storyboard-based application, you will often want to do a little preparation before navigation
|
||||
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
|
||||
// Get the new view controller using [segue destinationViewController].
|
||||
// Pass the selected object to the new view controller.
|
||||
}
|
||||
*/
|
||||
|
||||
@end
|
||||
16
QXLive/Dynamic(语圈)/Controller/QXPublishViewController.h
Normal file
16
QXLive/Dynamic(语圈)/Controller/QXPublishViewController.h
Normal file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// QXPublishViewController.h
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/5/27.
|
||||
//
|
||||
|
||||
#import "QXBaseViewController.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QXPublishViewController : QXBaseViewController
|
||||
@property(nonatomic,copy)void(^publishFinishBlock)(void);
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
139
QXLive/Dynamic(语圈)/Controller/QXPublishViewController.m
Normal file
139
QXLive/Dynamic(语圈)/Controller/QXPublishViewController.m
Normal file
@@ -0,0 +1,139 @@
|
||||
//
|
||||
// QXPublishViewController.m
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/5/27.
|
||||
//
|
||||
|
||||
#import "QXPublishViewController.h"
|
||||
#import "QXTextView.h"
|
||||
#import "QXUserInfoEditFooterView.h"
|
||||
#import "QXSelectedTopicView.h"
|
||||
#import "QXTopicListView.h"
|
||||
#import "QXLocationManager.h"
|
||||
#import "QXDynamicNetwork.h"
|
||||
|
||||
@interface QXPublishViewController ()<QXUserInfoImageCellDelegate,QXLocationManagerDelegate>
|
||||
@property (nonatomic,strong)QXTextView *textView;
|
||||
@property (nonatomic,strong)QXSelectedTopicView *topicView;
|
||||
@property (nonatomic,strong)QXUserInfoEditFooterView *pickerView;
|
||||
@property (nonatomic,strong)NSString *images;
|
||||
@property (nonatomic,strong)NSString *city;
|
||||
@property (nonatomic,strong)UIButton* commitBtn;
|
||||
@end
|
||||
|
||||
@implementation QXPublishViewController
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
// Do any additional setup after loading the view.
|
||||
}
|
||||
-(void)viewWillAppear:(BOOL)animated{
|
||||
[super viewWillAppear:animated];
|
||||
[self.navigationController setNavigationBarHidden:NO animated:YES];
|
||||
}
|
||||
|
||||
-(void)setNavgationItems{
|
||||
[super setNavgationItems];
|
||||
self.navigationItem.title = QXText(@"动态发布");
|
||||
}
|
||||
-(void)initSubViews{
|
||||
self.topicView = [[QXSelectedTopicView alloc] initWithFrame:CGRectMake(16, NavContentHeight+12, SCREEN_WIDTH-32, 44)];
|
||||
self.topicView.backgroundColor = RGB16(0xEFF2F8);
|
||||
[self.topicView addRoundedCornersWithRadius:11];
|
||||
MJWeakSelf
|
||||
[self.topicView addTapBlock:^(id _Nonnull obj) {
|
||||
QXTopicListView *listView = [[QXTopicListView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, ScaleWidth(374))];
|
||||
listView.selecctedTopicBlock = ^(NSArray<QXTopicModel *> * _Nonnull topicArr) {
|
||||
weakSelf.topicView.selectedTopic = topicArr;
|
||||
};
|
||||
[[QXGlobal shareGlobal] showView:listView popType:(PopViewTypeBottomToUpActionSheet) tapDismiss:YES finishBlock:^{
|
||||
|
||||
}];
|
||||
}];
|
||||
[self.view addSubview:self.topicView];
|
||||
|
||||
self.textView = [[QXTextView alloc] initWithFrame:CGRectMake(16, self.topicView.bottom+12, SCREEN_WIDTH-32, 180)];
|
||||
self.textView.placehoulder = QXText(@"此刻想和大家分享点什么");
|
||||
self.textView.font = [UIFont systemFontOfSize:12];
|
||||
self.textView.maxLength = 1200;
|
||||
self.textView.backgroundColor = [UIColor whiteColor];
|
||||
[self.textView addRoundedCornersWithRadius:7];
|
||||
[self.view addSubview:self.textView];
|
||||
|
||||
int itemWidth = (self.view.width-16*2-20*2)/3;
|
||||
self.pickerView = [[QXUserInfoEditFooterView alloc] initWithFrame:CGRectMake(0, self.textView.bottom, SCREEN_WIDTH, itemWidth*3+12*2+20*2)];
|
||||
self.pickerView.backgroundColor = [UIColor clearColor];
|
||||
self.pickerView.maxCount = 9;
|
||||
self.pickerView.hideTitle = YES;
|
||||
self.pickerView.delegate = self;
|
||||
[self.view addSubview:self.pickerView];
|
||||
[[QXLocationManager shareManager] startLoction];
|
||||
[QXLocationManager shareManager].delegate = self;
|
||||
self.commitBtn = [[UIButton alloc] init];
|
||||
[self.commitBtn setTitle:QXText(@"发布") forState:(UIControlStateNormal)];
|
||||
self.commitBtn.titleLabel.font = [UIFont systemFontOfSize:14];;
|
||||
[self.commitBtn setTitleColor:QXConfig.btnTextColor forState:(UIControlStateNormal)];
|
||||
[self.commitBtn addRoundedCornersWithRadius:21];
|
||||
self.commitBtn.backgroundColor = QXConfig.themeColor;
|
||||
[self.commitBtn addTarget:self action:@selector(commitAction) forControlEvents:(UIControlEventTouchUpInside)];
|
||||
[self.view addSubview:self.commitBtn];
|
||||
[self.commitBtn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.mas_equalTo(38);
|
||||
make.right.mas_equalTo(-38);
|
||||
make.height.mas_equalTo(42);
|
||||
make.bottom.mas_equalTo(-(kSafeAreaBottom));
|
||||
}];
|
||||
}
|
||||
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
|
||||
[self.view endEditing:YES];
|
||||
}
|
||||
-(void)commitAction{
|
||||
// if (self.topicView.selectedTopic.count == 0) {
|
||||
// showToast(@"请选择话题");
|
||||
// return;
|
||||
// }
|
||||
if (self.textView.text.length == 0) {
|
||||
showToast(@"发布内容不能为空");
|
||||
return;
|
||||
}
|
||||
// if (self.images.length == 0) {
|
||||
// showToast(@"请上传图片");
|
||||
// return;
|
||||
// }
|
||||
NSString *topic = @"";
|
||||
if (self.topicView.selectedTopic.count > 0) {
|
||||
for (QXTopicModel*md in self.topicView.selectedTopic) {
|
||||
if (topic.length == 0) {
|
||||
topic = [topic stringByAppendingFormat:@"%@",md.topic_id];
|
||||
}else{
|
||||
topic = [topic stringByAppendingFormat:@",%@",md.topic_id];
|
||||
}
|
||||
}
|
||||
}
|
||||
MJWeakSelf
|
||||
[QXDynamicNetwork publishDynamicWithImages:self.images
|
||||
content:self.textView.text
|
||||
topic_id:topic
|
||||
ip:self.city
|
||||
successBlock:^(NSDictionary * _Nonnull dict) {
|
||||
if (weakSelf.publishFinishBlock) {
|
||||
weakSelf.publishFinishBlock();
|
||||
}
|
||||
[weakSelf.navigationController popViewControllerAnimated:YES];
|
||||
}
|
||||
failBlock:^(NSError * _Nonnull error, NSString * _Nonnull msg) {
|
||||
|
||||
}];
|
||||
}
|
||||
|
||||
-(void)locationSuccessWithCity:(NSString *)city province:(NSString * _Nonnull)province area:(NSString * _Nonnull)area address:(NSString * _Nonnull)address{
|
||||
[[QXLocationManager shareManager] stopLoction];
|
||||
self.city = city;
|
||||
}
|
||||
|
||||
-(void)didUploadFinishedWithImageUrlList:(NSArray *)urlList{
|
||||
self.images = [urlList componentsJoinedByString:@","];
|
||||
}
|
||||
|
||||
@end
|
||||
19
QXLive/Dynamic(语圈)/Controller/QXReportViewController.h
Normal file
19
QXLive/Dynamic(语圈)/Controller/QXReportViewController.h
Normal file
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// QXReportViewController.h
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/7/9.
|
||||
//
|
||||
|
||||
#import "QXBaseViewController.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QXReportViewController : QXBaseViewController
|
||||
/// 1-用户,2房间,3动态&
|
||||
@property (nonatomic,strong)NSString *reportType;
|
||||
/// fromId=对应id
|
||||
@property (nonatomic,strong)NSString *fromId;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
214
QXLive/Dynamic(语圈)/Controller/QXReportViewController.m
Normal file
214
QXLive/Dynamic(语圈)/Controller/QXReportViewController.m
Normal file
@@ -0,0 +1,214 @@
|
||||
//
|
||||
// QXLevelViewController.m
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/5/9.
|
||||
//
|
||||
|
||||
#import "QXReportViewController.h"
|
||||
#import <WebKit/WebKit.h>
|
||||
|
||||
static void *WKWebBrowserContext = &WKWebBrowserContext;
|
||||
@interface QXReportViewController ()<WKScriptMessageHandler>
|
||||
@property(nonatomic,strong)WKWebView *contentWebView;
|
||||
@property(nonatomic,strong)UIProgressView *progressView;
|
||||
@end
|
||||
|
||||
@implementation QXReportViewController
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
// Do any additional setup after loading the view.
|
||||
[self.view addSubview:self.contentWebView];
|
||||
[self.view addSubview:self.progressView];
|
||||
|
||||
[self layoutConstraints];
|
||||
[self loadData];
|
||||
}
|
||||
-(void)viewWillAppear:(BOOL)animated{
|
||||
[super viewWillAppear:animated];
|
||||
[self.navigationController setNavigationBarHidden:YES animated:YES];
|
||||
}
|
||||
//-(void)setNavgationItems{
|
||||
// [super setNavgationItems];
|
||||
// self.navigationItem.title = @"段位";
|
||||
//}
|
||||
|
||||
- (void)layoutConstraints {
|
||||
[self.contentWebView setFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT)];
|
||||
[self.progressView setFrame:CGRectMake(0, 0, SCREEN_WIDTH
|
||||
, 2)];
|
||||
}
|
||||
- (void)loadData {
|
||||
// 1-用户,2房间,3动态&fromId=对应id
|
||||
NSInteger safeTop = kSafeAreaTop;
|
||||
NSURL* url= [NSURL URLWithString:[NSString stringWithFormat:@"%@web/index.html#/pages/feedback/report?id=%@&fromType=%@&fromId=%@&h=%ld",H5ServerUrl,[QXGlobal shareGlobal].loginModel.token ,self.reportType,self.fromId,safeTop]];
|
||||
NSURLRequest *request =[NSURLRequest requestWithURL:url];
|
||||
[self.contentWebView loadRequest:request];
|
||||
}
|
||||
|
||||
|
||||
|
||||
#pragma mark - WKNavigationDelegate
|
||||
//开始加载
|
||||
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation{
|
||||
//开始加载的时候,让加载进度条显示
|
||||
self.progressView.hidden = NO;
|
||||
}
|
||||
|
||||
//网页加载完成
|
||||
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{
|
||||
// 获取加载网页的标题
|
||||
// if (self.title.length == 0) {
|
||||
// self.navigationItem.title = self.contentWebView.title;
|
||||
// }
|
||||
// if ([self.titleString containsString:@"转账"]) {
|
||||
// // 设置字体
|
||||
// NSString *fontFamilyStr = @"document.getElementsByTagName('body')[0].style.fontFamily='Arial';";
|
||||
// [webView evaluateJavaScript:fontFamilyStr completionHandler:nil];
|
||||
// //设置颜色
|
||||
// [ webView evaluateJavaScript:@"document.getElementsByTagName('body')[0].style.webkitTextFillColor= '#333333'" completionHandler:nil];
|
||||
// //修改字体大小
|
||||
// [ webView evaluateJavaScript:@"document.getElementsByTagName('body')[0].style.webkitTextSizeAdjust= '150%'"completionHandler:nil];
|
||||
// }
|
||||
}
|
||||
//内容返回时调用
|
||||
- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation {
|
||||
|
||||
}
|
||||
|
||||
//服务器请求跳转的时候调用
|
||||
- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation {
|
||||
|
||||
}
|
||||
|
||||
// 内容加载失败时候调用
|
||||
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error{
|
||||
|
||||
}
|
||||
-(void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
|
||||
NSLog(@"message.name====%@ body=%@",message.name,message.body);
|
||||
if([message.name isEqualToString:@"nativeHandler"]){
|
||||
NSDictionary *dict = message.body;
|
||||
if ([dict[@"action"] isEqualToString:@"closeWeb"]) {
|
||||
if (self.contentWebView.canGoBack) {
|
||||
[self.contentWebView goBack];
|
||||
}else{
|
||||
[self.navigationController popViewControllerAnimated:YES];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
|
||||
//如果是跳转一个新页面
|
||||
if (navigationAction.targetFrame == nil) {
|
||||
[webView loadRequest:navigationAction.request];
|
||||
}
|
||||
NSURL *URL = navigationAction.request.URL;
|
||||
[self dealSomeThing:URL];
|
||||
decisionHandler(WKNavigationActionPolicyAllow);
|
||||
}
|
||||
|
||||
- (void)dealSomeThing:(NSURL *)url{
|
||||
NSString *scheme = [url scheme];
|
||||
NSString *resourceSpecifier = [url resourceSpecifier];
|
||||
if ([scheme isEqualToString:@"tel"]) {
|
||||
NSString *callPhone = [NSString stringWithFormat:@"tel://%@", resourceSpecifier];
|
||||
/// 防止iOS 10及其之后,拨打电话系统弹出框延迟出现
|
||||
dispatch_async(dispatch_get_global_queue(0, 0), ^{
|
||||
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:callPhone]];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//进度条
|
||||
- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView {
|
||||
}
|
||||
|
||||
//KVO监听进度条
|
||||
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
|
||||
|
||||
if ([keyPath isEqualToString:NSStringFromSelector(@selector(estimatedProgress))] && object == self.contentWebView) {
|
||||
[self.progressView setAlpha:1.0f];
|
||||
BOOL animated = self.contentWebView.estimatedProgress > self.progressView.progress;
|
||||
[self.progressView setProgress:self.contentWebView.estimatedProgress animated:animated];
|
||||
|
||||
// Once complete, fade out UIProgressView
|
||||
if(self.contentWebView.estimatedProgress >= 1.0f) {
|
||||
[UIView animateWithDuration:0.3f delay:0.3f options:UIViewAnimationOptionCurveEaseOut animations:^{
|
||||
[self.progressView setAlpha:0.0f];
|
||||
} completion:^(BOOL finished) {
|
||||
[self.progressView setProgress:0.0f animated:NO];
|
||||
}];
|
||||
}
|
||||
}
|
||||
else {
|
||||
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - getters and setters
|
||||
- (WKWebView *)contentWebView {
|
||||
if (!_contentWebView) {
|
||||
//设置网页的配置文件
|
||||
WKWebViewConfiguration * configuration = [[WKWebViewConfiguration alloc]init];
|
||||
// 允许可以与网页交互,选择视图
|
||||
configuration.selectionGranularity = YES;
|
||||
// web内容处理池pr
|
||||
configuration.processPool = [[WKProcessPool alloc] init];
|
||||
//自定义配置,一般用于 js调用oc方法(OC拦截URL中的数据做自定义操作)
|
||||
WKUserContentController * UserContentController = [[WKUserContentController alloc]init];
|
||||
// 是否支持记忆读取
|
||||
configuration.suppressesIncrementalRendering = NO;
|
||||
// 允许用户更改网页的设置
|
||||
[UserContentController addScriptMessageHandler:self name:@"nativeHandler"];
|
||||
configuration.preferences.javaScriptEnabled = YES;
|
||||
configuration.preferences.javaScriptCanOpenWindowsAutomatically = YES;
|
||||
configuration.userContentController = UserContentController;
|
||||
// 此处一定要做判断,因为是iOS9之后才有的方法,否则在iOS8下会崩溃
|
||||
if ([[UIDevice currentDevice].systemVersion floatValue] >= 9.0) {
|
||||
//允许视频播放
|
||||
configuration.allowsAirPlayForMediaPlayback = YES;
|
||||
// 允许在线播放
|
||||
configuration.allowsInlineMediaPlayback = YES;
|
||||
//开启手势触摸 默认设置就是NO。在ios8系统中会导致手势问题,程序崩溃
|
||||
_contentWebView.allowsBackForwardNavigationGestures = YES;
|
||||
}
|
||||
_contentWebView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:configuration];
|
||||
_contentWebView.backgroundColor = [UIColor clearColor];
|
||||
_contentWebView.opaque = YES;
|
||||
//适应你设定的尺寸
|
||||
[_contentWebView sizeToFit];
|
||||
_contentWebView.scrollView.showsVerticalScrollIndicator = NO;
|
||||
// 设置代理
|
||||
_contentWebView.navigationDelegate = self;
|
||||
//kvo 添加进度监控
|
||||
[_contentWebView addObserver:self forKeyPath:NSStringFromSelector(@selector(estimatedProgress)) options:0 context:WKWebBrowserContext];
|
||||
}
|
||||
return _contentWebView;
|
||||
}
|
||||
|
||||
- (UIProgressView *)progressView {
|
||||
if (!_progressView) {
|
||||
_progressView = [[UIProgressView alloc]initWithProgressViewStyle:UIProgressViewStyleDefault];
|
||||
[_progressView setTrackTintColor:[UIColor colorWithRed:240.0/255 green:240.0/255 blue:240.0/255 alpha:1.0]];
|
||||
_progressView.progressTintColor = QXConfig.themeColor;
|
||||
}
|
||||
return _progressView;
|
||||
}
|
||||
|
||||
-(void)setProgressColor:(UIColor *)progressColor{
|
||||
_progressView.progressTintColor = progressColor;
|
||||
}
|
||||
// 记得dealloc
|
||||
- (void)dealloc {
|
||||
if (self) {
|
||||
[self.contentWebView removeObserver:self forKeyPath:NSStringFromSelector(@selector(estimatedProgress))];
|
||||
}
|
||||
}
|
||||
- (void)didReceiveMemoryWarning {
|
||||
[super didReceiveMemoryWarning];
|
||||
|
||||
}
|
||||
@end
|
||||
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// QXToppicDynamicViewController.h
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/6/3.
|
||||
//
|
||||
|
||||
#import "QXBaseViewController.h"
|
||||
#import "QXDynamicModel.h"
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QXToppicDynamicViewController : QXBaseViewController
|
||||
@property (nonatomic,strong)QXTopicModel *model;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
106
QXLive/Dynamic(语圈)/Controller/QXToppicDynamicViewController.m
Normal file
106
QXLive/Dynamic(语圈)/Controller/QXToppicDynamicViewController.m
Normal file
@@ -0,0 +1,106 @@
|
||||
//
|
||||
// QXToppicDynamicViewController.m
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/6/3.
|
||||
//
|
||||
|
||||
#import "QXToppicDynamicViewController.h"
|
||||
#import "QXDynamicListCell.h"
|
||||
#import "QXToppicDynamicTopView.h"
|
||||
#import "QXDynamicNetwork.h"
|
||||
|
||||
@interface QXToppicDynamicViewController ()<UITableViewDelegate,UITableViewDataSource>
|
||||
@property (strong, nonatomic) UITableView *tableView;
|
||||
@property (strong, nonatomic) QXToppicDynamicTopView *topView;
|
||||
@end
|
||||
|
||||
@implementation QXToppicDynamicViewController
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
// Do any additional setup after loading the view.
|
||||
}
|
||||
|
||||
-(void)viewWillAppear:(BOOL)animated{
|
||||
[super viewWillAppear:animated];
|
||||
[self.navigationController setNavigationBarHidden:NO animated:YES];
|
||||
}
|
||||
|
||||
-(void)setNavgationItems{
|
||||
[super setNavgationItems];
|
||||
self.navigationItem.title = self.model.title;
|
||||
}
|
||||
|
||||
-(void)initSubViews{
|
||||
self.page = 1;
|
||||
self.tableView.tableHeaderView = self.topView;
|
||||
[self.view addSubview:self.tableView];
|
||||
[self getDynamicList];
|
||||
}
|
||||
-(void)getDynamicList{
|
||||
MJWeakSelf
|
||||
[QXDynamicNetwork topicDynamicListWithTopic_id:self.model.topic_id page:self.page successBlock:^(NSArray<QXDynamicModel *> * _Nonnull list) {
|
||||
if (weakSelf.page == 1) {
|
||||
[weakSelf.dataArray removeAllObjects];
|
||||
}
|
||||
[weakSelf.dataArray addObjectsFromArray:list];
|
||||
[weakSelf.tableView.mj_header endRefreshing];
|
||||
if (list.count == 0) {
|
||||
weakSelf.tableView.mj_footer.state = MJRefreshStateNoMoreData;
|
||||
}else{
|
||||
[weakSelf.tableView.mj_footer endRefreshing];
|
||||
}
|
||||
[self.tableView reloadData];
|
||||
} failBlock:^(NSError * _Nonnull error, NSString * _Nonnull msg) {
|
||||
[weakSelf.tableView.mj_header endRefreshing];
|
||||
[weakSelf.tableView.mj_footer endRefreshing];
|
||||
}];
|
||||
}
|
||||
#pragma mark - UITableViewDelegate,UITableViewDataSource
|
||||
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
|
||||
return self.dataArray.count;
|
||||
}
|
||||
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
|
||||
QXDynamicListCell *cell = [tableView dequeueReusableCellWithIdentifier:@"QXDynamicListCell" forIndexPath:indexPath];
|
||||
cell.selectionStyle = NO;
|
||||
cell.model = self.dataArray[indexPath.row];
|
||||
// SPTrendListModel *model = self.dataArray[indexPath.row];
|
||||
// cell.model = model;
|
||||
MJWeakSelf
|
||||
cell.onDeleteBlock = ^(QXDynamicModel * _Nonnull model) {
|
||||
[weakSelf.dataArray removeObject:model];
|
||||
[weakSelf.tableView reloadSection:indexPath.section withRowAnimation:(UITableViewRowAnimationAutomatic)];
|
||||
};
|
||||
return cell;
|
||||
}
|
||||
-(UITableView *)tableView{
|
||||
if (!_tableView) {
|
||||
self.tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, NavContentHeight, SCREEN_WIDTH, SCREEN_HEIGHT-NavContentHeight) style:UITableViewStylePlain];
|
||||
self.tableView.backgroundColor = [UIColor clearColor];
|
||||
self.tableView.delegate = self;
|
||||
self.tableView.dataSource = self;
|
||||
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
|
||||
[self.tableView registerNib:[UINib nibWithNibName:@"QXDynamicListCell" bundle:nil] forCellReuseIdentifier:@"QXDynamicListCell"];
|
||||
self.tableView.rowHeight = UITableViewAutomaticDimension;
|
||||
self.tableView.estimatedRowHeight = 152;
|
||||
MJWeakSelf
|
||||
_tableView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{
|
||||
weakSelf.page = 1;
|
||||
[weakSelf getDynamicList];
|
||||
}];
|
||||
_tableView.mj_footer = [MJRefreshBackNormalFooter footerWithRefreshingBlock:^{
|
||||
weakSelf.page++;
|
||||
[weakSelf getDynamicList];
|
||||
}];
|
||||
}
|
||||
return _tableView;
|
||||
}
|
||||
-(QXToppicDynamicTopView *)topView{
|
||||
if (!_topView) {
|
||||
_topView = [[QXToppicDynamicTopView alloc] initWithModel:self.model];
|
||||
}
|
||||
return _topView;
|
||||
}
|
||||
|
||||
@end
|
||||
130
QXLive/Dynamic(语圈)/Model/QXDynamicModel.h
Normal file
130
QXLive/Dynamic(语圈)/Model/QXDynamicModel.h
Normal file
@@ -0,0 +1,130 @@
|
||||
//
|
||||
// QXDynamicModel.h
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/5/29.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
@class QXTopicModel,QXDynamicLikeModel;
|
||||
@interface QXDynamicModel : NSObject
|
||||
/// 动态id
|
||||
@property (nonatomic,strong)NSString *id;
|
||||
/// 用户id
|
||||
@property (nonatomic,strong)NSString *user_id;
|
||||
/// 用户id
|
||||
@property (nonatomic,strong)NSString *user_code;
|
||||
/// 图片,隔开
|
||||
@property (nonatomic,strong)NSString *images;
|
||||
/// 性别 1男2女
|
||||
@property (nonatomic,strong)NSString *sex;
|
||||
/// 内容
|
||||
@property (nonatomic,strong)NSString *content;
|
||||
/// 点赞数
|
||||
@property (nonatomic,strong)NSString *like_num;
|
||||
/// 评论数
|
||||
@property (nonatomic,strong)NSString *comment_num;
|
||||
/// 话题名称
|
||||
@property (nonatomic,strong)NSArray<QXTopicModel*> *title;
|
||||
/// 打赏金额
|
||||
@property (nonatomic,strong)NSString *rewards_num;
|
||||
/// 是否点赞1点,0未
|
||||
@property (nonatomic,strong)NSString *is_like;
|
||||
/// 作者是否在房间中(1在,0不在)
|
||||
@property (nonatomic,strong)NSString *is_room;
|
||||
/// 作者所在房间ID (is_room =0 此值小于0 )
|
||||
@property (nonatomic,strong)NSString *room_id;
|
||||
/// 头像
|
||||
@property (nonatomic,strong)NSString *avatar;
|
||||
/// 装扮
|
||||
@property (nonatomic,strong)NSString *dress;
|
||||
/// 昵称
|
||||
@property (nonatomic,strong)NSString *nickname;
|
||||
/// 时间
|
||||
@property (nonatomic,strong)NSString *createtime;
|
||||
/// 是否为推荐
|
||||
@property (nonatomic,strong)NSString *is_recommend;
|
||||
/// 昵称
|
||||
@property (nonatomic,strong)NSString *share_url;
|
||||
|
||||
@property (nonatomic,strong)NSArray<QXDynamicLikeModel*> *like_list;
|
||||
@end
|
||||
|
||||
|
||||
@interface QXTopicModel : NSObject<YYModel>
|
||||
/// id
|
||||
@property (nonatomic,strong)NSString *topic_id;
|
||||
/// 话题描述
|
||||
@property (nonatomic,strong)NSString *content;
|
||||
/// 话题名称
|
||||
@property (nonatomic,strong)NSString *title;
|
||||
/// 话题图片
|
||||
@property (nonatomic,strong)NSString *pic;
|
||||
/// 多少条动态
|
||||
@property (nonatomic,strong)NSString *count;
|
||||
/// 选择
|
||||
@property (nonatomic,assign)BOOL isSelected;
|
||||
@end
|
||||
|
||||
#pragma mark - 点赞列表
|
||||
@interface QXDynamicLikeModel : NSObject<YYModel>
|
||||
/// 用户id
|
||||
@property (nonatomic,strong)NSString *user_id;
|
||||
/// 昵称
|
||||
@property (nonatomic,strong)NSString *nickname;
|
||||
/// 头像
|
||||
@property (nonatomic,strong)NSString *avatar;
|
||||
/// 年龄
|
||||
@property (nonatomic,strong)NSString *age;
|
||||
/// 星座
|
||||
@property (nonatomic,strong)NSString *constellation;
|
||||
/// 生日
|
||||
@property (nonatomic,strong)NSString *birthday;
|
||||
/// 性别 1 男 2女
|
||||
@property (nonatomic,strong)NSString *sex;
|
||||
@end
|
||||
|
||||
#pragma mark - 评论列表
|
||||
@class QXDynamicCommentListModel;
|
||||
@interface QXDynamicCommentModel : NSObject
|
||||
|
||||
@property (nonatomic,strong)NSArray<QXDynamicCommentListModel*>* list;
|
||||
/// 总评论数
|
||||
@property (nonatomic,strong)NSString* total;
|
||||
|
||||
|
||||
@end
|
||||
|
||||
@interface QXDynamicCommentListModel : NSObject
|
||||
/// 评论ID
|
||||
@property (nonatomic,strong)NSString *id;
|
||||
/// 动态ID
|
||||
@property (nonatomic,strong)NSString *zone_id;
|
||||
/// 评论内容
|
||||
@property (nonatomic,strong)NSString *content;
|
||||
/// 时间
|
||||
@property (nonatomic,strong)NSString *createtime;
|
||||
/// 评论者ID
|
||||
@property (nonatomic,strong)NSString *user_id;
|
||||
/// 评论者
|
||||
@property (nonatomic,strong)NSString *nickname;
|
||||
/// 评论者头像
|
||||
@property (nonatomic,strong)NSString *avatar;
|
||||
/// 评论者是否作者 0不是,1
|
||||
@property (nonatomic,strong)NSString *is_author;
|
||||
/// 二级评论
|
||||
@property (nonatomic,strong)NSArray<QXDynamicCommentListModel*> *replies;
|
||||
|
||||
|
||||
/// 以上为一级评论 下面是二级评论
|
||||
/// 回复给谁的ID
|
||||
@property (nonatomic,strong)NSString *reply_to;
|
||||
/// 上级评论的ID
|
||||
@property (nonatomic,strong)NSString *pid;
|
||||
/// 回复给谁
|
||||
@property (nonatomic,strong)NSString *reply_to_user;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
51
QXLive/Dynamic(语圈)/Model/QXDynamicModel.m
Normal file
51
QXLive/Dynamic(语圈)/Model/QXDynamicModel.m
Normal file
@@ -0,0 +1,51 @@
|
||||
//
|
||||
// QXDynamicModel.m
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/5/29.
|
||||
//
|
||||
|
||||
#import "QXDynamicModel.h"
|
||||
|
||||
@implementation QXDynamicModel
|
||||
+(NSDictionary<NSString *,id> *)modelContainerPropertyGenericClass{
|
||||
return @{
|
||||
@"title" : @"QXTopicModel",
|
||||
@"like_list":@"QXDynamicLikeModel"
|
||||
};
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation QXTopicModel
|
||||
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation QXDynamicLikeModel
|
||||
|
||||
|
||||
|
||||
@end
|
||||
|
||||
@implementation QXDynamicCommentModel
|
||||
|
||||
+(NSDictionary<NSString *,id> *)modelContainerPropertyGenericClass{
|
||||
return @{
|
||||
@"list" : @"QXDynamicCommentListModel",
|
||||
};
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation QXDynamicCommentListModel
|
||||
|
||||
+(NSDictionary<NSString *,id> *)modelContainerPropertyGenericClass{
|
||||
return @{
|
||||
@"replies" : @"QXDynamicCommentListModel",
|
||||
};
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
153
QXLive/Dynamic(语圈)/Services/QXDynamicNetwork.h
Normal file
153
QXLive/Dynamic(语圈)/Services/QXDynamicNetwork.h
Normal file
@@ -0,0 +1,153 @@
|
||||
//
|
||||
// QXDynamicNetwork.h
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/5/30.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "QXDynamicModel.h"
|
||||
#import "QXUserModel.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QXDynamicNetwork : NSObject
|
||||
/**
|
||||
发布动态
|
||||
images,用,隔开
|
||||
*/
|
||||
+(void)publishDynamicWithImages:(NSString*)images
|
||||
content:(NSString*)content
|
||||
topic_id:(NSString*)topic_id
|
||||
ip:(NSString*)ip
|
||||
successBlock:(void (^)(NSDictionary* dict))successBlock
|
||||
failBlock:(void (^)(NSError * error, NSString * msg))failBlock;
|
||||
/**
|
||||
动态列表
|
||||
*/
|
||||
+(void)getDynamicListWithPage:(NSInteger)page
|
||||
successBlock:(void (^)(NSArray<QXDynamicModel*>*hotos))successBlock
|
||||
failBlock:(void (^)(NSError * error, NSString * msg))failBlock;
|
||||
/**
|
||||
话题列表
|
||||
*/
|
||||
+(void)getTopicListWithPage:(NSInteger)page
|
||||
isTopTopic:(BOOL)isTopTopic
|
||||
successBlock:(void (^)(NSArray<QXTopicModel*>*hotos))successBlock
|
||||
failBlock:(void (^)(NSError * error, NSString * msg))failBlock;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
扩列列表
|
||||
*/
|
||||
|
||||
+(void)expansionListWithPage:(NSInteger)page
|
||||
type:(NSString*)type
|
||||
successBlock:(void (^)(NSArray<QXUserHomeModel*>*list,BOOL isAppStore))successBlock
|
||||
failBlock:(void (^)(NSError * error, NSString * msg))failBlock;
|
||||
|
||||
/**
|
||||
动态打赏
|
||||
is_pack 1金币购买,2背包礼物
|
||||
*/
|
||||
+(void)dynamicGiveGiftWithId:(NSString*)Id
|
||||
gift_id:(NSString*)gift_id
|
||||
num:(NSString*)num
|
||||
is_pack:(NSString*)is_pack
|
||||
successBlock:(void (^)(NSDictionary* dict))successBlock
|
||||
failBlock:(void (^)(NSError * error, NSString * msg))failBlock;
|
||||
|
||||
/**
|
||||
动态打赏列表
|
||||
*/
|
||||
+(void)dynamicGiveGiftListWithId:(NSString*)Id
|
||||
successBlock:(void (^)(NSArray<QXUserHomeModel*>* list))successBlock
|
||||
failBlock:(void (^)(NSError * error, NSString * msg))failBlock;
|
||||
|
||||
|
||||
/**
|
||||
动态点赞
|
||||
*/
|
||||
|
||||
+(void)likeDynamicWithId:(NSString*)Id
|
||||
isLike:(BOOL)isLike
|
||||
successBlock:(void (^)(NSDictionary* dict))successBlock
|
||||
failBlock:(void (^)(NSError * error, NSString * msg))failBlock;
|
||||
|
||||
/**
|
||||
删除动态
|
||||
*/
|
||||
+(void)deleteDynamicWithId:(NSString*)Id
|
||||
successBlock:(void (^)(NSDictionary* dict))successBlock
|
||||
failBlock:(void (^)(NSError * error, NSString * msg))failBlock;
|
||||
|
||||
/**
|
||||
话题动态
|
||||
*/
|
||||
+(void)topicDynamicListWithTopic_id:(NSString*)topic_id
|
||||
page:(NSInteger)page
|
||||
successBlock:(void (^)(NSArray<QXDynamicModel*>*list))successBlock
|
||||
failBlock:(void (^)(NSError * error, NSString * msg))failBlock;
|
||||
|
||||
/**
|
||||
动态详情
|
||||
*/
|
||||
+(void)dynamicPageWithId:(NSString*)Id
|
||||
successBlock:(void (^)(QXDynamicModel*model))successBlock
|
||||
failBlock:(void (^)(NSError * error, NSString * msg))failBlock;
|
||||
|
||||
/**
|
||||
评论列表
|
||||
*/
|
||||
+(void)commentListWithId:(NSString*)Id
|
||||
page:(NSInteger)page
|
||||
successBlock:(void (^)(QXDynamicCommentModel* model))successBlock
|
||||
failBlock:(void (^)(NSError * error, NSString * msg))failBlock;
|
||||
|
||||
/**
|
||||
点赞列表
|
||||
*/
|
||||
+(void)likeListWithId:(NSString*)Id
|
||||
page:(NSInteger)page
|
||||
successBlock:(void (^)(NSArray<QXDynamicLikeModel*>* list))successBlock
|
||||
failBlock:(void (^)(NSError * error, NSString * msg))failBlock;
|
||||
|
||||
/**
|
||||
评论动态/回复评论
|
||||
*/
|
||||
+(void)commentDynamicWithId:(NSString*)Id
|
||||
pid:(NSString*)pid
|
||||
reply_to:(NSString*)reply_to
|
||||
content:(NSString*)content
|
||||
successBlock:(void (^)(NSDictionary* dict))successBlock
|
||||
failBlock:(void (^)(NSError * error, NSString * msg))failBlock;
|
||||
|
||||
|
||||
/**
|
||||
删除评论
|
||||
*/
|
||||
+(void)deleteCommentWithCommentId:(NSString*)Id
|
||||
successBlock:(void (^)(NSDictionary* dict))successBlock
|
||||
failBlock:(void (^)(NSError * error, NSString * msg))failBlock;
|
||||
|
||||
/**
|
||||
互关用户列表
|
||||
*/
|
||||
+(void)mutualRelationshipWithPage:(NSInteger)page
|
||||
successBlock:(void (^)(NSArray<QXDynamicLikeModel*>*hotos))successBlock
|
||||
failBlock:(void (^)(NSError * error, NSString * msg))failBlock;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
关注
|
||||
type 1 用户 2房间
|
||||
*/
|
||||
+(void)followWithUserId:(NSString*)userId
|
||||
type:(NSString*)type
|
||||
successBlock:(void (^)(NSDictionary* dict))successBlock
|
||||
failBlock:(void (^)(NSError * error, NSString * msg))failBlock;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
318
QXLive/Dynamic(语圈)/Services/QXDynamicNetwork.m
Normal file
318
QXLive/Dynamic(语圈)/Services/QXDynamicNetwork.m
Normal file
@@ -0,0 +1,318 @@
|
||||
//
|
||||
// QXDynamicNetwork.m
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/5/30.
|
||||
//
|
||||
|
||||
#import "QXDynamicNetwork.h"
|
||||
|
||||
@implementation QXDynamicNetwork
|
||||
+(void)publishDynamicWithImages:(NSString*)images
|
||||
content:(NSString*)content
|
||||
topic_id:(NSString*)topic_id
|
||||
ip:(NSString*)ip
|
||||
successBlock:(void (^)(NSDictionary* dict))successBlock
|
||||
failBlock:(void (^)(NSError * error, NSString * msg))failBlock{
|
||||
NSMutableDictionary *parameters = [NSMutableDictionary dictionary];
|
||||
if (images.length > 0) {
|
||||
[parameters setObject:images forKey:@"images"];
|
||||
}
|
||||
[parameters setObject:content forKey:@"content"];
|
||||
if (topic_id.length > 0) {
|
||||
[parameters setObject:topic_id forKey:@"topic_id"];
|
||||
}
|
||||
if (ip.length > 0) {
|
||||
[parameters setObject:ip forKey:@"ip"];
|
||||
}
|
||||
[[QXRequset shareInstance] postWithUrl:QXDynamicPublish parameters:parameters needCache:NO success:^(id responseObject) {
|
||||
if (successBlock) {
|
||||
successBlock(responseObject[@"data"]);
|
||||
}
|
||||
} fail:^(NSError *error, NSString *msg, NSURLSessionDataTask *task) {
|
||||
if (failBlock) {
|
||||
failBlock(error,msg);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
+(void)getDynamicListWithPage:(NSInteger)page
|
||||
successBlock:(void (^)(NSArray<QXDynamicModel *> * _Nonnull))successBlock
|
||||
failBlock:(void (^)(NSError * _Nonnull, NSString * _Nonnull))failBlock{
|
||||
NSDictionary *parameters = @{
|
||||
@"page":[NSNumber numberWithInteger:page]
|
||||
};
|
||||
[[QXRequset shareInstance] postWithUrl:QXDynamicList parameters:parameters needCache:NO success:^(id responseObject) {
|
||||
if (successBlock) {
|
||||
NSArray *list = [NSArray yy_modelArrayWithClass:[QXDynamicModel class] json:responseObject[@"data"]];
|
||||
successBlock(list);
|
||||
}
|
||||
} fail:^(NSError *error, NSString *msg, NSURLSessionDataTask *task) {
|
||||
if (failBlock) {
|
||||
failBlock(error,msg);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
+(void)getTopicListWithPage:(NSInteger)page
|
||||
isTopTopic:(BOOL)isTopTopic
|
||||
successBlock:(void (^)(NSArray<QXTopicModel *> * _Nonnull))successBlock
|
||||
failBlock:(void (^)(NSError * _Nonnull, NSString * _Nonnull))failBlock{
|
||||
NSDictionary *parameters = @{
|
||||
@"page":[NSNumber numberWithInteger:page]
|
||||
};
|
||||
NSString *url = QXTopicList;
|
||||
if (isTopTopic) {
|
||||
url = QXTopTopic;
|
||||
}
|
||||
[[QXRequset shareInstance] postWithUrl:url parameters:parameters needCache:NO success:^(id responseObject) {
|
||||
if (successBlock) {
|
||||
NSArray *list = [NSArray yy_modelArrayWithClass:[QXTopicModel class] json:responseObject[@"data"]];
|
||||
successBlock(list);
|
||||
}
|
||||
} fail:^(NSError *error, NSString *msg, NSURLSessionDataTask *task) {
|
||||
if (failBlock) {
|
||||
failBlock(error,msg);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
+(void)expansionListWithPage:(NSInteger)page
|
||||
type:(NSString*)type
|
||||
successBlock:(void (^)(NSArray<QXUserHomeModel*>*list,BOOL isAppStore))successBlock
|
||||
failBlock:(void (^)(NSError * error, NSString * msg))failBlock{
|
||||
NSDictionary *parameters = @{
|
||||
@"page":[NSNumber numberWithInteger:page],
|
||||
@"type":type
|
||||
};
|
||||
[[QXRequset shareInstance] postWithUrl:QXExpandList parameters:parameters needCache:NO success:^(id responseObject) {
|
||||
if (successBlock) {
|
||||
NSArray *list = [NSArray yy_modelArrayWithClass:[QXUserHomeModel class] json:responseObject[@"data"]];
|
||||
BOOL isAppStroe = [responseObject[@"api_version"] boolValue];
|
||||
successBlock(list,isAppStroe);
|
||||
}
|
||||
} fail:^(NSError *error, NSString *msg, NSURLSessionDataTask *task) {
|
||||
if (failBlock) {
|
||||
failBlock(error,msg);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
+(void)dynamicGiveGiftWithId:(NSString *)Id
|
||||
gift_id:(NSString*)gift_id
|
||||
num:(NSString*)num
|
||||
is_pack:(NSString*)is_pack
|
||||
successBlock:(void (^)(NSDictionary * _Nonnull))successBlock failBlock:(void (^)(NSError * _Nonnull, NSString * _Nonnull))failBlock{
|
||||
NSDictionary *parameters = @{
|
||||
@"id":Id,
|
||||
@"gift_id":gift_id,
|
||||
@"num":num,
|
||||
@"is_pack":is_pack
|
||||
};
|
||||
[[QXRequset shareInstance] postWithUrl:QXDynamicGive parameters:parameters needCache:NO success:^(id responseObject) {
|
||||
if (successBlock) {
|
||||
successBlock(responseObject[@"data"]);
|
||||
}
|
||||
} fail:^(NSError *error, NSString *msg, NSURLSessionDataTask *task) {
|
||||
if (failBlock) {
|
||||
failBlock(error,msg);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
+(void)dynamicGiveGiftListWithId:(NSString *)Id successBlock:(void (^)(NSArray<QXUserHomeModel *> * _Nonnull))successBlock failBlock:(void (^)(NSError * _Nonnull, NSString * _Nonnull))failBlock{
|
||||
NSDictionary *parameters = @{
|
||||
@"id":Id,
|
||||
};
|
||||
[[QXRequset shareInstance] postWithUrl:QXDynamicGiveList parameters:parameters needCache:NO success:^(id responseObject) {
|
||||
if (successBlock) {
|
||||
NSArray *list = [NSArray yy_modelArrayWithClass:[QXUserHomeModel class] json:responseObject[@"data"]];
|
||||
successBlock(list);
|
||||
}
|
||||
} fail:^(NSError *error, NSString *msg, NSURLSessionDataTask *task) {
|
||||
if (failBlock) {
|
||||
failBlock(error,msg);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
+(void)likeDynamicWithId:(NSString*)Id
|
||||
isLike:(BOOL)isLike
|
||||
successBlock:(void (^)(NSDictionary* dict))successBlock
|
||||
failBlock:(void (^)(NSError * error, NSString * msg))failBlock{
|
||||
NSDictionary *parameters = @{
|
||||
@"id":Id
|
||||
};
|
||||
[[QXRequset shareInstance] postWithUrl:QXDynamicLike parameters:parameters needCache:NO success:^(id responseObject) {
|
||||
if (successBlock) {
|
||||
successBlock(responseObject[@"data"]);
|
||||
}
|
||||
} fail:^(NSError *error, NSString *msg, NSURLSessionDataTask *task) {
|
||||
if (failBlock) {
|
||||
failBlock(error,msg);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
+(void)deleteDynamicWithId:(NSString *)Id successBlock:(void (^)(NSDictionary * _Nonnull))successBlock failBlock:(void (^)(NSError * _Nonnull, NSString * _Nonnull))failBlock{
|
||||
NSDictionary *parameters = @{
|
||||
@"id":Id
|
||||
};
|
||||
[[QXRequset shareInstance] postWithUrl:QXDynamicDelete parameters:parameters needCache:NO success:^(id responseObject) {
|
||||
if (successBlock) {
|
||||
successBlock(responseObject[@"data"]);
|
||||
}
|
||||
} fail:^(NSError *error, NSString *msg, NSURLSessionDataTask *task) {
|
||||
if (failBlock) {
|
||||
failBlock(error,msg);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
+(void)topicDynamicListWithTopic_id:(NSString *)topic_id
|
||||
page:(NSInteger)page
|
||||
successBlock:(void (^)(NSArray<QXDynamicModel *> * _Nonnull))successBlock
|
||||
failBlock:(void (^)(NSError * _Nonnull, NSString * _Nonnull))failBlock{
|
||||
NSDictionary *parameters = @{
|
||||
@"page":[NSNumber numberWithInteger:page],
|
||||
@"topic_id":topic_id
|
||||
};
|
||||
[[QXRequset shareInstance] postWithUrl:QXDynamicTopicPage parameters:parameters needCache:NO success:^(id responseObject) {
|
||||
if (successBlock) {
|
||||
NSArray *list = [NSArray yy_modelArrayWithClass:[QXDynamicModel class] json:responseObject[@"data"]];
|
||||
successBlock(list);
|
||||
}
|
||||
} fail:^(NSError *error, NSString *msg, NSURLSessionDataTask *task) {
|
||||
if (failBlock) {
|
||||
failBlock(error,msg);
|
||||
}
|
||||
}];
|
||||
|
||||
}
|
||||
|
||||
|
||||
+(void)dynamicPageWithId:(NSString *)Id
|
||||
successBlock:(void (^)(QXDynamicModel * _Nonnull))successBlock
|
||||
failBlock:(void (^)(NSError * _Nonnull, NSString * _Nonnull))failBlock{
|
||||
NSDictionary *parameters = @{
|
||||
@"id":Id
|
||||
};
|
||||
[[QXRequset shareInstance] postWithUrl:QXDynamicDetail parameters:parameters needCache:NO success:^(id responseObject) {
|
||||
if (successBlock) {
|
||||
QXDynamicModel *model = [QXDynamicModel yy_modelWithJSON:responseObject[@"data"]];
|
||||
successBlock(model);
|
||||
}
|
||||
} fail:^(NSError *error, NSString *msg, NSURLSessionDataTask *task) {
|
||||
if (failBlock) {
|
||||
failBlock(error,msg);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
+(void)commentListWithId:(NSString *)Id page:(NSInteger)page successBlock:(void (^)(QXDynamicCommentModel* model))successBlock failBlock:(void (^)(NSError * _Nonnull, NSString * _Nonnull))failBlock{
|
||||
NSDictionary *parameters = @{
|
||||
@"page":[NSNumber numberWithInteger:page],
|
||||
@"id":Id
|
||||
};
|
||||
[[QXRequset shareInstance] postWithUrl:QXDynamicCommentList parameters:parameters needCache:NO success:^(id responseObject) {
|
||||
if (successBlock) {
|
||||
QXDynamicCommentModel *model = [QXDynamicCommentModel yy_modelWithJSON:responseObject[@"data"]];
|
||||
successBlock(model);
|
||||
}
|
||||
} fail:^(NSError *error, NSString *msg, NSURLSessionDataTask *task) {
|
||||
if (failBlock) {
|
||||
failBlock(error,msg);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
+(void)likeListWithId:(NSString *)Id page:(NSInteger)page successBlock:(void (^)(NSArray<QXDynamicLikeModel *> * _Nonnull))successBlock failBlock:(void (^)(NSError * _Nonnull, NSString * _Nonnull))failBlock{
|
||||
NSDictionary *parameters = @{
|
||||
@"page":[NSNumber numberWithInteger:page],
|
||||
@"id":Id
|
||||
};
|
||||
[[QXRequset shareInstance] postWithUrl:QXDynamicLikeList parameters:parameters needCache:NO success:^(id responseObject) {
|
||||
if (successBlock) {
|
||||
NSArray *list = [NSArray yy_modelArrayWithClass:[QXDynamicLikeModel class] json:responseObject[@"data"]];
|
||||
successBlock(list);
|
||||
}
|
||||
} fail:^(NSError *error, NSString *msg, NSURLSessionDataTask *task) {
|
||||
if (failBlock) {
|
||||
failBlock(error,msg);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
+(void)commentDynamicWithId:(NSString *)Id pid:(NSString*)pid reply_to:(NSString*)reply_to content:(NSString*)content successBlock:(void (^)(NSDictionary * _Nonnull))successBlock failBlock:(void (^)(NSError * _Nonnull, NSString * _Nonnull))failBlock{
|
||||
NSDictionary *parameters = @{
|
||||
@"pid":pid,
|
||||
@"id":Id,
|
||||
@"reply_to":reply_to,
|
||||
@"content":content
|
||||
};
|
||||
[[QXRequset shareInstance] postWithUrl:QXDynamicComment parameters:parameters needCache:NO success:^(id responseObject) {
|
||||
if (successBlock) {
|
||||
successBlock(responseObject[@"data"]);
|
||||
}
|
||||
} fail:^(NSError *error, NSString *msg, NSURLSessionDataTask *task) {
|
||||
if (failBlock) {
|
||||
failBlock(error,msg);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
+(void)deleteCommentWithCommentId:(NSString *)Id successBlock:(void (^)(NSDictionary * _Nonnull))successBlock failBlock:(void (^)(NSError * _Nonnull, NSString * _Nonnull))failBlock{
|
||||
NSDictionary *parameters = @{
|
||||
@"id":Id,
|
||||
};
|
||||
[[QXRequset shareInstance] postWithUrl:QXDynamicDeleteComment parameters:parameters needCache:NO success:^(id responseObject) {
|
||||
if (successBlock) {
|
||||
successBlock(responseObject[@"data"]);
|
||||
}
|
||||
} fail:^(NSError *error, NSString *msg, NSURLSessionDataTask *task) {
|
||||
if (failBlock) {
|
||||
failBlock(error,msg);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
+(void)mutualRelationshipWithPage:(NSInteger)page successBlock:(void (^)(NSArray<QXDynamicLikeModel *> * _Nonnull))successBlock failBlock:(void (^)(NSError * _Nonnull, NSString * _Nonnull))failBlock{
|
||||
NSDictionary *parameters = @{
|
||||
@"page":[NSNumber numberWithInteger:page]
|
||||
};
|
||||
[[QXRequset shareInstance] postWithUrl:QXDynamicMutualRelationship parameters:parameters needCache:NO success:^(id responseObject) {
|
||||
if (successBlock) {
|
||||
NSArray *list = [NSArray yy_modelArrayWithClass:[QXDynamicLikeModel class] json:responseObject[@"data"]];
|
||||
successBlock(list);
|
||||
}
|
||||
} fail:^(NSError *error, NSString *msg, NSURLSessionDataTask *task) {
|
||||
if (failBlock) {
|
||||
failBlock(error,msg);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
+(void)followWithUserId:(NSString*)userId
|
||||
type:(NSString*)type
|
||||
successBlock:(void (^)(NSDictionary* dict))successBlock
|
||||
failBlock:(void (^)(NSError * error, NSString * msg))failBlock{
|
||||
NSDictionary *parameters = @{
|
||||
@"user_id":userId,
|
||||
@"type":type
|
||||
};
|
||||
[[QXRequset shareInstance] postWithUrl:QXUserFollow parameters:parameters needCache:NO success:^(id responseObject) {
|
||||
if (successBlock) {
|
||||
successBlock(responseObject[@"data"]);
|
||||
}
|
||||
} fail:^(NSError *error, NSString *msg, NSURLSessionDataTask *task) {
|
||||
if (failBlock) {
|
||||
failBlock(error,msg);
|
||||
}
|
||||
}];
|
||||
}
|
||||
@end
|
||||
26
QXLive/Dynamic(语圈)/View/QXDynamicLikeListView.h
Normal file
26
QXLive/Dynamic(语圈)/View/QXDynamicLikeListView.h
Normal file
@@ -0,0 +1,26 @@
|
||||
//
|
||||
// QXDynamicLikeListView.h
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/6/3.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QXDynamicLikeListView : UIView
|
||||
@property (nonatomic,strong)NSString *Id;
|
||||
@property (nonatomic,strong)NSString *num;
|
||||
-(void)showInView:(UIView*)view;
|
||||
-(void)hide;
|
||||
@end
|
||||
|
||||
@interface QXDynamicLikeListCell : UITableViewCell
|
||||
@property (nonatomic,strong)UIImageView *headerImageView;
|
||||
@property (nonatomic,strong)UILabel *nameLabel;
|
||||
@property (nonatomic,strong)UILabel *infoLabel;
|
||||
@property (nonatomic,strong)QXDynamicLikeModel *model;
|
||||
+(instancetype)cellWithTableView:(UITableView*)tableView;
|
||||
@end
|
||||
NS_ASSUME_NONNULL_END
|
||||
187
QXLive/Dynamic(语圈)/View/QXDynamicLikeListView.m
Normal file
187
QXLive/Dynamic(语圈)/View/QXDynamicLikeListView.m
Normal file
@@ -0,0 +1,187 @@
|
||||
//
|
||||
// QXDynamicLikeListView.m
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/6/3.
|
||||
//
|
||||
|
||||
#import "QXDynamicLikeListView.h"
|
||||
#import "QXDynamicNetwork.h"
|
||||
|
||||
@class QXDynamicLikeListCell;
|
||||
@interface QXDynamicLikeListView()<UITableViewDelegate,UITableViewDataSource,UIGestureRecognizerDelegate>
|
||||
@property (nonatomic,strong)UILabel *titleLabel;
|
||||
@property (nonatomic,strong)UIView *bgView;
|
||||
@property (nonatomic,strong)UITableView *tableView;
|
||||
@property (nonatomic,strong)NSMutableArray *dataArray;
|
||||
@property (nonatomic,assign)NSInteger page;
|
||||
@end
|
||||
@implementation QXDynamicLikeListView
|
||||
- (instancetype)initWithFrame:(CGRect)frame
|
||||
{
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
[self initSubviews];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{
|
||||
return touch.view == self;
|
||||
}
|
||||
|
||||
-(void)showInView:(UIView *)view{
|
||||
[view addSubview:self];
|
||||
[UIView animateWithDuration:0.3 animations:^{
|
||||
self.bgView.y = SCREEN_HEIGHT-ScaleWidth(347);
|
||||
}];
|
||||
}
|
||||
-(void)hide{
|
||||
[UIView animateWithDuration:0.3 animations:^{
|
||||
self.bgView.y = SCREEN_HEIGHT;
|
||||
} completion:^(BOOL finished) {
|
||||
[self removeFromSuperview];
|
||||
}];
|
||||
}
|
||||
|
||||
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
|
||||
return self.dataArray.count;
|
||||
}
|
||||
|
||||
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
|
||||
QXDynamicLikeListCell *cell = [QXDynamicLikeListCell cellWithTableView:tableView];
|
||||
cell.model = self.dataArray[indexPath.row];
|
||||
return cell;
|
||||
}
|
||||
|
||||
-(void)initSubviews{
|
||||
self.page = 1;
|
||||
self.backgroundColor = [UIColor colorWithWhite:0.0 alpha:0.3];
|
||||
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(hide)];
|
||||
tap.delegate = self;
|
||||
[self addGestureRecognizer:tap];
|
||||
|
||||
self.bgView = [[UIView alloc] initWithFrame:CGRectMake(0, SCREEN_HEIGHT, SCREEN_WIDTH, ScaleWidth(347))];
|
||||
self.bgView.backgroundColor = [UIColor whiteColor];
|
||||
[self.bgView addRoundedCornersWithRadius:16 byRoundingCorners:(UIRectCornerTopLeft|UIRectCornerTopRight)];
|
||||
[self addSubview:self.bgView];
|
||||
|
||||
|
||||
self.titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(16, 16, self.bgView.width-32, 27)];
|
||||
self.titleLabel.textColor = QXConfig.textColor;
|
||||
self.titleLabel.font = [UIFont boldSystemFontOfSize:18];
|
||||
[self.bgView addSubview:self.titleLabel];
|
||||
|
||||
self.tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, self.titleLabel.bottom+5, self.bgView.width, self.bgView.height-self.titleLabel.bottom-5) style:(UITableViewStylePlain)];
|
||||
self.tableView.dataSource = self;
|
||||
self.tableView.delegate = self;
|
||||
self.tableView.rowHeight = 53;
|
||||
MJWeakSelf
|
||||
_tableView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{
|
||||
weakSelf.page = 1;
|
||||
[weakSelf getLikeList];
|
||||
}];
|
||||
_tableView.mj_footer = [MJRefreshBackStateFooter footerWithRefreshingBlock:^{
|
||||
weakSelf.page++;
|
||||
[weakSelf getLikeList];
|
||||
}];
|
||||
[self.bgView addSubview:self.tableView];
|
||||
}
|
||||
|
||||
-(void)setId:(NSString *)Id{
|
||||
_Id = Id;
|
||||
[self getLikeList];
|
||||
}
|
||||
-(void)setNum:(NSString *)num{
|
||||
_num = num;
|
||||
self.titleLabel.text = num;
|
||||
}
|
||||
-(void)getLikeList{
|
||||
MJWeakSelf
|
||||
[QXDynamicNetwork likeListWithId:self.Id page:self.page successBlock:^(NSArray<QXDynamicLikeModel *> * _Nonnull list) {
|
||||
if (weakSelf.page == 1) {
|
||||
[weakSelf.dataArray removeAllObjects];
|
||||
}
|
||||
[weakSelf.dataArray addObjectsFromArray:list];
|
||||
if (list.count == 0) {
|
||||
weakSelf.tableView.mj_footer.state = MJRefreshStateNoMoreData;
|
||||
}else{
|
||||
[weakSelf.tableView.mj_footer endRefreshing];
|
||||
}
|
||||
[weakSelf.tableView.mj_header endRefreshing];
|
||||
[weakSelf.tableView reloadData];
|
||||
} failBlock:^(NSError * _Nonnull error, NSString * _Nonnull msg) {
|
||||
[weakSelf.tableView.mj_footer endRefreshing];
|
||||
[weakSelf.tableView.mj_header endRefreshing];
|
||||
}];
|
||||
|
||||
}
|
||||
|
||||
-(NSMutableArray *)dataArray{
|
||||
if (!_dataArray) {
|
||||
_dataArray = [NSMutableArray array];
|
||||
}
|
||||
return _dataArray;
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
@implementation QXDynamicLikeListCell
|
||||
|
||||
+(instancetype)cellWithTableView:(UITableView *)tableView{
|
||||
static NSString* cellId = @"QXDynamicLikeListCell";
|
||||
QXDynamicLikeListCell *cell = [tableView dequeueReusableCellWithIdentifier:cellId];
|
||||
if (!cell) {
|
||||
cell = [[QXDynamicLikeListCell alloc] initWithStyle:(UITableViewCellStyleDefault) reuseIdentifier:cellId];
|
||||
}
|
||||
return cell;
|
||||
}
|
||||
|
||||
-(instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{
|
||||
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
|
||||
self.selectionStyle = UITableViewCellSelectionStyleNone;
|
||||
[self initSubviews];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
-(void)initSubviews{
|
||||
self.headerImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"user_header_placehoulder"]];
|
||||
self.headerImageView.contentMode = UIViewContentModeScaleAspectFill;
|
||||
[self.headerImageView addRoundedCornersWithRadius:20];
|
||||
[self.contentView addSubview:self.headerImageView];
|
||||
|
||||
self.nameLabel = [[UILabel alloc] init];
|
||||
self.nameLabel.textColor = QXConfig.textColor;
|
||||
self.nameLabel.font = [UIFont systemFontOfSize:14];
|
||||
[self.contentView addSubview:self.nameLabel];
|
||||
|
||||
self.infoLabel = [[UILabel alloc] init];
|
||||
self.infoLabel.textColor = RGB16(0x999999);
|
||||
self.infoLabel.font = [UIFont systemFontOfSize:14];
|
||||
[self.contentView addSubview:self.infoLabel];
|
||||
|
||||
[self.headerImageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.mas_equalTo(16);
|
||||
make.size.mas_equalTo(CGSizeMake(40, 40));
|
||||
make.centerY.equalTo(self);
|
||||
}];
|
||||
|
||||
[self.nameLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(self.headerImageView.mas_right).offset(8);
|
||||
make.height.mas_equalTo(21);
|
||||
make.top.equalTo(self.headerImageView).offset(-2);
|
||||
}];
|
||||
|
||||
[self.infoLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(self.headerImageView.mas_right).offset(8);
|
||||
make.height.mas_equalTo(21);
|
||||
make.top.equalTo(self.nameLabel.mas_bottom);
|
||||
}];
|
||||
}
|
||||
-(void)setModel:(QXDynamicLikeModel *)model{
|
||||
_model = model;
|
||||
[self.headerImageView sd_setImageWithURL:[NSURL URLWithString:model.avatar] placeholderImage:[UIImage imageNamed:@"user_header_placehoulder"]];
|
||||
self.nameLabel.text = model.nickname;
|
||||
self.infoLabel.text = [NSString stringWithFormat:@"%@/%@/%@",model.sex.intValue==1?@"男":@"女",model.age,model.constellation];
|
||||
}
|
||||
@end
|
||||
50
QXLive/Dynamic(语圈)/View/QXDynamicListCell.h
Executable file
50
QXLive/Dynamic(语圈)/View/QXDynamicListCell.h
Executable file
@@ -0,0 +1,50 @@
|
||||
//
|
||||
// QXDynamicListCell.h
|
||||
// SweetParty
|
||||
//
|
||||
// Created by bj_szd on 2022/6/1.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "QXDynamicModel.h"
|
||||
#import "QXSeatHeaderView.h"
|
||||
typedef NS_ENUM(NSInteger) {
|
||||
QXDynamicListCellDynamic = 0,
|
||||
QXDynamicListCellDetail ,
|
||||
QXDynamicListCellHomePage ,
|
||||
}QXDynamicListCellType;
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QXDynamicListCell : UITableViewCell
|
||||
@property (weak, nonatomic) IBOutlet UIView *bgView;
|
||||
|
||||
@property (weak, nonatomic) IBOutlet QXSeatHeaderView *avatarImgV;
|
||||
@property (weak, nonatomic) IBOutlet UILabel *nicknameLab;
|
||||
@property (weak, nonatomic) IBOutlet UIImageView *sexImgV;
|
||||
@property (weak, nonatomic) IBOutlet UILabel *timeLab;
|
||||
@property (weak, nonatomic) IBOutlet UIButton *focusBtn;
|
||||
@property (weak, nonatomic) IBOutlet UILabel *contentLab;
|
||||
@property (weak, nonatomic) IBOutlet UIView *imgsBgView;
|
||||
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *imgsBgViewHeightCon;
|
||||
@property (weak, nonatomic) IBOutlet UIButton *commentBtn;
|
||||
@property (weak, nonatomic) IBOutlet UIButton *zanBtn;
|
||||
@property (weak, nonatomic) IBOutlet UIButton *giveBtn;
|
||||
@property (weak, nonatomic) IBOutlet UIImageView *sexImageView;
|
||||
|
||||
|
||||
@property (weak, nonatomic) IBOutlet UIImageView *userImageView1;
|
||||
@property (weak, nonatomic) IBOutlet UIImageView *userImageView2;
|
||||
@property (weak, nonatomic) IBOutlet UIImageView *userImageView3;
|
||||
@property (weak, nonatomic) IBOutlet UILabel *likeCountLabel;
|
||||
@property (weak, nonatomic) IBOutlet UIButton *likeViewBtn;
|
||||
|
||||
@property (nonatomic, copy) void(^onDeleteBlock)(QXDynamicModel*model);
|
||||
|
||||
|
||||
@property (nonatomic, strong) QXDynamicModel *model;
|
||||
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *bgLeftCon;
|
||||
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *bgRightCon;
|
||||
@property (nonatomic, assign) QXDynamicListCellType cellType;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
418
QXLive/Dynamic(语圈)/View/QXDynamicListCell.m
Executable file
418
QXLive/Dynamic(语圈)/View/QXDynamicListCell.m
Executable file
@@ -0,0 +1,418 @@
|
||||
//
|
||||
// QXDynamicListCell.m
|
||||
// SweetParty
|
||||
//
|
||||
// Created by bj_szd on 2022/6/1.
|
||||
//
|
||||
|
||||
#import "QXDynamicListCell.h"
|
||||
//#import "UILabel+ChangeSpace.h"
|
||||
//#import "KNPhotoBrowser.h"
|
||||
//#import "SPTrendReportVC.h"
|
||||
#import "QXSendGiftView.h"
|
||||
#import "YBImageBrowser.h"
|
||||
#import "QXDynamicNetwork.h"
|
||||
#import "QXShareView.h"
|
||||
#import "QXAlertView.h"
|
||||
#import "QXDynamicDetailViewController.h"
|
||||
#import "QXUserHomePageViewController.h"
|
||||
#import "QXDynamicLikeListView.h"
|
||||
#import "QXReportViewController.h"
|
||||
|
||||
@interface QXDynamicListCell ()<QXShareViewDelegate>
|
||||
|
||||
|
||||
@property (nonatomic, strong) NSMutableArray *imgViewsArray;
|
||||
@property (nonatomic, strong)QXSendGiftView *sendView;
|
||||
@end
|
||||
|
||||
@implementation QXDynamicListCell
|
||||
|
||||
- (void)awakeFromNib {
|
||||
[super awakeFromNib];
|
||||
|
||||
self.imgViewsArray = [NSMutableArray arrayWithCapacity:6];
|
||||
self.zanBtn.needEventInterval = 0.5;
|
||||
[self createUI];
|
||||
}
|
||||
-(void)setCellType:(QXDynamicListCellType)cellType{
|
||||
_cellType = cellType;
|
||||
}
|
||||
|
||||
- (void)setModel:(QXDynamicModel *)model {
|
||||
_model = model;
|
||||
|
||||
[self.avatarImgV setHeadIcon:model.avatar dress:@""];
|
||||
self.nicknameLab.text = model.nickname;
|
||||
NSDate *date = [NSDate dateWithTimeIntervalSince1970:model.createtime.longLongValue]; //此处根据项目需求,选择是否除以1000 , 如果时间戳精确到秒则去掉1000
|
||||
NSDateFormatter *formatter = [[NSDateFormatter alloc]init];
|
||||
formatter.dateFormat = @"yyyy-MM-dd HH:mm:ss";
|
||||
NSString*time = [formatter stringFromDate:date];
|
||||
self.zanBtn.selected = model.is_like.integerValue == 0?NO:YES;
|
||||
self.timeLab.text = time;
|
||||
UIImage *sexImage = [UIImage imageNamed:model.sex.intValue==1?@"user_sex_boy":@"user_sex_girl"];
|
||||
self.sexImageView.image = sexImage;
|
||||
// self.focusBtn.selected = model.is_follow;
|
||||
//// self.focusBtn.backgroundColor = model.is_follow ? HEXCOLOR(0x383841) : mainDeepColor;
|
||||
//
|
||||
// self.focusBtn.hidden = [BJUserManager.userInfo.uid integerValue] == [model.uid integerValue];
|
||||
NSString *topic = @"";
|
||||
for (QXTopicModel *md in model.title) {
|
||||
if (topic.length == 0) {
|
||||
topic = [topic stringByAppendingFormat:@"%@",md.title];
|
||||
}else{
|
||||
topic = [topic stringByAppendingFormat:@" %@",md.title];
|
||||
}
|
||||
}
|
||||
NSString *content = [NSString stringWithFormat:@"%@ %@",model.content,topic];
|
||||
NSMutableAttributedString *attr = [[NSMutableAttributedString alloc] initWithString:content];
|
||||
[attr yy_setColor:QXConfig.themeColor range:[content rangeOfString:topic]];
|
||||
self.contentLab.attributedText = attr;
|
||||
// [UILabel changeLineSpaceForLabel:self.contentLab WithSpace:5];
|
||||
//
|
||||
// NSString *topic = [model.title stringByReplacingOccurrencesOfString:@"#" withString:@""];
|
||||
// self.topicLabel.text = topic;
|
||||
[self.commentBtn setTitle:[NSString qx_showHotCountNum:model.comment_num.longLongValue] forState:UIControlStateNormal];
|
||||
[self.zanBtn setTitle:[NSString stringWithFormat:@"%@", [NSString qx_showHotCountNum:model.like_num.longLongValue]] forState:UIControlStateNormal];
|
||||
self.zanBtn.selected = [model.is_like isEqualToString:@"1"]?YES:NO;
|
||||
[self.giveBtn setTitle:[NSString qx_showHotCountNum:model.rewards_num.longLongValue] forState:(UIControlStateNormal)];
|
||||
self.imgsBgView.hidden = YES;
|
||||
self.imgsBgViewHeightCon.constant = 0;
|
||||
for (UIImageView *imgV in self.imgViewsArray) {
|
||||
imgV.hidden = YES;
|
||||
}
|
||||
CGFloat imgWidth = (SCREEN_WIDTH-16*2-12*2-10*2)/3;
|
||||
UIImageView *firstImgV = self.imgViewsArray.firstObject;
|
||||
[firstImgV mas_updateConstraints:^(MASConstraintMaker *make) {
|
||||
make.size.mas_equalTo(CGSizeMake(imgWidth, imgWidth));
|
||||
}];
|
||||
NSArray *images;
|
||||
if (model.images.length > 0) {
|
||||
images = [model.images componentsSeparatedByString:@","];
|
||||
}
|
||||
if (images.count > 0) {
|
||||
for (NSInteger i = 0; i < images.count; i++) {
|
||||
if (i < self.imgViewsArray.count) {
|
||||
UIImageView *imgV = self.imgViewsArray[i];
|
||||
imgV.hidden = NO;
|
||||
[imgV sd_setImageWithURL:[NSURL URLWithString:images[i]]];
|
||||
}
|
||||
}
|
||||
if (images.count == 1) {//特殊
|
||||
CGFloat itemW = (SCREEN_WIDTH-15-15-15)/2;
|
||||
CGFloat imgBgHeight = itemW;
|
||||
self.imgsBgView.hidden = NO;
|
||||
self.imgsBgViewHeightCon.constant = imgBgHeight;
|
||||
[firstImgV mas_updateConstraints:^(MASConstraintMaker *make) {
|
||||
make.size.mas_equalTo(CGSizeMake(itemW, imgBgHeight));
|
||||
}];
|
||||
}else {
|
||||
CGFloat itemW = (SCREEN_WIDTH-16*2-12*2-10*2)/3;
|
||||
CGFloat imgBgHeight = 0;
|
||||
NSInteger lines = images.count%3 == 0 ? images.count/3 : images.count/3+1;
|
||||
imgBgHeight = itemW*lines + 10*(lines-1);
|
||||
self.imgsBgView.hidden = NO;
|
||||
self.imgsBgViewHeightCon.constant = imgBgHeight;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (model.room_id.intValue > 0) {
|
||||
[self setBtnTypeWithIsFollow:YES];
|
||||
}else{
|
||||
[self setBtnTypeWithIsFollow:NO];
|
||||
}
|
||||
if (self.cellType == QXDynamicListCellDetail) {
|
||||
self.bgLeftCon.constant = 0;
|
||||
self.bgRightCon.constant = 0;
|
||||
if (model.like_list.count == 0) {
|
||||
self.userImageView1.hidden = YES;
|
||||
self.userImageView2.hidden = YES;
|
||||
self.userImageView3.hidden = YES;
|
||||
self.likeViewBtn.hidden = YES;
|
||||
self.likeCountLabel.hidden = YES;
|
||||
}else if (model.like_list.count == 1) {
|
||||
self.likeViewBtn.hidden = NO;
|
||||
self.likeCountLabel.hidden = NO;
|
||||
self.userImageView1.hidden = NO;
|
||||
QXDynamicLikeModel *md = model.like_list.firstObject;
|
||||
[self.userImageView1 sd_setImageWithURL:[NSURL URLWithString:md.avatar] placeholderImage:[UIImage imageNamed:@"user_header_placehoulder"]];
|
||||
self.userImageView2.hidden = YES;
|
||||
self.userImageView3.hidden = YES;
|
||||
self.likeCountLabel.text = [NSString localizedStringWithFormat:QXText(@"等%@人点赞"),self.zanBtn.titleLabel.text];
|
||||
}else if(model.like_list.count == 2){
|
||||
self.likeCountLabel.hidden = NO;
|
||||
self.userImageView1.hidden = NO;
|
||||
self.userImageView1.hidden = NO;
|
||||
self.userImageView2.hidden = NO;
|
||||
QXDynamicLikeModel *md1 = model.like_list.firstObject;
|
||||
[self.userImageView1 sd_setImageWithURL:[NSURL URLWithString:md1.avatar] placeholderImage:[UIImage imageNamed:@"user_header_placehoulder"]];
|
||||
QXDynamicLikeModel *md2 = model.like_list[1];
|
||||
[self.userImageView2 sd_setImageWithURL:[NSURL URLWithString:md2.avatar] placeholderImage:[UIImage imageNamed:@"user_header_placehoulder"]];
|
||||
self.userImageView3.hidden = YES;
|
||||
self.likeCountLabel.text = [NSString localizedStringWithFormat:QXText(@"等%@人点赞"),self.zanBtn.titleLabel.text];
|
||||
}else{
|
||||
self.likeCountLabel.hidden = NO;
|
||||
self.userImageView1.hidden = NO;
|
||||
self.userImageView1.hidden = NO;
|
||||
self.userImageView2.hidden = NO;
|
||||
self.userImageView3.hidden = NO;
|
||||
QXDynamicLikeModel *md1 = model.like_list.firstObject;
|
||||
[self.userImageView1 sd_setImageWithURL:[NSURL URLWithString:md1.avatar] placeholderImage:[UIImage imageNamed:@"user_header_placehoulder"]];
|
||||
QXDynamicLikeModel *md2 = model.like_list[1];
|
||||
[self.userImageView2 sd_setImageWithURL:[NSURL URLWithString:md2.avatar] placeholderImage:[UIImage imageNamed:@"user_header_placehoulder"]];
|
||||
QXDynamicLikeModel *md3 = model.like_list[2];
|
||||
[self.userImageView3 sd_setImageWithURL:[NSURL URLWithString:md3.avatar] placeholderImage:[UIImage imageNamed:@"user_header_placehoulder"]];
|
||||
self.likeCountLabel.text = [NSString localizedStringWithFormat:QXText(@"等%@人点赞"),self.zanBtn.titleLabel.text];
|
||||
}
|
||||
self.focusBtn.hidden = NO;
|
||||
}else if (self.cellType == QXDynamicListCellDynamic) {
|
||||
self.userImageView1.hidden = YES;
|
||||
self.userImageView2.hidden = YES;
|
||||
self.userImageView3.hidden = YES;
|
||||
self.likeViewBtn.hidden = YES;
|
||||
self.likeCountLabel.hidden = YES;
|
||||
self.focusBtn.hidden = NO;
|
||||
}else{
|
||||
self.userImageView1.hidden = YES;
|
||||
self.userImageView2.hidden = YES;
|
||||
self.userImageView3.hidden = YES;
|
||||
self.likeViewBtn.hidden = YES;
|
||||
self.likeCountLabel.hidden = YES;
|
||||
self.focusBtn.hidden = YES;
|
||||
}
|
||||
|
||||
if ([self.model.user_id isEqualToString:[QXGlobal shareGlobal].loginModel.user_id]) {
|
||||
self.focusBtn.hidden = YES;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)createUI {
|
||||
CGFloat imgWidth = (SCREEN_WIDTH-16*2-12*2-10*2)/3;
|
||||
for (NSInteger i = 0; i < 9; i++) {
|
||||
UIImageView *imgV = [[UIImageView alloc] init];
|
||||
imgV.tag = i+100;
|
||||
imgV.userInteractionEnabled = YES;
|
||||
MJWeakSelf
|
||||
// [imgV dg_Tapped:^{
|
||||
// [weakSelf onPreviewImage:imgV];
|
||||
// }];
|
||||
[imgV addTapBlock:^(id _Nonnull obj) {
|
||||
[weakSelf previewPhotoWithCurrentIndex:imgV.tag-100];
|
||||
}];
|
||||
imgV.hidden = YES;
|
||||
imgV.layer.masksToBounds = YES;
|
||||
imgV.layer.cornerRadius = 10;
|
||||
imgV.contentMode = UIViewContentModeScaleAspectFill;
|
||||
[self.imgsBgView addSubview:imgV];
|
||||
[self.imgViewsArray addObject:imgV];
|
||||
|
||||
[imgV mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.equalTo(self.imgsBgView).offset((imgWidth+10)*(i/3));
|
||||
make.left.equalTo(self.imgsBgView).offset((imgWidth+10)*(i%3));
|
||||
make.size.mas_equalTo(CGSizeMake(imgWidth, imgWidth));
|
||||
}];
|
||||
}
|
||||
}
|
||||
-(void)previewPhotoWithCurrentIndex:(NSInteger)currentIndex{
|
||||
NSArray *images = [self.model.images componentsSeparatedByString:@","];
|
||||
YBImageBrowser *browser = [YBImageBrowser new];
|
||||
NSMutableArray *sourceArray = [NSMutableArray array];
|
||||
for (int i = 0 ; i <images.count;i++) {
|
||||
NSString *url = images[i];
|
||||
YBIBImageData *data = [[YBIBImageData alloc] init];
|
||||
data.imageURL = [NSURL URLWithString:url];
|
||||
UIImageView *imageView = [self viewWithTag:100+i];
|
||||
data.projectiveView = imageView;
|
||||
[sourceArray addObject:data];
|
||||
}
|
||||
browser.dataSourceArray = sourceArray;
|
||||
browser.currentPage = currentIndex;
|
||||
[browser show];
|
||||
}
|
||||
- (IBAction)onFocus:(id)sender {
|
||||
if (!QXGlobal.shareGlobal.isLogin) {
|
||||
[[QXGlobal shareGlobal] logOut];
|
||||
return;
|
||||
}
|
||||
if (self.model.room_id.intValue > 0) {
|
||||
// 去房间
|
||||
[[QXGlobal shareGlobal] joinRoomWithRoomId:self.model.room_id isRejoin:NO navagationController:self.navigationController];
|
||||
}else{
|
||||
//去聊天
|
||||
// 去聊天
|
||||
[[QXGlobal shareGlobal] chatWithUserID:self.model.user_id nickname:self.model.nickname avatar:self.model.avatar navagationController:self.navigationController];
|
||||
}
|
||||
}
|
||||
- (IBAction)commentAction:(id)sender {
|
||||
if (!QXGlobal.shareGlobal.isLogin) {
|
||||
[[QXGlobal shareGlobal] logOut];
|
||||
return;
|
||||
}
|
||||
switch (self.cellType) {
|
||||
case QXDynamicListCellDetail:
|
||||
|
||||
break;
|
||||
case QXDynamicListCellDynamic:{
|
||||
QXDynamicDetailViewController *vc = [[QXDynamicDetailViewController alloc] init];
|
||||
vc.model = self.model;
|
||||
[self.navigationController pushViewController:vc animated:YES];
|
||||
}
|
||||
|
||||
break;
|
||||
case QXDynamicListCellHomePage:{
|
||||
QXDynamicDetailViewController *vc = [[QXDynamicDetailViewController alloc] init];
|
||||
vc.model = self.model;
|
||||
[self.navigationController pushViewController:vc animated:YES];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)onZan:(UIButton*)sender {
|
||||
if (!QXGlobal.shareGlobal.isLogin) {
|
||||
[[QXGlobal shareGlobal] logOut];
|
||||
return;
|
||||
}
|
||||
BOOL isLike = !sender.selected;
|
||||
MJWeakSelf
|
||||
[QXDynamicNetwork likeDynamicWithId:self.model.id isLike:isLike successBlock:^(NSDictionary * _Nonnull dict) {
|
||||
weakSelf.zanBtn.selected = !weakSelf.zanBtn.selected;
|
||||
if (weakSelf.zanBtn.selected) {
|
||||
[weakSelf.zanBtn setTitle:[NSString stringWithFormat:@"%ld", weakSelf.model.like_num.integerValue+1] forState:UIControlStateNormal];
|
||||
}else{
|
||||
[weakSelf.zanBtn setTitle:[NSString stringWithFormat:@"%ld", weakSelf.model.like_num.integerValue] forState:UIControlStateNormal];
|
||||
}
|
||||
} failBlock:^(NSError * _Nonnull error, NSString * _Nonnull msg) {
|
||||
|
||||
}];
|
||||
|
||||
}
|
||||
|
||||
- (IBAction)onHomepage:(id)sender {
|
||||
if (!QXGlobal.shareGlobal.isLogin) {
|
||||
[[QXGlobal shareGlobal] logOut];
|
||||
return;
|
||||
}
|
||||
if (self.cellType == QXDynamicListCellHomePage) {
|
||||
return;
|
||||
}
|
||||
QXUserHomePageViewController *vc = [[QXUserHomePageViewController alloc] init];
|
||||
vc.user_id = self.model.user_id;
|
||||
[self.navigationController pushViewController:vc animated:YES];
|
||||
}
|
||||
|
||||
- (IBAction)onMore:(id)sender {
|
||||
if (!QXGlobal.shareGlobal.isLogin) {
|
||||
[[QXGlobal shareGlobal] logOut];
|
||||
return;
|
||||
}
|
||||
QXShareView *shareView = [[QXShareView alloc] init];
|
||||
shareView.shareType = QXShareViewTypeFind;
|
||||
shareView.delegate = self;
|
||||
shareView.dynamicModel = self.model;
|
||||
[shareView showInView:KEYWINDOW];
|
||||
}
|
||||
- (IBAction)likeViewAction:(id)sender {
|
||||
if (!QXGlobal.shareGlobal.isLogin) {
|
||||
[[QXGlobal shareGlobal] logOut];
|
||||
return;
|
||||
}
|
||||
QXDynamicLikeListView *listView = [[QXDynamicLikeListView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT)];
|
||||
listView.Id = self.model.id;
|
||||
listView.num = [NSString localizedStringWithFormat:QXText(@"已有%@人点赞"),self.zanBtn.titleLabel.text];
|
||||
[listView showInView:KEYWINDOW];
|
||||
}
|
||||
|
||||
-(void)didClickShareModel:(QXShareViewModel *)model{
|
||||
if ([model.name isEqualToString:QXText(@"删除")]) {
|
||||
MJWeakSelf
|
||||
QXAlertView *al = [[QXAlertView alloc] initWithFrame:CGRectMake(0, 0, ScaleWidth(300), ScaleWidth(175))];
|
||||
al.type = QXAlertViewTypeDeleteDynamic;
|
||||
al.commitBlock = ^{
|
||||
[weakSelf deleteDynamic];
|
||||
};
|
||||
[[QXGlobal shareGlobal] showView:al popType:(PopViewTypeTopToCenter) tapDismiss:NO finishBlock:^{
|
||||
|
||||
}];
|
||||
}else if ([model.name isEqualToString:QXText(@"复制链接")]) {
|
||||
UIPasteboard *p = [UIPasteboard generalPasteboard];
|
||||
p.string = [NSString stringWithFormat:@"%@", self.model.share_url];
|
||||
showToast(@"复制成功");
|
||||
}else if ([model.name isEqualToString:QXText(@"举报")]) {
|
||||
QXReportViewController *reportVC = [[QXReportViewController alloc] init];
|
||||
reportVC.reportType = @"3";
|
||||
reportVC.fromId = self.model.id;
|
||||
[self.navigationController pushViewController:reportVC animated:YES];
|
||||
}
|
||||
}
|
||||
|
||||
-(void)deleteDynamic{
|
||||
MJWeakSelf
|
||||
[QXDynamicNetwork deleteDynamicWithId:self.model.id successBlock:^(NSDictionary * _Nonnull dict) {
|
||||
if (weakSelf.onDeleteBlock) {
|
||||
weakSelf.onDeleteBlock(weakSelf.model);
|
||||
}
|
||||
} failBlock:^(NSError * _Nonnull error, NSString * _Nonnull msg) {
|
||||
|
||||
}];
|
||||
}
|
||||
-(void)onReport {
|
||||
// SPTrendReportVC *vc = [[SPTrendReportVC alloc] init];
|
||||
// vc.userId = self.model.uid;
|
||||
// [vc pushSelf];
|
||||
}
|
||||
- (IBAction)giveAction:(id)sender {
|
||||
// QXAlertViewController *al = [[QXAlertViewController alloc] init];
|
||||
// al.alertView = sendView;
|
||||
// al.tapDismiss = YES;
|
||||
// al.popType = PopViewTypeBottomToUpActionSheet;
|
||||
// self.sendView.vc = self.viewController;
|
||||
if (!QXGlobal.shareGlobal.isLogin) {
|
||||
[[QXGlobal shareGlobal] logOut];
|
||||
return;
|
||||
}
|
||||
self.sendView.dynamicId = self.model.id;
|
||||
MJWeakSelf
|
||||
self.sendView.sendSuccessBlock = ^(NSString * _Nonnull dynamicId) {
|
||||
[weakSelf reloadDetail];
|
||||
[weakSelf.sendView hide];
|
||||
self->_sendView = nil;
|
||||
};
|
||||
[self.sendView showInView:KEYWINDOW];
|
||||
|
||||
// al.modalPresentationStyle = UIModalPresentationOverFullScreen;
|
||||
// [self.viewController presentViewController:al animated:NO completion:nil];
|
||||
}
|
||||
|
||||
-(void)reloadDetail{
|
||||
MJWeakSelf
|
||||
[QXDynamicNetwork dynamicPageWithId:self.model.id successBlock:^(QXDynamicModel * _Nonnull model) {
|
||||
weakSelf.model = model;
|
||||
[weakSelf setModel:model];
|
||||
} failBlock:^(NSError * _Nonnull error, NSString * _Nonnull msg) {
|
||||
|
||||
}];
|
||||
}
|
||||
|
||||
-(void)setBtnTypeWithIsFollow:(BOOL)isFollow{
|
||||
[self.focusBtn setTitle:isFollow?QXText(@"跟随"):QXText(@"私信") forState:(UIControlStateNormal)];
|
||||
[self.focusBtn setTitleColor:UIColor.whiteColor forState:(UIControlStateNormal)];
|
||||
self.focusBtn.backgroundColor = RGB16(0x333333);
|
||||
self.focusBtn.titleLabel.font = [UIFont systemFontOfSize:14];
|
||||
[self.focusBtn addRoundedCornersWithRadius:12.5];
|
||||
}
|
||||
-(QXSendGiftView *)sendView{
|
||||
if (!_sendView) {
|
||||
_sendView = [[QXSendGiftView alloc] initWithType:(QXSendGiftViewTypeFind)];
|
||||
// QXAlertViewController *al = [[QXAlertViewController alloc] init];
|
||||
// al.alertView = sendView;
|
||||
// al.tapDismiss = YES;
|
||||
// al.popType = PopViewTypeBottomToUpActionSheet;
|
||||
[_sendView reloadData];
|
||||
}
|
||||
return _sendView;
|
||||
}
|
||||
@end
|
||||
345
QXLive/Dynamic(语圈)/View/QXDynamicListCell.xib
Executable file
345
QXLive/Dynamic(语圈)/View/QXDynamicListCell.xib
Executable file
@@ -0,0 +1,345 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
|
||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23506"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" rowHeight="235" id="KGk-i7-Jjw" customClass="QXDynamicListCell">
|
||||
<rect key="frame" x="0.0" y="0.0" width="436" height="152"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM">
|
||||
<rect key="frame" x="0.0" y="0.0" width="436" height="152"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="FEa-6s-S1q">
|
||||
<rect key="frame" x="16" y="6" width="404" height="140"/>
|
||||
<subviews>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="iFl-Jk-YzR">
|
||||
<rect key="frame" x="12" y="12" width="50" height="50"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="50" id="8Ho-cM-60x"/>
|
||||
<constraint firstAttribute="height" constant="50" id="h0K-eb-9YA"/>
|
||||
</constraints>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
|
||||
<real key="value" value="25"/>
|
||||
</userDefinedRuntimeAttribute>
|
||||
<userDefinedRuntimeAttribute type="boolean" keyPath="layer.masksToBounds" value="YES"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</imageView>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="vk2-bh-wsO" customClass="QXSeatHeaderView">
|
||||
<rect key="frame" x="12" y="12" width="50" height="50"/>
|
||||
</view>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="nKt-dS-UFi">
|
||||
<rect key="frame" x="46" y="46" width="16" height="16"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="16" id="LAw-FW-P22"/>
|
||||
<constraint firstAttribute="width" constant="16" id="Rnl-1o-McO"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="gzL-1m-sSx">
|
||||
<rect key="frame" x="72" y="19" width="40" height="18"/>
|
||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
|
||||
<color key="textColor" red="0.12941176470588234" green="0.12941176470588234" blue="0.12941176470588234" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<imageView hidden="YES" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="slU-4Q-xRo">
|
||||
<rect key="frame" x="118" y="20.5" width="15" height="15"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="15" id="OBm-DF-7Rk"/>
|
||||
<constraint firstAttribute="width" constant="15" id="vaN-Ip-2ve"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="s4f-xe-cfP">
|
||||
<rect key="frame" x="72" y="45" width="31.5" height="14.5"/>
|
||||
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="12"/>
|
||||
<color key="textColor" red="0.59999999999999998" green="0.59999999999999998" blue="0.59999999999999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="XGd-g3-CJu">
|
||||
<rect key="frame" x="12" y="74" width="380" height="11"/>
|
||||
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="14"/>
|
||||
<color key="textColor" red="0.12941176470588234" green="0.12941176470588234" blue="0.12941176470588234" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="xKO-5c-aaJ">
|
||||
<rect key="frame" x="12" y="96" width="380" height="0.0"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" id="pz4-85-F5Q"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="0i8-vW-sax">
|
||||
<rect key="frame" x="0.0" y="96" width="404" height="44"/>
|
||||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="EKa-4e-K1g">
|
||||
<rect key="frame" x="172" y="7" width="70" height="30"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="70" id="V3Y-g1-oI6"/>
|
||||
<constraint firstAttribute="height" constant="30" id="dgb-HX-3qu"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="14"/>
|
||||
<inset key="titleEdgeInsets" minX="5" minY="0.0" maxX="0.0" maxY="0.0"/>
|
||||
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="5" maxY="0.0"/>
|
||||
<state key="normal" title="0" image="dynamic_comment">
|
||||
<color key="titleColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="commentAction:" destination="KGk-i7-Jjw" eventType="touchUpInside" id="KTj-Zd-Dnp"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="S5y-fG-SnS">
|
||||
<rect key="frame" x="247" y="8" width="70" height="30"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="30" id="Eev-1U-blc"/>
|
||||
<constraint firstAttribute="width" constant="70" id="JXW-ug-osW"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="14"/>
|
||||
<inset key="titleEdgeInsets" minX="5" minY="0.0" maxX="0.0" maxY="0.0"/>
|
||||
<inset key="imageEdgeInsets" minX="0.0" minY="2" maxX="5" maxY="0.0"/>
|
||||
<state key="normal" title="0" image="dynamic_like">
|
||||
<color key="titleColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</state>
|
||||
<state key="selected" image="dynamic_like_sel">
|
||||
<color key="titleColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="onZan:" destination="KGk-i7-Jjw" eventType="touchUpInside" id="bEY-DV-IGu"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Jjl-ep-Ior">
|
||||
<rect key="frame" x="322" y="7" width="70" height="30"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="30" id="6Uo-qy-hOs"/>
|
||||
<constraint firstAttribute="width" constant="70" id="pcM-Th-kf6"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="14"/>
|
||||
<inset key="titleEdgeInsets" minX="5" minY="0.0" maxX="0.0" maxY="0.0"/>
|
||||
<inset key="imageEdgeInsets" minX="0.0" minY="2" maxX="5" maxY="0.0"/>
|
||||
<state key="normal" title="0" image="dynamic_give">
|
||||
<color key="titleColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</state>
|
||||
<state key="selected" image="trend_zan_sel">
|
||||
<color key="titleColor" red="0.57254901960000004" green="0.28627450980000002" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="giveAction:" destination="KGk-i7-Jjw" eventType="touchUpInside" id="81t-bQ-N6F"/>
|
||||
</connections>
|
||||
</button>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="rSB-IC-yLc">
|
||||
<rect key="frame" x="12" y="15" width="14" height="14"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="14" id="Ljn-Kf-utR"/>
|
||||
<constraint firstAttribute="height" constant="14" id="p75-do-YHv"/>
|
||||
</constraints>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="boolean" keyPath="layer.masksToBounds" value="YES"/>
|
||||
<userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
|
||||
<integer key="value" value="7"/>
|
||||
</userDefinedRuntimeAttribute>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</imageView>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="jZt-T7-Wn2">
|
||||
<rect key="frame" x="21" y="15" width="14" height="14"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="14" id="OcC-ac-TLM"/>
|
||||
<constraint firstAttribute="width" constant="14" id="PYK-z6-0qB"/>
|
||||
</constraints>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="boolean" keyPath="layer.masksToBounds" value="YES"/>
|
||||
<userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
|
||||
<integer key="value" value="7"/>
|
||||
</userDefinedRuntimeAttribute>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</imageView>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="mgq-EX-fSI">
|
||||
<rect key="frame" x="30" y="15" width="14" height="14"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="14" id="Oyp-Lt-cfG"/>
|
||||
<constraint firstAttribute="height" constant="14" id="yeO-Qa-e2X"/>
|
||||
</constraints>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="boolean" keyPath="layer.masksToBounds" value="YES"/>
|
||||
<userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
|
||||
<integer key="value" value="7"/>
|
||||
</userDefinedRuntimeAttribute>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</imageView>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="SkL-b5-rlj">
|
||||
<rect key="frame" x="47" y="15" width="120" height="14.5"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="12"/>
|
||||
<color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Avw-XH-qrb">
|
||||
<rect key="frame" x="12" y="4.5" width="155" height="35"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="35" id="erH-l2-lcl"/>
|
||||
</constraints>
|
||||
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
|
||||
<connections>
|
||||
<action selector="likeViewAction:" destination="KGk-i7-Jjw" eventType="touchUpInside" id="ZTN-ot-yW2"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstItem="jZt-T7-Wn2" firstAttribute="leading" secondItem="rSB-IC-yLc" secondAttribute="trailing" constant="-5" id="2Ib-Dy-i17"/>
|
||||
<constraint firstItem="Jjl-ep-Ior" firstAttribute="centerY" secondItem="0i8-vW-sax" secondAttribute="centerY" id="4f7-N6-bwy"/>
|
||||
<constraint firstItem="SkL-b5-rlj" firstAttribute="centerY" secondItem="rSB-IC-yLc" secondAttribute="centerY" id="9dX-bU-0tW"/>
|
||||
<constraint firstItem="mgq-EX-fSI" firstAttribute="top" secondItem="rSB-IC-yLc" secondAttribute="top" id="CGL-dM-rHg"/>
|
||||
<constraint firstItem="SkL-b5-rlj" firstAttribute="leading" secondItem="mgq-EX-fSI" secondAttribute="trailing" constant="3" id="JRF-TW-TOd"/>
|
||||
<constraint firstItem="S5y-fG-SnS" firstAttribute="centerY" secondItem="0i8-vW-sax" secondAttribute="centerY" constant="1" id="O7I-Td-ldi"/>
|
||||
<constraint firstItem="mgq-EX-fSI" firstAttribute="leading" secondItem="jZt-T7-Wn2" secondAttribute="trailing" constant="-5" id="P30-wH-iQV"/>
|
||||
<constraint firstItem="Avw-XH-qrb" firstAttribute="centerY" secondItem="rSB-IC-yLc" secondAttribute="centerY" id="PJy-0P-XVJ"/>
|
||||
<constraint firstItem="S5y-fG-SnS" firstAttribute="leading" secondItem="EKa-4e-K1g" secondAttribute="trailing" constant="5" id="PzI-EM-1dk"/>
|
||||
<constraint firstItem="jZt-T7-Wn2" firstAttribute="top" secondItem="rSB-IC-yLc" secondAttribute="top" id="Spz-Uu-qba"/>
|
||||
<constraint firstItem="Avw-XH-qrb" firstAttribute="leading" secondItem="rSB-IC-yLc" secondAttribute="leading" id="UcG-Dj-JzT"/>
|
||||
<constraint firstItem="Jjl-ep-Ior" firstAttribute="leading" secondItem="S5y-fG-SnS" secondAttribute="trailing" constant="5" id="ZiO-Ov-lfy"/>
|
||||
<constraint firstAttribute="height" constant="44" id="aJZ-Tj-Bff"/>
|
||||
<constraint firstItem="Avw-XH-qrb" firstAttribute="trailing" secondItem="SkL-b5-rlj" secondAttribute="trailing" id="c9I-mq-qTD"/>
|
||||
<constraint firstItem="EKa-4e-K1g" firstAttribute="leading" secondItem="SkL-b5-rlj" secondAttribute="trailing" constant="5" id="ktO-7i-Qrp"/>
|
||||
<constraint firstItem="rSB-IC-yLc" firstAttribute="centerY" secondItem="Jjl-ep-Ior" secondAttribute="centerY" id="og5-QO-H9q"/>
|
||||
<constraint firstAttribute="trailing" secondItem="Jjl-ep-Ior" secondAttribute="trailing" constant="12" id="q5A-pu-iWj"/>
|
||||
<constraint firstItem="EKa-4e-K1g" firstAttribute="centerY" secondItem="0i8-vW-sax" secondAttribute="centerY" id="qBQ-fz-vcY"/>
|
||||
<constraint firstItem="rSB-IC-yLc" firstAttribute="leading" secondItem="0i8-vW-sax" secondAttribute="leading" constant="12" id="vTi-ga-8P8"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="XnQ-EM-4IC">
|
||||
<rect key="frame" x="12" y="12" width="100" height="50"/>
|
||||
<connections>
|
||||
<action selector="onHomepage:" destination="KGk-i7-Jjw" eventType="touchUpInside" id="H3O-BM-n0k"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="jzI-eZ-gdm">
|
||||
<rect key="frame" x="362" y="0.0" width="40" height="50"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="50" id="jOd-F8-n6l"/>
|
||||
<constraint firstAttribute="width" constant="40" id="vEP-wn-0YJ"/>
|
||||
</constraints>
|
||||
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
|
||||
<state key="normal" image="dynamic_more"/>
|
||||
<connections>
|
||||
<action selector="onMore:" destination="KGk-i7-Jjw" eventType="touchUpInside" id="ljO-t9-GAH"/>
|
||||
</connections>
|
||||
</button>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="80W-MV-Snb">
|
||||
<rect key="frame" x="0.0" y="140" width="404" height="0.0"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.049149908987032316" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" id="Okg-di-KRQ"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<button opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="KBv-qN-JAr">
|
||||
<rect key="frame" x="287" y="12.5" width="70" height="25"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="25" id="JXr-Sj-Gnx"/>
|
||||
<constraint firstAttribute="width" constant="70" id="sja-gQ-iRl"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="12"/>
|
||||
<color key="tintColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<state key="normal">
|
||||
<color key="titleColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</state>
|
||||
<state key="selected" image="trend_focus_sel">
|
||||
<color key="titleColor" red="0.50196078431372548" green="0.50196078431372548" blue="0.59607843137254901" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="onFocus:" destination="KGk-i7-Jjw" eventType="touchUpInside" id="j6Y-rX-j41"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstItem="vk2-bh-wsO" firstAttribute="top" secondItem="iFl-Jk-YzR" secondAttribute="top" id="0s9-8o-8YE"/>
|
||||
<constraint firstItem="XnQ-EM-4IC" firstAttribute="bottom" secondItem="iFl-Jk-YzR" secondAttribute="bottom" id="2ac-w2-BKA"/>
|
||||
<constraint firstItem="s4f-xe-cfP" firstAttribute="leading" secondItem="gzL-1m-sSx" secondAttribute="leading" id="38p-VS-qLr"/>
|
||||
<constraint firstAttribute="bottom" secondItem="80W-MV-Snb" secondAttribute="bottom" id="3h2-58-lfe"/>
|
||||
<constraint firstItem="jzI-eZ-gdm" firstAttribute="top" secondItem="FEa-6s-S1q" secondAttribute="top" id="89I-UH-pXs"/>
|
||||
<constraint firstAttribute="trailing" secondItem="jzI-eZ-gdm" secondAttribute="trailing" constant="2" id="Cme-Hw-cqe"/>
|
||||
<constraint firstItem="0i8-vW-sax" firstAttribute="leading" secondItem="FEa-6s-S1q" secondAttribute="leading" id="F8G-QN-wtB"/>
|
||||
<constraint firstItem="XnQ-EM-4IC" firstAttribute="leading" secondItem="iFl-Jk-YzR" secondAttribute="leading" id="Hgn-gx-xME"/>
|
||||
<constraint firstAttribute="trailing" secondItem="0i8-vW-sax" secondAttribute="trailing" id="LDf-pd-BxE"/>
|
||||
<constraint firstItem="nKt-dS-UFi" firstAttribute="bottom" secondItem="vk2-bh-wsO" secondAttribute="bottom" id="Nja-UU-BcF"/>
|
||||
<constraint firstItem="vk2-bh-wsO" firstAttribute="leading" secondItem="iFl-Jk-YzR" secondAttribute="leading" id="P2L-Sd-ymb"/>
|
||||
<constraint firstItem="gzL-1m-sSx" firstAttribute="leading" secondItem="iFl-Jk-YzR" secondAttribute="trailing" constant="10" id="Pxx-kz-iUB"/>
|
||||
<constraint firstItem="XnQ-EM-4IC" firstAttribute="trailing" secondItem="gzL-1m-sSx" secondAttribute="trailing" id="RZH-11-ZZs"/>
|
||||
<constraint firstItem="iFl-Jk-YzR" firstAttribute="leading" secondItem="FEa-6s-S1q" secondAttribute="leading" constant="12" id="S1l-dI-KHD"/>
|
||||
<constraint firstItem="gzL-1m-sSx" firstAttribute="top" secondItem="iFl-Jk-YzR" secondAttribute="top" constant="7" id="VC5-4G-7Gw"/>
|
||||
<constraint firstItem="iFl-Jk-YzR" firstAttribute="top" secondItem="FEa-6s-S1q" secondAttribute="top" constant="12" id="Vjt-qY-whB"/>
|
||||
<constraint firstItem="0i8-vW-sax" firstAttribute="top" secondItem="xKO-5c-aaJ" secondAttribute="bottom" id="WDL-Wr-cuB"/>
|
||||
<constraint firstAttribute="bottom" secondItem="0i8-vW-sax" secondAttribute="bottom" id="Xon-6v-maS"/>
|
||||
<constraint firstItem="XGd-g3-CJu" firstAttribute="leading" secondItem="FEa-6s-S1q" secondAttribute="leading" constant="12" id="bKS-fP-sXh"/>
|
||||
<constraint firstItem="XnQ-EM-4IC" firstAttribute="top" secondItem="iFl-Jk-YzR" secondAttribute="top" id="dMG-bF-Wg3"/>
|
||||
<constraint firstItem="KBv-qN-JAr" firstAttribute="centerY" secondItem="jzI-eZ-gdm" secondAttribute="centerY" id="dcA-w8-qQN"/>
|
||||
<constraint firstItem="XGd-g3-CJu" firstAttribute="top" secondItem="iFl-Jk-YzR" secondAttribute="bottom" constant="12" id="eEd-f0-9fK"/>
|
||||
<constraint firstItem="xKO-5c-aaJ" firstAttribute="leading" secondItem="XGd-g3-CJu" secondAttribute="leading" id="fLw-df-ckN"/>
|
||||
<constraint firstItem="slU-4Q-xRo" firstAttribute="leading" secondItem="gzL-1m-sSx" secondAttribute="trailing" constant="6" id="g49-EX-wEM"/>
|
||||
<constraint firstItem="vk2-bh-wsO" firstAttribute="bottom" secondItem="iFl-Jk-YzR" secondAttribute="bottom" id="hsd-6k-jET"/>
|
||||
<constraint firstItem="xKO-5c-aaJ" firstAttribute="top" secondItem="XGd-g3-CJu" secondAttribute="bottom" constant="11" id="j8o-e5-R6g"/>
|
||||
<constraint firstAttribute="trailing" secondItem="80W-MV-Snb" secondAttribute="trailing" id="jB9-yk-qTN"/>
|
||||
<constraint firstItem="s4f-xe-cfP" firstAttribute="top" secondItem="gzL-1m-sSx" secondAttribute="bottom" constant="8" id="jff-zj-ite"/>
|
||||
<constraint firstItem="80W-MV-Snb" firstAttribute="leading" secondItem="FEa-6s-S1q" secondAttribute="leading" id="jnc-2p-hcR"/>
|
||||
<constraint firstItem="jzI-eZ-gdm" firstAttribute="leading" secondItem="KBv-qN-JAr" secondAttribute="trailing" constant="5" id="kv0-Li-FDy"/>
|
||||
<constraint firstItem="nKt-dS-UFi" firstAttribute="trailing" secondItem="vk2-bh-wsO" secondAttribute="trailing" id="nVC-Xf-S6M"/>
|
||||
<constraint firstItem="slU-4Q-xRo" firstAttribute="centerY" secondItem="gzL-1m-sSx" secondAttribute="centerY" id="p8d-jw-X6X"/>
|
||||
<constraint firstAttribute="trailing" secondItem="XGd-g3-CJu" secondAttribute="trailing" constant="12" id="sMu-dZ-CIe"/>
|
||||
<constraint firstItem="vk2-bh-wsO" firstAttribute="trailing" secondItem="iFl-Jk-YzR" secondAttribute="trailing" id="sYt-vO-dxf"/>
|
||||
<constraint firstItem="xKO-5c-aaJ" firstAttribute="trailing" secondItem="XGd-g3-CJu" secondAttribute="trailing" id="ufS-2M-IcL"/>
|
||||
</constraints>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="boolean" keyPath="layer.masksToBounds" value="YES"/>
|
||||
<userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
|
||||
<integer key="value" value="16"/>
|
||||
</userDefinedRuntimeAttribute>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</view>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="FEa-6s-S1q" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" constant="16" id="3Vj-wd-HM3"/>
|
||||
<constraint firstAttribute="bottom" secondItem="FEa-6s-S1q" secondAttribute="bottom" constant="6" id="716-YN-jJw"/>
|
||||
<constraint firstItem="FEa-6s-S1q" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="top" constant="6" id="U2e-RQ-yQk"/>
|
||||
<constraint firstAttribute="trailing" secondItem="FEa-6s-S1q" secondAttribute="trailing" constant="16" id="p42-QY-zTx"/>
|
||||
</constraints>
|
||||
</tableViewCellContentView>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<connections>
|
||||
<outlet property="avatarImgV" destination="vk2-bh-wsO" id="PCS-cN-uVM"/>
|
||||
<outlet property="bgLeftCon" destination="3Vj-wd-HM3" id="Bsh-cK-7Tu"/>
|
||||
<outlet property="bgRightCon" destination="p42-QY-zTx" id="osh-v4-oXG"/>
|
||||
<outlet property="bgView" destination="FEa-6s-S1q" id="aia-HE-ZZo"/>
|
||||
<outlet property="commentBtn" destination="EKa-4e-K1g" id="RUU-d2-9X4"/>
|
||||
<outlet property="contentLab" destination="XGd-g3-CJu" id="79N-et-e2R"/>
|
||||
<outlet property="focusBtn" destination="KBv-qN-JAr" id="6hu-Wt-CaW"/>
|
||||
<outlet property="giveBtn" destination="Jjl-ep-Ior" id="zSP-AO-2Li"/>
|
||||
<outlet property="imgsBgView" destination="xKO-5c-aaJ" id="i8U-8p-HAZ"/>
|
||||
<outlet property="imgsBgViewHeightCon" destination="pz4-85-F5Q" id="BVd-Eq-IRQ"/>
|
||||
<outlet property="likeCountLabel" destination="SkL-b5-rlj" id="SCq-dQ-i87"/>
|
||||
<outlet property="likeViewBtn" destination="Avw-XH-qrb" id="TrC-Wd-RVW"/>
|
||||
<outlet property="nicknameLab" destination="gzL-1m-sSx" id="mJS-uW-MuX"/>
|
||||
<outlet property="sexImageView" destination="nKt-dS-UFi" id="uXD-tN-GaU"/>
|
||||
<outlet property="sexImgV" destination="slU-4Q-xRo" id="fsh-v7-Cfd"/>
|
||||
<outlet property="timeLab" destination="s4f-xe-cfP" id="d77-Je-mK5"/>
|
||||
<outlet property="userImageView1" destination="rSB-IC-yLc" id="zg2-hF-dBP"/>
|
||||
<outlet property="userImageView2" destination="jZt-T7-Wn2" id="uY6-kc-xWg"/>
|
||||
<outlet property="userImageView3" destination="mgq-EX-fSI" id="9A7-1p-619"/>
|
||||
<outlet property="zanBtn" destination="S5y-fG-SnS" id="Kq5-GZ-FlA"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="263.768115942029" y="150"/>
|
||||
</tableViewCell>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="dynamic_comment" width="24" height="24"/>
|
||||
<image name="dynamic_give" width="24" height="24"/>
|
||||
<image name="dynamic_like" width="24" height="24"/>
|
||||
<image name="dynamic_like_sel" width="24" height="24"/>
|
||||
<image name="dynamic_more" width="24" height="24"/>
|
||||
<image name="trend_focus_sel" width="59" height="28"/>
|
||||
<image name="trend_zan_sel" width="24" height="24"/>
|
||||
</resources>
|
||||
</document>
|
||||
20
QXLive/Dynamic(语圈)/View/QXDynamicTopicCell.h
Normal file
20
QXLive/Dynamic(语圈)/View/QXDynamicTopicCell.h
Normal file
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// QXDynamicTopicCell.h
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/5/9.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "QXDynamicModel.h"
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QXDynamicTopicCell : UICollectionViewCell
|
||||
@property (weak, nonatomic) IBOutlet UILabel *titleLabel;
|
||||
@property (weak, nonatomic) IBOutlet UIImageView *topicImageView;
|
||||
@property (weak, nonatomic) IBOutlet UIImageView *tagImageView;
|
||||
@property (weak, nonatomic) IBOutlet UILabel *countLabel;
|
||||
@property (nonatomic,strong)QXTopicModel *model;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
22
QXLive/Dynamic(语圈)/View/QXDynamicTopicCell.m
Normal file
22
QXLive/Dynamic(语圈)/View/QXDynamicTopicCell.m
Normal file
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// QXDynamicTopicCell.m
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/5/9.
|
||||
//
|
||||
|
||||
#import "QXDynamicTopicCell.h"
|
||||
#import "NSString+QX.h"
|
||||
|
||||
@implementation QXDynamicTopicCell
|
||||
-(void)setModel:(QXTopicModel *)model{
|
||||
[self.topicImageView sd_setImageWithURL:[NSURL URLWithString:model.pic] placeholderImage:nil];
|
||||
self.titleLabel.text = model.title;
|
||||
self.countLabel.text = [NSString localizedStringWithFormat:QXText(@"%@条动态"),[NSString qx_showHotCountNum:model.count.longLongValue]];
|
||||
}
|
||||
- (void)awakeFromNib {
|
||||
[super awakeFromNib];
|
||||
// Initialization code
|
||||
}
|
||||
|
||||
@end
|
||||
82
QXLive/Dynamic(语圈)/View/QXDynamicTopicCell.xib
Normal file
82
QXLive/Dynamic(语圈)/View/QXDynamicTopicCell.xib
Normal file
@@ -0,0 +1,82 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23506"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" id="gTV-IL-0wX" customClass="QXDynamicTopicCell">
|
||||
<rect key="frame" x="0.0" y="0.0" width="260" height="45"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
|
||||
<rect key="frame" x="0.0" y="0.0" width="260" height="45"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="VZ2-zn-s54">
|
||||
<rect key="frame" x="0.0" y="0.0" width="45" height="45"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" secondItem="VZ2-zn-s54" secondAttribute="height" multiplier="1:1" id="3ik-gC-t5O"/>
|
||||
</constraints>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="boolean" keyPath="layer.masksToBounds" value="YES"/>
|
||||
<userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
|
||||
<integer key="value" value="4"/>
|
||||
</userDefinedRuntimeAttribute>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</imageView>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="# 萌新驾到" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="VEs-QB-WWq">
|
||||
<rect key="frame" x="52" y="0.0" width="78" height="20"/>
|
||||
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="16"/>
|
||||
<color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="dynamic_topic_tag" translatesAutoresizingMaskIntoConstraints="NO" id="RtE-EB-lWr">
|
||||
<rect key="frame" x="52" y="30" width="37" height="13"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="37" id="4j6-sN-hql"/>
|
||||
<constraint firstAttribute="height" constant="13" id="WTr-P2-WQj"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="2.92w条动态" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="rTU-7J-yig">
|
||||
<rect key="frame" x="93" y="26.666666666666671" width="72" height="20"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="20" id="VBn-jM-uVT"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="12"/>
|
||||
<color key="textColor" red="0.59999999999999998" green="0.59999999999999998" blue="0.59999999999999998" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
</view>
|
||||
<viewLayoutGuide key="safeArea" id="SEy-5g-ep8"/>
|
||||
<constraints>
|
||||
<constraint firstItem="VZ2-zn-s54" firstAttribute="leading" secondItem="gTV-IL-0wX" secondAttribute="leading" id="Esx-wY-aRk"/>
|
||||
<constraint firstItem="VEs-QB-WWq" firstAttribute="leading" secondItem="VZ2-zn-s54" secondAttribute="trailing" constant="7" id="Flk-Se-GPC"/>
|
||||
<constraint firstItem="RtE-EB-lWr" firstAttribute="leading" secondItem="VZ2-zn-s54" secondAttribute="trailing" constant="7" id="H4i-fy-dPr"/>
|
||||
<constraint firstAttribute="bottom" secondItem="VZ2-zn-s54" secondAttribute="bottom" id="WvW-oS-6y5"/>
|
||||
<constraint firstItem="VEs-QB-WWq" firstAttribute="top" secondItem="gTV-IL-0wX" secondAttribute="top" id="XCm-kM-T5b"/>
|
||||
<constraint firstItem="VZ2-zn-s54" firstAttribute="top" secondItem="gTV-IL-0wX" secondAttribute="top" id="gtA-uD-jZS"/>
|
||||
<constraint firstItem="rTU-7J-yig" firstAttribute="centerY" secondItem="RtE-EB-lWr" secondAttribute="centerY" id="jIt-Hm-jNG"/>
|
||||
<constraint firstAttribute="bottom" secondItem="RtE-EB-lWr" secondAttribute="bottom" constant="2" id="yw1-IM-rGt"/>
|
||||
<constraint firstItem="rTU-7J-yig" firstAttribute="leading" secondItem="RtE-EB-lWr" secondAttribute="trailing" constant="4" id="z97-ri-2VL"/>
|
||||
</constraints>
|
||||
<size key="customSize" width="439" height="156"/>
|
||||
<connections>
|
||||
<outlet property="countLabel" destination="rTU-7J-yig" id="ocw-kQ-niu"/>
|
||||
<outlet property="tagImageView" destination="RtE-EB-lWr" id="851-cF-Stg"/>
|
||||
<outlet property="titleLabel" destination="VEs-QB-WWq" id="c9M-Vu-nfH"/>
|
||||
<outlet property="topicImageView" destination="VZ2-zn-s54" id="LjS-Jk-r2L"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="435.87786259541986" y="57.04225352112676"/>
|
||||
</collectionViewCell>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="dynamic_topic_tag" width="37" height="13"/>
|
||||
</resources>
|
||||
</document>
|
||||
28
QXLive/Dynamic(语圈)/View/QXExpansionAppStoreView.h
Normal file
28
QXLive/Dynamic(语圈)/View/QXExpansionAppStoreView.h
Normal file
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// QXExpansionAppStoreView.h
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/7/31.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "QXUserModel.h"
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QXExpansionAppStoreView : UIView
|
||||
@property (nonatomic,strong)NSArray<QXUserHomeModel*> *users;
|
||||
@property (nonatomic,copy)void(^userBlock)(QXUserHomeModel*user);
|
||||
@end
|
||||
|
||||
|
||||
@interface QXExpansionAppStoreSubView : UIView
|
||||
@property(nonatomic,strong)UIImageView *headerImageView;
|
||||
@property(nonatomic,strong)UILabel *nameLabel;
|
||||
@property(nonatomic,strong)UIImageView *sexImageView;
|
||||
@property(nonatomic,strong)QXUserHomeModel *model;
|
||||
|
||||
- (void)startSmoothFloatAnimation ;
|
||||
|
||||
- (void)stopFloatAnimation ;
|
||||
@end
|
||||
NS_ASSUME_NONNULL_END
|
||||
379
QXLive/Dynamic(语圈)/View/QXExpansionAppStoreView.m
Normal file
379
QXLive/Dynamic(语圈)/View/QXExpansionAppStoreView.m
Normal file
@@ -0,0 +1,379 @@
|
||||
//
|
||||
// QXExpansionAppStoreView.m
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/7/31.
|
||||
//
|
||||
|
||||
#import "QXExpansionAppStoreView.h"
|
||||
#import "CKShimmerLabel.h"
|
||||
@interface QXExpansionAppStoreView()<CAAnimationDelegate>
|
||||
@property (nonatomic,strong)CKShimmerLabel *titleLabel;
|
||||
@property (nonatomic,strong)UIImageView *bgImageView;
|
||||
@property (nonatomic,strong)UIImageView *fengcheImageView;
|
||||
@property (nonatomic,strong)UIButton *changeBtn;
|
||||
@property (nonatomic,strong)NSMutableArray *randomArray;
|
||||
|
||||
@property (nonatomic,strong)QXExpansionAppStoreSubView *userView1;
|
||||
@property (nonatomic,strong)QXExpansionAppStoreSubView *userView2;
|
||||
@property (nonatomic,strong)QXExpansionAppStoreSubView *userView3;
|
||||
@property (nonatomic,strong)QXExpansionAppStoreSubView *userView4;
|
||||
@property (nonatomic,strong)NSMutableArray *userViews;
|
||||
@end
|
||||
|
||||
@implementation QXExpansionAppStoreView
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame
|
||||
{
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
[self initSubviews];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
|
||||
UIView *hitView= [super hitTest:point withEvent:event];
|
||||
if (hitView== self)
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
else
|
||||
{
|
||||
return hitView;
|
||||
}
|
||||
}
|
||||
-(void)initSubviews{
|
||||
|
||||
|
||||
self.bgImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"expansion_bg"]];
|
||||
self.bgImageView.frame = CGRectMake((self.width-375)/2, (self.height-375)/2-20, 375, 375);
|
||||
[self addSubview:self.bgImageView];
|
||||
// [self.bgImageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
// make.height.width.mas_equalTo(375);
|
||||
// make.centerX.centerY.equalTo(self);
|
||||
// }];
|
||||
|
||||
self.titleLabel = [[CKShimmerLabel alloc] init];
|
||||
self.titleLabel.shimmerWidth = 20;
|
||||
self.titleLabel.shimmerRadius = 20;
|
||||
self.titleLabel.shimmerColor = QXConfig.themeColor;
|
||||
self.titleLabel.shimmerType = ST_LeftToRight;
|
||||
self.titleLabel.repeat = YES;
|
||||
self.titleLabel.textColor = RGB16(0x333333);
|
||||
self.titleLabel.font = [UIFont fontWithName:@"YouSheBiaoTiHei" size:30];
|
||||
self.titleLabel.text = @"风车转转转,找寻新玩伴";
|
||||
self.titleLabel.top = 80;
|
||||
[self.titleLabel.contentLabel sizeToFit];
|
||||
self.titleLabel.width = self.titleLabel.contentLabel.width;
|
||||
self.titleLabel.centerX = self.centerX;
|
||||
|
||||
[self.titleLabel startShimmer];
|
||||
[self addSubview:self.titleLabel];
|
||||
|
||||
|
||||
self.fengcheImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"fengche"]];
|
||||
self.fengcheImageView.hidden = YES;
|
||||
self.fengcheImageView.frame = CGRectMake((self.width-70)/2, (self.height-70)/2-20, 70, 70);
|
||||
[self.fengcheImageView addRoundedCornersWithRadius:35];
|
||||
self.fengcheImageView.layer.borderWidth = 5;
|
||||
self.fengcheImageView.layer.borderColor = UIColor.whiteColor.CGColor;
|
||||
[self addSubview:self.fengcheImageView];
|
||||
// [self.fengcheImageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
// make.centerY.centerX.equalTo(self.bgImageView);
|
||||
// make.height.width.mas_offset(70);
|
||||
// }];
|
||||
|
||||
self.changeBtn = [[UIButton alloc] init];
|
||||
self.changeBtn.frame = self.fengcheImageView.frame;
|
||||
self.changeBtn.backgroundColor = QXConfig.themeColor;
|
||||
[self.changeBtn addRoundedCornersWithRadius:35];
|
||||
[self.changeBtn setTitle:@"换一批" forState:(UIControlStateNormal)];
|
||||
self.changeBtn.layer.borderWidth = 5;
|
||||
self.changeBtn.layer.borderColor = UIColor.whiteColor.CGColor;
|
||||
self.changeBtn.titleLabel.font = [UIFont systemFontOfSize:15];
|
||||
[self.changeBtn setTitleColor:RGB16(0x333333) forState:(UIControlStateNormal)];
|
||||
[self.changeBtn addTarget:self action:@selector(changeAction:) forControlEvents:(UIControlEventTouchUpInside)];
|
||||
[self addSubview:self.changeBtn];
|
||||
// [self.changeBtn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
// make.centerY.centerX.equalTo(self.bgImageView);
|
||||
// make.height.width.mas_offset(70);
|
||||
// }];
|
||||
|
||||
self.userView1 = [[QXExpansionAppStoreSubView alloc] initWithFrame:CGRectMake(self.bgImageView.left+40, self.bgImageView.top+28, 100, 100)];
|
||||
[self addSubview:self.userView1];
|
||||
// [self.userView1 mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
// make.left.equalTo(self.bgImageView).offset(40);
|
||||
// make.top.equalTo(self.bgImageView).offset(32);
|
||||
// make.width.mas_equalTo(100);
|
||||
// make.height.mas_equalTo(100);
|
||||
// }];
|
||||
|
||||
self.userView2 = [[QXExpansionAppStoreSubView alloc] initWithFrame:CGRectMake(self.bgImageView.right-40-100, self.bgImageView.top+28, 100, 100)];
|
||||
[self addSubview:self.userView2];
|
||||
// [self.userView2 mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
// make.right.equalTo(self.bgImageView).offset(-40);
|
||||
// make.top.equalTo(self.bgImageView).offset(32);
|
||||
// make.width.mas_equalTo(100);
|
||||
// make.height.mas_equalTo(100);
|
||||
// }];
|
||||
|
||||
self.userView3 = [[QXExpansionAppStoreSubView alloc] initWithFrame:CGRectMake(self.bgImageView.left+40, self.bgImageView.bottom-55-100, 100, 100)];
|
||||
[self addSubview:self.userView3];
|
||||
// [self.userView3 mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
// make.left.equalTo(self.bgImageView).offset(40);
|
||||
// make.bottom.equalTo(self.bgImageView).offset(-55);
|
||||
// make.width.mas_equalTo(100);
|
||||
// make.height.mas_equalTo(100);
|
||||
// }];
|
||||
|
||||
self.userView4 = [[QXExpansionAppStoreSubView alloc] initWithFrame:CGRectMake(self.bgImageView.right-40-100, self.bgImageView.bottom-55-100, 100, 100)];
|
||||
[self addSubview:self.userView4];
|
||||
// [self.userView4 mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
// make.right.equalTo(self.bgImageView).offset(-40);
|
||||
// make.bottom.equalTo(self.bgImageView).offset(-55);
|
||||
// make.width.mas_equalTo(100);
|
||||
// make.height.mas_equalTo(100);
|
||||
// }];
|
||||
[self.userViews addObject:self.userView1];
|
||||
[self.userViews addObject:self.userView2];
|
||||
[self.userViews addObject:self.userView3];
|
||||
[self.userViews addObject:self.userView4];
|
||||
MJWeakSelf
|
||||
[self.userView1 addTapBlock:^(id _Nonnull obj) {
|
||||
if (weakSelf.userBlock) {
|
||||
weakSelf.userBlock(weakSelf.userView1.model);
|
||||
}
|
||||
}];
|
||||
|
||||
[self.userView2 addTapBlock:^(id _Nonnull obj) {
|
||||
if (weakSelf.userBlock) {
|
||||
weakSelf.userBlock(weakSelf.userView2.model);
|
||||
}
|
||||
}];
|
||||
|
||||
[self.userView3 addTapBlock:^(id _Nonnull obj) {
|
||||
if (weakSelf.userBlock) {
|
||||
weakSelf.userBlock(weakSelf.userView3.model);
|
||||
}
|
||||
}];
|
||||
|
||||
[self.userView4 addTapBlock:^(id _Nonnull obj) {
|
||||
if (weakSelf.userBlock) {
|
||||
weakSelf.userBlock(weakSelf.userView4.model);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
-(void)changeAction:(UIButton*)sender{
|
||||
[self.userView1 stopFloatAnimation];
|
||||
[self.userView2 stopFloatAnimation];
|
||||
[self.userView3 stopFloatAnimation];
|
||||
[self.userView4 stopFloatAnimation];
|
||||
|
||||
self.fengcheImageView.alpha = 0;
|
||||
self.fengcheImageView.hidden = NO;
|
||||
[UIView animateWithDuration:0.3 animations:^{
|
||||
self.changeBtn.alpha = 0;
|
||||
self.fengcheImageView.alpha = 1;
|
||||
|
||||
self.userView1.centerX = self.bgImageView.centerX;
|
||||
self.userView1.centerY = self.bgImageView.centerY;
|
||||
self.userView2.centerX = self.bgImageView.centerX;
|
||||
self.userView2.centerY = self.bgImageView.centerY;
|
||||
self.userView3.centerX = self.bgImageView.centerX;
|
||||
self.userView3.centerY = self.bgImageView.centerY;
|
||||
self.userView4.centerX = self.bgImageView.centerX;
|
||||
self.userView4.centerY = self.bgImageView.centerY;
|
||||
|
||||
|
||||
self.userView1.alpha = 0;
|
||||
self.userView2.alpha = 0;
|
||||
self.userView3.alpha = 0;
|
||||
self.userView4.alpha = 0;
|
||||
|
||||
|
||||
|
||||
} completion:^(BOOL finished) {
|
||||
self.changeBtn.hidden = YES;
|
||||
[self fengchezhuan];
|
||||
}];
|
||||
|
||||
}
|
||||
|
||||
-(void)fengchezhuan{
|
||||
CABasicAnimation *rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
|
||||
//旋转角度
|
||||
rotationAnimation.toValue = [NSNumber numberWithFloat: M_PI];
|
||||
//每次旋转的时间(单位秒)
|
||||
rotationAnimation.duration = 0.2;
|
||||
// rotationAnimation.repeatCount = 15;
|
||||
rotationAnimation.delegate = self;
|
||||
rotationAnimation.cumulative = YES;
|
||||
rotationAnimation.removedOnCompletion = NO;
|
||||
//重复旋转的次数,如果你想要无数次,那么设置成MAXFLOAT
|
||||
rotationAnimation.repeatCount = 8;
|
||||
[self.fengcheImageView.layer addAnimation:rotationAnimation forKey:@"rotationAnimation"];
|
||||
}
|
||||
-(void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{
|
||||
self.changeBtn.alpha = 0;
|
||||
self.changeBtn.hidden = NO;
|
||||
self.fengcheImageView.hidden = YES;
|
||||
[self configData];
|
||||
|
||||
[UIView animateWithDuration:0.3 animations:^{
|
||||
self.changeBtn.alpha = 1;
|
||||
self.userView1.frame = CGRectMake(self.bgImageView.left+40, self.bgImageView.top+28, 100, 100);
|
||||
self.userView2.frame = CGRectMake(self.bgImageView.right-40-100, self.bgImageView.top+28, 100, 100);
|
||||
self.userView3.frame = CGRectMake(self.bgImageView.left+40, self.bgImageView.bottom-55-100, 100, 100);
|
||||
self.userView4.frame = CGRectMake(self.bgImageView.right-40-100, self.bgImageView.bottom-55-100, 100, 100);
|
||||
self.userView1.alpha = 1;
|
||||
self.userView2.alpha = 1;
|
||||
self.userView3.alpha = 1;
|
||||
self.userView4.alpha = 1;
|
||||
|
||||
} completion:^(BOOL finished) {
|
||||
[self.userView1 startSmoothFloatAnimation];
|
||||
[self.userView2 startSmoothFloatAnimation];
|
||||
[self.userView3 startSmoothFloatAnimation];
|
||||
[self.userView4 startSmoothFloatAnimation];
|
||||
}];
|
||||
}
|
||||
-(void)setUsers:(NSArray *)users{
|
||||
_users = users;
|
||||
[self changeAction:self.changeBtn];
|
||||
}
|
||||
|
||||
-(void)configData{
|
||||
[self.randomArray removeAllObjects];
|
||||
if (_users.count <= 4) {
|
||||
[self.randomArray addObjectsFromArray:self.users];
|
||||
}else{
|
||||
NSArray *rArr = [self optimizedRandomFourNumbers];
|
||||
for (NSNumber *number in rArr) {
|
||||
[self.randomArray addObject:self.users[number.integerValue]];
|
||||
}
|
||||
}
|
||||
for (int i = 0 ; i < self.randomArray.count;i++) {
|
||||
QXUserHomeModel *md = self.randomArray[i];
|
||||
QXExpansionAppStoreSubView *v = self.userViews[i];
|
||||
v.model = md;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
- (NSArray *)optimizedRandomFourNumbers {
|
||||
NSMutableArray *allNumbers = [NSMutableArray arrayWithCapacity:self.users.count-1];
|
||||
for (int i = 1; i < self.users.count; i++) {
|
||||
[allNumbers addObject:@(i)];
|
||||
}
|
||||
|
||||
NSMutableArray *result = [NSMutableArray arrayWithCapacity:4];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int remainingCount = (int)allNumbers.count;
|
||||
int randomIndex = arc4random_uniform(remainingCount);
|
||||
[result addObject:allNumbers[randomIndex]];
|
||||
[allNumbers removeObjectAtIndex:randomIndex];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
-(NSMutableArray *)randomArray{
|
||||
if (!_randomArray) {
|
||||
_randomArray = [NSMutableArray array];
|
||||
}
|
||||
return _randomArray;
|
||||
}
|
||||
-(NSMutableArray *)userViews{
|
||||
if (!_userViews) {
|
||||
_userViews = [NSMutableArray array];
|
||||
}
|
||||
return _userViews;
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
@implementation QXExpansionAppStoreSubView
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame
|
||||
{
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
[self initSubviews];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
-(void)setModel:(QXUserHomeModel *)model{
|
||||
_model = model;
|
||||
[self.headerImageView sd_setImageWithURL:[NSURL URLWithString:model.avatar] placeholderImage:[UIImage imageNamed:@"user_header_placehoulder"]];
|
||||
self.nameLabel.text = model.nickname;
|
||||
UIImage *sexImage = [UIImage imageNamed:model.sex.intValue==1?@"user_sex_boy":@"user_sex_girl"];
|
||||
self.sexImageView.image = sexImage;
|
||||
}
|
||||
-(void)initSubviews{
|
||||
self.headerImageView = [[UIImageView alloc] init];
|
||||
self.headerImageView.contentMode = UIViewContentModeScaleAspectFill;
|
||||
[self.headerImageView addRoundedCornersWithRadius:35];
|
||||
// self.headerImageView.backgroundColor = [UIColor brownColor];;
|
||||
[self addSubview:self.headerImageView];
|
||||
[self.headerImageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.centerY.centerX.equalTo(self);
|
||||
make.height.width.mas_offset(70);
|
||||
}];
|
||||
|
||||
self.nameLabel = [[UILabel alloc] init];
|
||||
self.nameLabel.textColor = RGB16(0x333333);
|
||||
self.nameLabel.font = [UIFont systemFontOfSize:14];
|
||||
// self.nameLabel.text = @"张三";
|
||||
[self addSubview:self.nameLabel];
|
||||
[self.nameLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.equalTo(self.headerImageView.mas_bottom).offset(8);
|
||||
make.centerX.equalTo(self);
|
||||
make.height.mas_equalTo(20);
|
||||
}];
|
||||
|
||||
self.sexImageView = [[UIImageView alloc] init];
|
||||
[self addSubview:self.sexImageView];
|
||||
[self.sexImageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.bottom.right.equalTo(self.headerImageView);
|
||||
make.height.width.mas_offset(16);
|
||||
}];
|
||||
}
|
||||
- (void)startSmoothFloatAnimation {
|
||||
[self animateFloatUp];
|
||||
}
|
||||
|
||||
- (void)animateFloatUp {
|
||||
CGFloat floatDistance = 10.0f;
|
||||
CGFloat duration = 2.0f;
|
||||
|
||||
[UIView animateWithDuration:duration
|
||||
delay:0
|
||||
options:UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionAllowUserInteraction
|
||||
animations:^{
|
||||
self.transform = CGAffineTransformMakeTranslation(0, -floatDistance);
|
||||
}
|
||||
completion:^(BOOL finished) {
|
||||
[self animateFloatDown];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)animateFloatDown {
|
||||
CGFloat duration = 2.0f;
|
||||
|
||||
[UIView animateWithDuration:duration
|
||||
delay:0
|
||||
options:UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionAllowUserInteraction
|
||||
animations:^{
|
||||
self.transform = CGAffineTransformIdentity;
|
||||
}
|
||||
completion:^(BOOL finished) {
|
||||
[self animateFloatUp];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)stopFloatAnimation {
|
||||
[self.layer removeAllAnimations];
|
||||
[NSObject cancelPreviousPerformRequestsWithTarget:self];
|
||||
}
|
||||
@end
|
||||
27
QXLive/Dynamic(语圈)/View/QXExpansionCell.h
Normal file
27
QXLive/Dynamic(语圈)/View/QXExpansionCell.h
Normal file
@@ -0,0 +1,27 @@
|
||||
//
|
||||
// QXExpansionCell.h
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/5/27.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "QXUserModel.h"
|
||||
#import "QXSeatHeaderView.h"
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QXExpansionCell : UITableViewCell
|
||||
@property (weak, nonatomic) IBOutlet UIView *bgView;
|
||||
|
||||
@property (weak, nonatomic) IBOutlet QXSeatHeaderView *avatarImgV;
|
||||
@property (weak, nonatomic) IBOutlet UILabel *nicknameLab;
|
||||
@property (weak, nonatomic) IBOutlet UIImageView *levelImgV;
|
||||
@property (weak, nonatomic) IBOutlet UILabel *ageLabel;
|
||||
@property (weak, nonatomic) IBOutlet UIButton *followBtn;
|
||||
@property (weak, nonatomic) IBOutlet UIView *imgsBgView;
|
||||
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *imgsBgViewHeightCon;
|
||||
@property (weak, nonatomic) IBOutlet UIImageView *sexImageView;
|
||||
@property (nonatomic, strong) QXUserHomeModel *model;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
136
QXLive/Dynamic(语圈)/View/QXExpansionCell.m
Normal file
136
QXLive/Dynamic(语圈)/View/QXExpansionCell.m
Normal file
@@ -0,0 +1,136 @@
|
||||
//
|
||||
// QXExpansionCell.m
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/5/27.
|
||||
//
|
||||
|
||||
#import "QXExpansionCell.h"
|
||||
#import "YBImageBrowser.h"
|
||||
#import "QXChatViewController.h"
|
||||
|
||||
@interface QXExpansionCell()
|
||||
@property (nonatomic, strong) NSMutableArray *imgViewsArray;
|
||||
@end
|
||||
@implementation QXExpansionCell
|
||||
|
||||
- (void)createUI {
|
||||
CGFloat imgWidth = (SCREEN_WIDTH-16*2-12*2-10*2)/3;
|
||||
for (NSInteger i = 0; i < 6; i++) {
|
||||
UIImageView *imgV = [[UIImageView alloc] init];
|
||||
imgV.tag = i+100;
|
||||
imgV.userInteractionEnabled = YES;
|
||||
MJWeakSelf
|
||||
[imgV addTapBlock:^(id _Nonnull obj) {
|
||||
[weakSelf previewPhotoWithCurrentIndex:imgV.tag-100];
|
||||
}];
|
||||
imgV.hidden = YES;
|
||||
imgV.layer.masksToBounds = YES;
|
||||
imgV.layer.cornerRadius = 10;
|
||||
imgV.contentMode = UIViewContentModeScaleAspectFill;
|
||||
[self.imgsBgView addSubview:imgV];
|
||||
[self.imgViewsArray addObject:imgV];
|
||||
|
||||
[imgV mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.equalTo(self.imgsBgView).offset((imgWidth+10)*(i/3));
|
||||
make.left.equalTo(self.imgsBgView).offset((imgWidth+10)*(i%3));
|
||||
make.size.mas_equalTo(CGSizeMake(imgWidth, imgWidth));
|
||||
}];
|
||||
}
|
||||
}
|
||||
- (IBAction)chatAction:(id)sender {
|
||||
if (self.model.room_id.intValue > 0) {
|
||||
// 去房间
|
||||
[[QXGlobal shareGlobal] joinRoomWithRoomId:self.model.room_id isRejoin:NO navagationController:self.navigationController];
|
||||
}else{
|
||||
[[QXGlobal shareGlobal] chatWithUserID:self.model.user_id nickname:self.model.nickname avatar:self.model.avatar navagationController:self.navigationController];
|
||||
}
|
||||
}
|
||||
-(void)setModel:(QXUserHomeModel *)model{
|
||||
_model = model;
|
||||
[self.avatarImgV setHeadIcon:model.avatar dress:@""];
|
||||
self.nicknameLab.text = model.nickname;
|
||||
self.ageLabel.text = [NSString stringWithFormat:@"%ld岁 ip属地: %@",[model.birthday ageWithDateOfBirth],model.loginip];
|
||||
CGFloat imgWidth = (SCREEN_WIDTH-16*2-12*2-10*2)/3;
|
||||
UIImageView *firstImgV = self.imgViewsArray.firstObject;
|
||||
[firstImgV mas_updateConstraints:^(MASConstraintMaker *make) {
|
||||
make.size.mas_equalTo(CGSizeMake(imgWidth, imgWidth));
|
||||
}];
|
||||
UIImage *sexImage = [UIImage imageNamed:model.sex.intValue==1?@"user_sex_boy":@"user_sex_girl"];
|
||||
self.sexImageView.image = sexImage;
|
||||
NSArray *images;
|
||||
if (model.home_bgimages.length > 0) {
|
||||
images = [model.home_bgimages componentsSeparatedByString:@","];
|
||||
}
|
||||
for (UIImageView *imgV in self.imgViewsArray) {
|
||||
imgV.hidden = YES;
|
||||
}
|
||||
for (NSInteger i = 0; i < images.count; i++) {
|
||||
if (i < self.imgViewsArray.count) {
|
||||
UIImageView *imgV = self.imgViewsArray[i];
|
||||
imgV.hidden = NO;
|
||||
NSString *imageUrl = images[i];
|
||||
[imgV sd_setImageWithURL:[NSURL URLWithString:imageUrl]];
|
||||
}
|
||||
}
|
||||
self.imgsBgView.hidden = YES;
|
||||
if (images.count > 0) {
|
||||
if (images.count == 1) {//特殊
|
||||
CGFloat itemW = (SCREEN_WIDTH-15-15-15)/2;
|
||||
CGFloat imgBgHeight = itemW;
|
||||
self.imgsBgView.hidden = NO;
|
||||
self.imgsBgViewHeightCon.constant = imgBgHeight;
|
||||
[firstImgV mas_updateConstraints:^(MASConstraintMaker *make) {
|
||||
make.size.mas_equalTo(CGSizeMake(itemW, imgBgHeight));
|
||||
}];
|
||||
}else {
|
||||
CGFloat itemW = (SCREEN_WIDTH-16*2-12*2-10*2)/3;
|
||||
CGFloat imgBgHeight = 0;
|
||||
NSInteger lines = images.count%3 == 0 ? images.count/3 : images.count/3+1;
|
||||
imgBgHeight = itemW*lines + 10*(lines-1);
|
||||
self.imgsBgView.hidden = NO;
|
||||
if (images.count == 0) {
|
||||
self.imgsBgViewHeightCon.constant = 0;
|
||||
}else{
|
||||
self.imgsBgViewHeightCon.constant = imgBgHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (self.model.room_id.intValue > 0) {
|
||||
self.followBtn.selected = YES;
|
||||
}else{
|
||||
self.followBtn.selected = NO;
|
||||
}
|
||||
}
|
||||
|
||||
-(void)previewPhotoWithCurrentIndex:(NSInteger)currentIndex{
|
||||
NSArray *images = [self.model.home_bgimages componentsSeparatedByString:@","];
|
||||
YBImageBrowser *browser = [YBImageBrowser new];
|
||||
NSMutableArray *sourceArray = [NSMutableArray array];
|
||||
for (int i = 0 ; i <images.count;i++) {
|
||||
NSString *url = images[i];
|
||||
YBIBImageData *data = [[YBIBImageData alloc] init];
|
||||
data.imageURL = [NSURL URLWithString:url];
|
||||
UIImageView *imageView = [self viewWithTag:100+i];
|
||||
data.projectiveView = imageView;
|
||||
[sourceArray addObject:data];
|
||||
}
|
||||
browser.dataSourceArray = sourceArray;
|
||||
browser.currentPage = currentIndex;
|
||||
[browser show];
|
||||
}
|
||||
|
||||
- (void)awakeFromNib {
|
||||
[super awakeFromNib];
|
||||
// Initialization code
|
||||
self.imgViewsArray = [NSMutableArray arrayWithCapacity:6];
|
||||
[self createUI];
|
||||
}
|
||||
|
||||
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
|
||||
[super setSelected:selected animated:animated];
|
||||
|
||||
// Configure the view for the selected state
|
||||
}
|
||||
|
||||
@end
|
||||
156
QXLive/Dynamic(语圈)/View/QXExpansionCell.xib
Normal file
156
QXLive/Dynamic(语圈)/View/QXExpansionCell.xib
Normal file
@@ -0,0 +1,156 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23506"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" rowHeight="184" id="BqF-kO-8SX" customClass="QXExpansionCell">
|
||||
<rect key="frame" x="0.0" y="0.0" width="371" height="95"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="BqF-kO-8SX" id="ktB-xa-Y8j">
|
||||
<rect key="frame" x="0.0" y="0.0" width="371" height="95"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="d7u-yz-ciJ">
|
||||
<rect key="frame" x="16" y="6" width="339" height="83"/>
|
||||
<subviews>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="ij8-0l-yjh">
|
||||
<rect key="frame" x="12" y="12" width="50" height="50"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="50" id="Aa4-FN-u4i"/>
|
||||
<constraint firstAttribute="width" constant="50" id="b1V-LD-cvU"/>
|
||||
</constraints>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
|
||||
<real key="value" value="25"/>
|
||||
</userDefinedRuntimeAttribute>
|
||||
<userDefinedRuntimeAttribute type="boolean" keyPath="layer.masksToBounds" value="YES"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</imageView>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="SRz-S8-eVY" customClass="QXSeatHeaderView">
|
||||
<rect key="frame" x="12" y="12" width="50" height="50"/>
|
||||
</view>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="8cq-E3-DvJ">
|
||||
<rect key="frame" x="72" y="19" width="40" height="18"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="18" id="qwD-PD-2sr"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
|
||||
<color key="textColor" red="0.12941176469999999" green="0.12941176469999999" blue="0.12941176469999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<imageView hidden="YES" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="gIi-P2-Y9S">
|
||||
<rect key="frame" x="118" y="20" width="42" height="16"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="42" id="Pa0-JD-WZI"/>
|
||||
<constraint firstAttribute="height" constant="16" id="nev-GJ-TTd"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="SfJ-0f-fTV">
|
||||
<rect key="frame" x="72" y="45" width="31.666666666666671" height="14.666666666666664"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="14.67" id="ZBE-6b-COh"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="12"/>
|
||||
<color key="textColor" red="0.59999999999999998" green="0.59999999999999998" blue="0.59999999999999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<button opaque="NO" userInteractionEnabled="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="01B-he-W7N">
|
||||
<rect key="frame" x="12" y="12" width="100" height="50"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
</button>
|
||||
<button opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="WzX-5h-Rjx">
|
||||
<rect key="frame" x="254" y="24" width="73" height="26"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="73" id="xrz-si-tcM"/>
|
||||
<constraint firstAttribute="height" constant="26" id="zly-Ov-2fX"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="12"/>
|
||||
<color key="tintColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<state key="normal" image="expansion_call">
|
||||
<color key="titleColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</state>
|
||||
<state key="selected" image="room_user_follow">
|
||||
<color key="titleColor" red="0.50196078430000002" green="0.50196078430000002" blue="0.59607843140000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="chatAction:" destination="BqF-kO-8SX" eventType="touchUpInside" id="1oh-Nh-GtV"/>
|
||||
</connections>
|
||||
</button>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="aff-rQ-ltL">
|
||||
<rect key="frame" x="12" y="71" width="315" height="0.0"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" id="HM6-cc-JXk"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="rE2-Ub-cG3">
|
||||
<rect key="frame" x="46" y="46" width="16" height="16"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="16" id="hDn-pN-Z1j"/>
|
||||
<constraint firstAttribute="height" constant="16" id="txd-O6-q3p"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstItem="SRz-S8-eVY" firstAttribute="top" secondItem="ij8-0l-yjh" secondAttribute="top" id="5SH-Nr-W30"/>
|
||||
<constraint firstItem="SRz-S8-eVY" firstAttribute="leading" secondItem="ij8-0l-yjh" secondAttribute="leading" id="5xK-a1-AgP"/>
|
||||
<constraint firstItem="aff-rQ-ltL" firstAttribute="leading" secondItem="d7u-yz-ciJ" secondAttribute="leading" constant="12" id="7W3-i0-a7h"/>
|
||||
<constraint firstItem="ij8-0l-yjh" firstAttribute="top" secondItem="d7u-yz-ciJ" secondAttribute="top" constant="12" id="7rj-T2-7ef"/>
|
||||
<constraint firstItem="gIi-P2-Y9S" firstAttribute="leading" secondItem="8cq-E3-DvJ" secondAttribute="trailing" constant="6" id="9a3-JM-DNn"/>
|
||||
<constraint firstItem="SfJ-0f-fTV" firstAttribute="leading" secondItem="ij8-0l-yjh" secondAttribute="trailing" constant="10" id="LpR-OW-ApF"/>
|
||||
<constraint firstItem="SRz-S8-eVY" firstAttribute="bottom" secondItem="ij8-0l-yjh" secondAttribute="bottom" id="PL9-sW-Etp"/>
|
||||
<constraint firstItem="8cq-E3-DvJ" firstAttribute="top" secondItem="d7u-yz-ciJ" secondAttribute="top" constant="19" id="QB4-FR-hQC"/>
|
||||
<constraint firstAttribute="trailing" secondItem="aff-rQ-ltL" secondAttribute="trailing" constant="12" id="UJy-KH-Me6"/>
|
||||
<constraint firstItem="rE2-Ub-cG3" firstAttribute="trailing" secondItem="SRz-S8-eVY" secondAttribute="trailing" id="Us7-e2-feo"/>
|
||||
<constraint firstItem="ij8-0l-yjh" firstAttribute="leading" secondItem="d7u-yz-ciJ" secondAttribute="leading" constant="12" id="VNZ-KS-lUT"/>
|
||||
<constraint firstItem="rE2-Ub-cG3" firstAttribute="bottom" secondItem="SRz-S8-eVY" secondAttribute="bottom" id="Wkl-qB-guz"/>
|
||||
<constraint firstItem="aff-rQ-ltL" firstAttribute="top" secondItem="ij8-0l-yjh" secondAttribute="bottom" constant="9" id="gpK-ex-dHB"/>
|
||||
<constraint firstItem="WzX-5h-Rjx" firstAttribute="centerY" secondItem="ij8-0l-yjh" secondAttribute="centerY" id="lzk-gK-Xr5"/>
|
||||
<constraint firstItem="SfJ-0f-fTV" firstAttribute="top" secondItem="8cq-E3-DvJ" secondAttribute="bottom" constant="8" symbolic="YES" id="pb7-FA-QT6"/>
|
||||
<constraint firstItem="gIi-P2-Y9S" firstAttribute="centerY" secondItem="8cq-E3-DvJ" secondAttribute="centerY" id="qez-UP-KMH"/>
|
||||
<constraint firstItem="SRz-S8-eVY" firstAttribute="trailing" secondItem="ij8-0l-yjh" secondAttribute="trailing" id="sL4-bA-4lX"/>
|
||||
<constraint firstItem="8cq-E3-DvJ" firstAttribute="leading" secondItem="ij8-0l-yjh" secondAttribute="trailing" constant="10" id="xsB-a1-v4y"/>
|
||||
<constraint firstAttribute="trailing" secondItem="WzX-5h-Rjx" secondAttribute="trailing" constant="12" id="yE0-Ql-MBm"/>
|
||||
</constraints>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="boolean" keyPath="layer.masksToBounds" value="YES"/>
|
||||
<userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
|
||||
<integer key="value" value="16"/>
|
||||
</userDefinedRuntimeAttribute>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</view>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailing" secondItem="d7u-yz-ciJ" secondAttribute="trailing" constant="16" id="ZEn-eg-5b1"/>
|
||||
<constraint firstItem="d7u-yz-ciJ" firstAttribute="top" secondItem="ktB-xa-Y8j" secondAttribute="top" constant="6" id="c2h-ex-5ar"/>
|
||||
<constraint firstItem="d7u-yz-ciJ" firstAttribute="leading" secondItem="ktB-xa-Y8j" secondAttribute="leading" constant="16" id="kQp-hc-1Ws"/>
|
||||
<constraint firstAttribute="bottom" secondItem="d7u-yz-ciJ" secondAttribute="bottom" constant="6" id="qmb-ae-zTV"/>
|
||||
</constraints>
|
||||
</tableViewCellContentView>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<connections>
|
||||
<outlet property="ageLabel" destination="SfJ-0f-fTV" id="sju-Ih-cv5"/>
|
||||
<outlet property="avatarImgV" destination="SRz-S8-eVY" id="mLt-Oj-Jpd"/>
|
||||
<outlet property="bgView" destination="d7u-yz-ciJ" id="xlK-4p-D30"/>
|
||||
<outlet property="followBtn" destination="WzX-5h-Rjx" id="c7X-9W-ZDG"/>
|
||||
<outlet property="imgsBgView" destination="aff-rQ-ltL" id="iQp-mS-jyp"/>
|
||||
<outlet property="imgsBgViewHeightCon" destination="HM6-cc-JXk" id="rZb-Ea-rwx"/>
|
||||
<outlet property="levelImgV" destination="gIi-P2-Y9S" id="74c-sq-nRX"/>
|
||||
<outlet property="nicknameLab" destination="8cq-E3-DvJ" id="sfo-Gt-g93"/>
|
||||
<outlet property="sexImageView" destination="rE2-Ub-cG3" id="zbU-Lq-BLy"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="216.03053435114504" y="132.04225352112678"/>
|
||||
</tableViewCell>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="expansion_call" width="73" height="26"/>
|
||||
<image name="room_user_follow" width="73" height="26"/>
|
||||
</resources>
|
||||
</document>
|
||||
32
QXLive/Dynamic(语圈)/View/QXGiveGiftListView.h
Normal file
32
QXLive/Dynamic(语圈)/View/QXGiveGiftListView.h
Normal file
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// QXGiveGiftListView.h
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/5/29.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "QXUserModel.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QXGiveGiftListView : UIView
|
||||
/// 语圈id
|
||||
@property (nonatomic,strong)NSString* dynamicId;
|
||||
@property (nonatomic,strong)UIViewController *vc;
|
||||
-(void)showInView:(UIView *)view;
|
||||
-(void)hide;
|
||||
@end
|
||||
|
||||
@interface QXGiveGiftListCell : UITableViewCell
|
||||
@property (nonatomic,strong)UIImageView *rankingImageView;
|
||||
@property (nonatomic,strong)UILabel *rankingLabel;
|
||||
@property (nonatomic,strong)UIImageView *headerImageView;
|
||||
@property (nonatomic,strong)UILabel *nameLabel;
|
||||
@property (nonatomic,strong)UILabel *giftLabel;
|
||||
@property (nonatomic,strong)UIButton *followBtn;
|
||||
@property (nonatomic,strong)QXUserHomeModel *model;
|
||||
@property (nonatomic,copy)void(^clickUserBlock)(QXUserHomeModel *model);
|
||||
+(instancetype)cellWithTableView:(UITableView*)tableView;
|
||||
@end
|
||||
NS_ASSUME_NONNULL_END
|
||||
236
QXLive/Dynamic(语圈)/View/QXGiveGiftListView.m
Normal file
236
QXLive/Dynamic(语圈)/View/QXGiveGiftListView.m
Normal file
@@ -0,0 +1,236 @@
|
||||
//
|
||||
// QXGiveGiftListView.m
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/5/29.
|
||||
//
|
||||
|
||||
#import "QXGiveGiftListView.h"
|
||||
#import "QXDynamicNetwork.h"
|
||||
|
||||
@interface QXGiveGiftListView()<UITableViewDelegate,UITableViewDataSource,UIGestureRecognizerDelegate>
|
||||
@property (nonatomic,strong)UIView *bgView;
|
||||
@property (nonatomic,strong)UILabel *titleLabel;
|
||||
@property (nonatomic,strong)UITableView *tableView;
|
||||
@property (nonatomic,strong)NSMutableArray *dataArray;
|
||||
@end
|
||||
|
||||
@implementation QXGiveGiftListView
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.frame = CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
|
||||
[self initSubviews];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
-(void)initSubviews{
|
||||
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(hide)];
|
||||
tap.delegate = self;
|
||||
[self addGestureRecognizer:tap];
|
||||
self.backgroundColor = [UIColor clearColor];
|
||||
self.bgView = [[UIView alloc] initWithFrame:CGRectMake(0, SCREEN_HEIGHT, self.width, ScaleWidth(429)+kSafeAreaBottom)];
|
||||
self.bgView.backgroundColor = [UIColor whiteColor];
|
||||
[self.bgView addRoundedCornersWithRadius:16 byRoundingCorners:(UIRectCornerTopLeft|UIRectCornerTopRight)];
|
||||
[self addSubview:self.bgView];
|
||||
self.titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(16, 25, self.width-32, 27)];
|
||||
self.titleLabel.font = [UIFont boldSystemFontOfSize:18];
|
||||
self.titleLabel.textColor = RGB16(0x333333);
|
||||
self.titleLabel.textAlignment = NSTextAlignmentCenter;
|
||||
self.titleLabel.text = QXText(@"打赏榜单");
|
||||
[self.bgView addSubview:self.titleLabel];
|
||||
|
||||
[self.bgView addSubview:self.tableView];
|
||||
}
|
||||
-(void)setDynamicId:(NSString *)dynamicId{
|
||||
_dynamicId = dynamicId;
|
||||
[self getList];
|
||||
}
|
||||
|
||||
-(void)getList{
|
||||
MJWeakSelf
|
||||
[QXDynamicNetwork dynamicGiveGiftListWithId:self.dynamicId successBlock:^(NSArray<QXUserHomeModel *> * _Nonnull list) {
|
||||
[weakSelf.dataArray removeAllObjects];
|
||||
[weakSelf.dataArray addObjectsFromArray:list];
|
||||
[weakSelf.tableView reloadData];
|
||||
} failBlock:^(NSError * _Nonnull error, NSString * _Nonnull msg) {
|
||||
|
||||
}];
|
||||
|
||||
}
|
||||
|
||||
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
|
||||
return self.dataArray.count;
|
||||
}
|
||||
|
||||
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
|
||||
QXGiveGiftListCell *cell = [QXGiveGiftListCell cellWithTableView:tableView];
|
||||
if (indexPath.row == 0) {
|
||||
cell.rankingImageView.hidden = NO;
|
||||
cell.rankingLabel.hidden = YES;
|
||||
cell.rankingImageView.image = [UIImage imageNamed:@"ranking_first"];
|
||||
}else if (indexPath.row == 1){
|
||||
cell.rankingImageView.hidden = NO;
|
||||
cell.rankingLabel.hidden = YES;
|
||||
cell.rankingImageView.image = [UIImage imageNamed:@"ranking_second"];
|
||||
}else if (indexPath.row == 2){
|
||||
cell.rankingImageView.hidden = NO;
|
||||
cell.rankingLabel.hidden = YES;
|
||||
cell.rankingImageView.image = [UIImage imageNamed:@"ranking_third"];
|
||||
}else{
|
||||
cell.rankingImageView.hidden = YES;
|
||||
cell.rankingLabel.hidden = NO;
|
||||
cell.rankingLabel.text = [NSString stringWithFormat:@"%ld",indexPath.row];
|
||||
}
|
||||
QXUserHomeModel *model = self.dataArray[indexPath.row];
|
||||
cell.model = model;
|
||||
MJWeakSelf
|
||||
cell.clickUserBlock = ^(QXUserHomeModel * _Nonnull model) {
|
||||
[weakSelf hide];
|
||||
[weakSelf performSelector:@selector(chatAction:) withObject:model afterDelay:0.3];
|
||||
};
|
||||
return cell;
|
||||
}
|
||||
|
||||
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{
|
||||
return touch.view == self;
|
||||
}
|
||||
|
||||
-(void)showInView:(UIView *)view{
|
||||
[view addSubview:self];
|
||||
[UIView animateWithDuration:0.3 animations:^{
|
||||
self.bgView.y = SCREEN_HEIGHT-ScaleWidth(429)-kSafeAreaBottom;
|
||||
}];
|
||||
}
|
||||
-(void)hide{
|
||||
[UIView animateWithDuration:0.3 animations:^{
|
||||
self.bgView.y = SCREEN_HEIGHT;
|
||||
} completion:^(BOOL finished) {
|
||||
[self removeFromSuperview];
|
||||
}];
|
||||
}
|
||||
-(void)chatAction:(QXUserHomeModel*)model{
|
||||
[[QXGlobal shareGlobal] chatWithUserID:model.user_id nickname:model.nickname avatar:model.avatar navagationController:self.vc.navigationController];
|
||||
}
|
||||
-(UITableView *)tableView{
|
||||
if (!_tableView) {
|
||||
self.tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, self.titleLabel.bottom+6, self.width, self.height-self.titleLabel.bottom-6) style:UITableViewStylePlain];
|
||||
self.tableView.backgroundColor = [UIColor clearColor];
|
||||
self.tableView.delegate = self;
|
||||
self.tableView.dataSource = self;
|
||||
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
|
||||
self.tableView.rowHeight = 54;
|
||||
[self.tableView addRoundedCornersWithRadius:6];
|
||||
}
|
||||
return _tableView;
|
||||
}
|
||||
-(NSMutableArray *)dataArray{
|
||||
if (!_dataArray) {
|
||||
_dataArray = [NSMutableArray array];
|
||||
}
|
||||
return _dataArray;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation QXGiveGiftListCell
|
||||
|
||||
+(instancetype)cellWithTableView:(UITableView*)tableView{
|
||||
static NSString *cellId = @"QXGiveGiftListCell";
|
||||
QXGiveGiftListCell *cell = [tableView dequeueReusableCellWithIdentifier:cellId];
|
||||
if (!cell) {
|
||||
cell = [[QXGiveGiftListCell alloc] initWithStyle:(UITableViewCellStyleDefault) reuseIdentifier:cellId];
|
||||
cell.backgroundColor = [UIColor clearColor];
|
||||
cell.selectionStyle = UITableViewCellSelectionStyleNone;
|
||||
}
|
||||
return cell;
|
||||
}
|
||||
|
||||
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{
|
||||
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
|
||||
[self initSubviews];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
-(void)initSubviews{
|
||||
self.rankingImageView = [[UIImageView alloc] init];
|
||||
[self.contentView addSubview:self.rankingImageView];
|
||||
[self.rankingImageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.mas_equalTo(16);
|
||||
make.size.mas_equalTo(CGSizeMake(16, 16));
|
||||
make.centerY.equalTo(self);
|
||||
}];
|
||||
|
||||
self.rankingLabel = [[UILabel alloc] init];
|
||||
self.rankingLabel.font = [UIFont systemFontOfSize:14];
|
||||
self.rankingLabel.textColor = RGB16(0x666666);
|
||||
self.rankingLabel.textAlignment = NSTextAlignmentCenter;
|
||||
[self.contentView addSubview:self.rankingLabel];
|
||||
[self.rankingLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.mas_equalTo(16);
|
||||
make.height.mas_equalTo(16);
|
||||
make.centerY.equalTo(self);
|
||||
make.width.mas_equalTo(25);
|
||||
}];
|
||||
|
||||
self.headerImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"user_header_placehoulder"]];
|
||||
self.headerImageView.contentMode = UIViewContentModeScaleAspectFill;
|
||||
[self.contentView addSubview:self.headerImageView];
|
||||
[self.headerImageView addRoundedCornersWithRadius:20];
|
||||
[self.headerImageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(self.rankingImageView.mas_right).offset(12);
|
||||
make.size.mas_equalTo(CGSizeMake(40, 40));
|
||||
make.centerY.equalTo(self);
|
||||
}];
|
||||
|
||||
self.followBtn = [[UIButton alloc] init];
|
||||
[self.followBtn setImage:[UIImage imageNamed:@"expansion_call"] forState:(UIControlStateNormal)];
|
||||
[self.followBtn addTarget:self action:@selector(followAction) forControlEvents:(UIControlEventTouchUpInside)];
|
||||
[self.contentView addSubview:self.followBtn];
|
||||
[self.followBtn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.centerY.equalTo(self);
|
||||
make.height.mas_equalTo(24);
|
||||
make.width.mas_equalTo(70);
|
||||
make.right.mas_equalTo(-16);
|
||||
}];
|
||||
|
||||
self.nameLabel = [[UILabel alloc] init];
|
||||
self.nameLabel.font = [UIFont systemFontOfSize:14];
|
||||
self.nameLabel.textColor = QXConfig.textColor;
|
||||
[self.contentView addSubview:self.nameLabel];
|
||||
[self.nameLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(self.headerImageView.mas_right).offset(8);
|
||||
make.top.equalTo(self.headerImageView.mas_top).offset(-2);
|
||||
make.height.mas_equalTo(21);
|
||||
make.right.equalTo(self.followBtn.mas_left).offset(-16);
|
||||
}];
|
||||
|
||||
|
||||
self.giftLabel = [[UILabel alloc] init];
|
||||
self.giftLabel.font = [UIFont systemFontOfSize:14];
|
||||
self.giftLabel.textColor = RGB16(0xF4DF39);
|
||||
[self.contentView addSubview:self.giftLabel];
|
||||
[self.giftLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(self.headerImageView.mas_right).offset(8);
|
||||
make.top.equalTo(self.nameLabel.mas_bottom);
|
||||
make.height.mas_equalTo(21);
|
||||
make.right.equalTo(self.followBtn.mas_left).offset(-16);
|
||||
}];
|
||||
}
|
||||
-(void)setModel:(QXUserHomeModel *)model{
|
||||
_model = model;
|
||||
self.nameLabel.text = model.nickname;
|
||||
[self.headerImageView sd_setImageWithURL:[NSURL URLWithString:model.avatar] placeholderImage:[UIImage imageNamed:@"user_header_placehoulder"]];
|
||||
self.giftLabel.text = model.total_price;
|
||||
}
|
||||
-(void)followAction{
|
||||
|
||||
if (self.clickUserBlock) {
|
||||
self.clickUserBlock(self.model);
|
||||
}
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
34
QXLive/Dynamic(语圈)/View/QXMenuPopView.h
Normal file
34
QXLive/Dynamic(语圈)/View/QXMenuPopView.h
Normal file
@@ -0,0 +1,34 @@
|
||||
//
|
||||
// QXMenuPopView.h
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/5/28.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
typedef NS_ENUM(NSInteger) {
|
||||
QXMenuPopViewTypeArrowTop = 0,
|
||||
QXMenuPopViewTypeArrowBottom
|
||||
}QXMenuPopViewType;
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
@protocol QXMenuPopViewDelegate <NSObject>
|
||||
|
||||
@optional
|
||||
-(void)didSelectedIndex:(NSInteger)index menuTitle:(NSString*)menuTitle;
|
||||
|
||||
@end
|
||||
@interface QXMenuPopView : UIView
|
||||
@property (nonatomic,strong)NSArray *dataArray;
|
||||
@property (nonatomic,weak)id<QXMenuPopViewDelegate>delegate;
|
||||
|
||||
@property (nonatomic,assign)QXMenuPopViewType type;
|
||||
-(instancetype)initWithPoint:(CGPoint)point;
|
||||
|
||||
-(instancetype)initWithPoint:(CGPoint)point width:(CGFloat)width height:(CGFloat)height;
|
||||
|
||||
-(void)showInView:(UIView *)view;
|
||||
@end
|
||||
|
||||
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
165
QXLive/Dynamic(语圈)/View/QXMenuPopView.m
Normal file
165
QXLive/Dynamic(语圈)/View/QXMenuPopView.m
Normal file
@@ -0,0 +1,165 @@
|
||||
//
|
||||
// QXMenuPopView.m
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/5/28.
|
||||
//
|
||||
|
||||
#import "QXMenuPopView.h"
|
||||
@interface QXMenuPopView()<UITableViewDataSource,UITableViewDelegate,UIGestureRecognizerDelegate>
|
||||
@property (nonatomic,strong)UIView *arrowView;
|
||||
@property (nonatomic,strong)UIView *bgView;
|
||||
@property (nonatomic,assign)CGPoint point;
|
||||
@property (nonatomic,assign)CGFloat width;
|
||||
@property (nonatomic,assign)CGFloat height;
|
||||
|
||||
@property (nonatomic,strong)UITableView *tableView;
|
||||
@end
|
||||
@implementation QXMenuPopView
|
||||
|
||||
-(instancetype)initWithPoint:(CGPoint)point{
|
||||
if (self = [super initWithFrame:[UIScreen mainScreen].bounds]) {
|
||||
self.frame = [UIScreen mainScreen].bounds;
|
||||
self.backgroundColor = [UIColor colorWithWhite:0.0 alpha:0.3];
|
||||
_point = point;
|
||||
_width = 88;
|
||||
_height = 103;
|
||||
[self initSubviews];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
-(instancetype)initWithPoint:(CGPoint)point width:(CGFloat)width height:(CGFloat)height{
|
||||
if (self = [super initWithFrame:[UIScreen mainScreen].bounds]) {
|
||||
self.frame = [UIScreen mainScreen].bounds;
|
||||
self.backgroundColor = [UIColor colorWithWhite:0.0 alpha:0.3];
|
||||
_point = point;
|
||||
_width = width;
|
||||
_height = height;
|
||||
[self initSubviews];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
-(void)initSubviews{
|
||||
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(hide)];
|
||||
tap.delegate = self;
|
||||
[self addGestureRecognizer:tap];
|
||||
|
||||
self.bgView = [[UIView alloc] initWithFrame:CGRectMake(_point.x -_width/2, _point.y, _width, _height)];
|
||||
self.bgView.clipsToBounds = YES;
|
||||
[self addSubview:self.bgView];
|
||||
|
||||
|
||||
|
||||
|
||||
[self.bgView addSubview:self.tableView];
|
||||
}
|
||||
|
||||
-(void)setDataArray:(NSArray *)dataArray{
|
||||
_dataArray = dataArray;
|
||||
[self.tableView reloadData];
|
||||
}
|
||||
|
||||
-(void)setType:(QXMenuPopViewType)type{
|
||||
_type = type;
|
||||
switch (type) {
|
||||
case QXMenuPopViewTypeArrowTop:
|
||||
self.bgView.frame = CGRectMake(_point.x -_width/2, _point.y, _width, _height);
|
||||
self.arrowView.frame = CGRectMake((_width-12)/2, 3, 12, 12);
|
||||
self.tableView.frame = CGRectMake(0, self.arrowView.top+5, self.bgView.width, self.bgView.height-13);
|
||||
self.arrowView = [[UIView alloc] initWithFrame:CGRectMake((_width-12)/2, 3, 12, 12)];
|
||||
self.arrowView.backgroundColor = [UIColor whiteColor];
|
||||
self.arrowView.transform = CGAffineTransformMakeRotation(45 * M_PI/180.0);
|
||||
[self.bgView insertSubview:self.arrowView belowSubview:self.tableView];
|
||||
break;
|
||||
case QXMenuPopViewTypeArrowBottom:
|
||||
self.bgView.frame = CGRectMake(_point.x -_width/2, _point.y, _width, _height);
|
||||
self.tableView.frame = CGRectMake(0, 0, self.bgView.width, self.bgView.height-16);
|
||||
self.arrowView = [[UIView alloc] initWithFrame:CGRectMake((_width-12)/2, self.tableView.bottom-8, 12, 12)];
|
||||
self.arrowView.backgroundColor = [UIColor whiteColor];
|
||||
self.arrowView.transform = CGAffineTransformMakeRotation(45 * M_PI/180.0);
|
||||
[self.bgView insertSubview:self.arrowView belowSubview:self.tableView];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{
|
||||
return touch.view == self;
|
||||
}
|
||||
|
||||
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
|
||||
return self.dataArray.count;
|
||||
}
|
||||
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
|
||||
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"QXMenuCell"];
|
||||
if (!cell) {
|
||||
cell = [[UITableViewCell alloc] initWithStyle:(UITableViewCellStyleDefault) reuseIdentifier:@"QXMenuCell"];
|
||||
}
|
||||
cell.textLabel.text = self.dataArray[indexPath.row];
|
||||
cell.textLabel.font = [UIFont systemFontOfSize:12];
|
||||
cell.textLabel.textColor = RGB16(0x999999);
|
||||
return cell;
|
||||
}
|
||||
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
|
||||
[tableView deselectRowAtIndexPath:indexPath animated:YES];
|
||||
[self hide];
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(didSelectedIndex:menuTitle:)]) {
|
||||
[self.delegate didSelectedIndex:indexPath.row menuTitle:self.dataArray[indexPath.row]];
|
||||
}
|
||||
}
|
||||
|
||||
-(UITableView *)tableView{
|
||||
if (!_tableView) {
|
||||
self.tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, self.arrowView.top+5, self.bgView.width, self.bgView.height-13) style:UITableViewStylePlain];
|
||||
self.tableView.backgroundColor = [UIColor whiteColor];
|
||||
self.tableView.delegate = self;
|
||||
self.tableView.dataSource = self;
|
||||
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
|
||||
self.tableView.rowHeight = 30;
|
||||
self.tableView.bounces = NO;
|
||||
[self.tableView addRoundedCornersWithRadius:6];
|
||||
}
|
||||
return _tableView;
|
||||
}
|
||||
|
||||
-(void)showInView:(UIView *)view{
|
||||
if (self.type == QXMenuPopViewTypeArrowTop) {
|
||||
self.bgView.height = 0;
|
||||
[view addSubview:self];
|
||||
[UIView animateWithDuration:0.1 animations:^{
|
||||
self.bgView.height = self.height;
|
||||
}];
|
||||
}else{
|
||||
self.bgView.height = 0;
|
||||
self.bgView.y = self.point.y+self.height;
|
||||
[view addSubview:self];
|
||||
[UIView animateWithDuration:0.1 animations:^{
|
||||
self.bgView.height = self.height;
|
||||
self.bgView.y = self.point.y;
|
||||
}];
|
||||
}
|
||||
|
||||
}
|
||||
-(void)hide{
|
||||
if (self.type == QXMenuPopViewTypeArrowTop) {
|
||||
[UIView animateWithDuration:0.1 animations:^{
|
||||
self.bgView.height = 0;
|
||||
} completion:^(BOOL finished) {
|
||||
[self removeFromSuperview];
|
||||
}];
|
||||
}else{
|
||||
[UIView animateWithDuration:0.1 animations:^{
|
||||
self.bgView.height = 0;
|
||||
self.bgView.y = self.point.y+self.height;
|
||||
} completion:^(BOOL finished) {
|
||||
[self removeFromSuperview];
|
||||
}];
|
||||
}
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
|
||||
|
||||
16
QXLive/Dynamic(语圈)/View/QXSelectedTopicView.h
Normal file
16
QXLive/Dynamic(语圈)/View/QXSelectedTopicView.h
Normal file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// QXSelectedTopicView.h
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/5/27.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "QXDynamicModel.h"
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QXSelectedTopicView : UIView
|
||||
@property (nonatomic,strong)NSArray <QXTopicModel*> *selectedTopic;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
67
QXLive/Dynamic(语圈)/View/QXSelectedTopicView.m
Normal file
67
QXLive/Dynamic(语圈)/View/QXSelectedTopicView.m
Normal file
@@ -0,0 +1,67 @@
|
||||
//
|
||||
// QXSelectedTopicView.m
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/5/27.
|
||||
//
|
||||
|
||||
#import "QXSelectedTopicView.h"
|
||||
@interface QXSelectedTopicView()
|
||||
@property (nonatomic,strong)UILabel *titleLabel;
|
||||
@property (nonatomic,strong)UIImageView *arrowImageView;
|
||||
@end
|
||||
|
||||
@implementation QXSelectedTopicView
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
[self initSubviews];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (instancetype)initWithFrame:(CGRect)frame
|
||||
{
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
[self initSubviews];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
-(void)initSubviews{
|
||||
self.titleLabel = [[UILabel alloc] init];
|
||||
self.titleLabel.text = QXText(@"选择话题");
|
||||
self.titleLabel.font = [UIFont boldSystemFontOfSize:16];
|
||||
self.titleLabel.textColor = QXConfig.textColor;
|
||||
[self addSubview:self.titleLabel];
|
||||
|
||||
|
||||
self.arrowImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"arrowRight"]];
|
||||
[self addSubview:self.arrowImageView];
|
||||
[self.arrowImageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.right.mas_equalTo(-12);
|
||||
make.size.mas_equalTo(CGSizeMake(16, 16));
|
||||
make.centerY.equalTo(self);
|
||||
}];
|
||||
|
||||
[self.titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.mas_equalTo(12);
|
||||
make.right.equalTo(self.arrowImageView.mas_left).offset(-12);
|
||||
make.centerY.equalTo(self);
|
||||
}];
|
||||
|
||||
}
|
||||
-(void)setSelectedTopic:(NSArray< QXTopicModel *>*)selectedTopic{
|
||||
_selectedTopic = selectedTopic;
|
||||
NSString *topic = @"";
|
||||
for (QXTopicModel*md in selectedTopic) {
|
||||
if (topic.length == 0) {
|
||||
topic = [topic stringByAppendingFormat:@"%@",md.title];
|
||||
}else{
|
||||
topic = [topic stringByAppendingFormat:@",%@",md.title];
|
||||
}
|
||||
}
|
||||
self.titleLabel.text = topic;
|
||||
}
|
||||
@end
|
||||
118
QXLive/Dynamic(语圈)/View/QXSendGiftView.h
Normal file
118
QXLive/Dynamic(语圈)/View/QXSendGiftView.h
Normal file
@@ -0,0 +1,118 @@
|
||||
//
|
||||
// QXSendGiftView.h
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/5/29.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "JXCategoryView.h"
|
||||
#import "QXRoomModel.h"
|
||||
#import "QXGiftModel.h"
|
||||
#import "QXUserModel.h"
|
||||
|
||||
typedef NS_ENUM(NSInteger) {
|
||||
/// 发现打赏
|
||||
QXSendGiftViewTypeFind = 0,
|
||||
/// 房间送礼
|
||||
QXSendGiftViewTypeRoom ,
|
||||
/// 拍卖
|
||||
QXSendGiftViewTypeAuction ,
|
||||
}QXSendGiftViewType;
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QXSendGiftView : UIView
|
||||
-(instancetype)initWithType:(QXSendGiftViewType)type;
|
||||
|
||||
@property (nonatomic,assign)QXSendGiftViewType type;
|
||||
|
||||
@property (nonatomic,strong)NSMutableArray *titles;
|
||||
@property (nonatomic,strong)UINavigationController *navgationVC;
|
||||
@property (nonatomic,strong)UIViewController *vc;
|
||||
|
||||
@property (nonatomic,strong)NSArray *pitUsers;
|
||||
|
||||
/// 用户模型
|
||||
@property (nonatomic,strong)QXRoomPitModel *userModel;
|
||||
|
||||
/// 房间id 房间送礼物时传
|
||||
@property (nonatomic,strong)NSString* roomId;
|
||||
/// 语圈id
|
||||
@property (nonatomic,strong)NSString* dynamicId;
|
||||
/// 拍卖id
|
||||
@property (nonatomic,strong)NSString* auctionId;
|
||||
|
||||
@property (nonatomic,copy)void(^sendSuccessBlock)(NSString*dynamicId);
|
||||
|
||||
@property (nonatomic,copy)void(^roomSendSuccessBlock)(BOOL isAuction, QXGiftModel*giftModel,NSString*userId, NSString*auctionId);
|
||||
-(void)reloadData;
|
||||
|
||||
-(void)showInView:(UIView *)view;
|
||||
|
||||
-(void)hide;
|
||||
@end
|
||||
|
||||
@interface QXSendGiftCollectionView : UIView<UICollectionViewDelegate,UICollectionViewDataSource,JXCategoryListContentViewDelegate>
|
||||
@property (nonatomic,strong)UICollectionView *collectionView;
|
||||
@property (nonatomic,strong)NSMutableArray *dataArray;
|
||||
@property (nonatomic,strong)NSString *giftLabelId;
|
||||
@property (nonatomic,assign)NSInteger selectedIndex;
|
||||
@property (nonatomic,copy)void(^selectetGiftBlock)(QXGiftModel *gift);
|
||||
@end
|
||||
|
||||
@interface QXSendGiftUserView : UIView<UICollectionViewDelegate,UICollectionViewDataSource>
|
||||
@property (nonatomic,strong)UILabel *titltLabel;
|
||||
@property (nonatomic,strong)UIButton *detailBtn;
|
||||
@property (nonatomic,strong)UICollectionView *collectionView;
|
||||
@property (nonatomic,strong)UIView *lineView;
|
||||
@property (nonatomic,strong)NSMutableArray *dataArray;
|
||||
/// 语圈id
|
||||
@property (nonatomic,strong)NSString* dynamicId;
|
||||
@property (nonatomic,strong)UIViewController *vc;
|
||||
@end
|
||||
|
||||
|
||||
@interface QXSendGiftUserCell : UICollectionViewCell
|
||||
@property (nonatomic,strong)UIImageView *imageView;
|
||||
@property (nonatomic,strong)QXRoomPitModel *pitModel;
|
||||
|
||||
@property (nonatomic,strong)QXUserHomeModel *sendUserModel;
|
||||
@end
|
||||
|
||||
|
||||
@interface QXSendGiftPitUserView : UIView<UICollectionViewDelegate,UICollectionViewDataSource>
|
||||
@property (nonatomic,strong)UICollectionView *collectionView;
|
||||
/// 全麦
|
||||
@property (nonatomic,strong)UIButton *allBtn;
|
||||
/// 是否为麦位
|
||||
@property (nonatomic,assign)BOOL isPitUser;
|
||||
/// 是否是给单人送礼物
|
||||
@property (nonatomic,assign)BOOL isSingle;
|
||||
|
||||
@property (nonatomic,strong)NSArray* users;
|
||||
|
||||
@property (nonatomic,strong)NSMutableArray* selectedArray;
|
||||
@end
|
||||
|
||||
@interface QXSendGiftPitUserCell : UICollectionViewCell
|
||||
@property (nonatomic,strong)UIButton *selectedBtn;
|
||||
@property (nonatomic,strong)UIImageView *headerImageView;
|
||||
@property (nonatomic,strong)QXRoomPitModel *pitModel;
|
||||
@end
|
||||
|
||||
|
||||
@interface QXContinuousGiftView : UIView<CAAnimationDelegate>
|
||||
@property (nonatomic,strong)CAShapeLayer *circleLayer;
|
||||
@property (nonatomic,strong)UIImageView *giftImageView;
|
||||
@property (nonatomic,strong)UIButton *sendBtn;
|
||||
|
||||
@property (nonatomic,strong)QXGiftModel *giftModel;
|
||||
@property (nonatomic,assign)BOOL isAuction;
|
||||
@property (nonatomic,strong)NSString *userId;
|
||||
@property (nonatomic,strong)NSString *auctionId;
|
||||
@property (nonatomic,strong)NSString *roomId;
|
||||
|
||||
@property (nonatomic,strong)CABasicAnimation *animation;
|
||||
@property (nonatomic,copy)void(^dissMissBlock)(QXGiftModel *gift);
|
||||
@end
|
||||
NS_ASSUME_NONNULL_END
|
||||
1056
QXLive/Dynamic(语圈)/View/QXSendGiftView.m
Normal file
1056
QXLive/Dynamic(语圈)/View/QXSendGiftView.m
Normal file
File diff suppressed because it is too large
Load Diff
24
QXLive/Dynamic(语圈)/View/QXTopicListView.h
Normal file
24
QXLive/Dynamic(语圈)/View/QXTopicListView.h
Normal file
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// QXTopicListView.h
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/5/28.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "QXDynamicNetwork.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QXTopicListView : UIView
|
||||
@property (nonatomic,copy)void(^selecctedTopicBlock)(NSArray<QXTopicModel*>*topicArr);
|
||||
@end
|
||||
|
||||
|
||||
@interface QXTopicListViewCell : UITableViewCell
|
||||
@property (nonatomic,strong)UILabel *titleLabel;
|
||||
@property (nonatomic,strong)UIButton *rightBtn;
|
||||
@property (nonatomic,strong)QXTopicModel *model;
|
||||
+(instancetype)cellWithTableView:(UITableView*)tableView;
|
||||
@end
|
||||
NS_ASSUME_NONNULL_END
|
||||
201
QXLive/Dynamic(语圈)/View/QXTopicListView.m
Normal file
201
QXLive/Dynamic(语圈)/View/QXTopicListView.m
Normal file
@@ -0,0 +1,201 @@
|
||||
//
|
||||
// QXTopicListView.m
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/5/28.
|
||||
//
|
||||
|
||||
#import "QXTopicListView.h"
|
||||
|
||||
|
||||
@interface QXTopicListView()<UITableViewDelegate,UITableViewDataSource>
|
||||
@property (nonatomic,strong)UITableView *tableView;
|
||||
@property (nonatomic,strong)NSMutableArray *dataArray;
|
||||
@property (nonatomic,strong)NSMutableArray *selectedArray;
|
||||
@property (nonatomic,strong)UILabel* titleLabel;
|
||||
@property (nonatomic,assign)NSInteger page;
|
||||
|
||||
@property (nonatomic,strong)UIButton* cancelBtn;
|
||||
@property (nonatomic,strong)UIButton* commitBtn;
|
||||
@end
|
||||
|
||||
@implementation QXTopicListView
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame
|
||||
{
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
[self initSubviews];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
-(void)initSubviews{
|
||||
self.page = 1;
|
||||
self.backgroundColor = [UIColor whiteColor];
|
||||
[self addRoundedCornersWithRadius:16 byRoundingCorners:(UIRectCornerTopLeft|UIRectCornerTopRight)];
|
||||
self.titleLabel = [[UILabel alloc] initWithFrame:CGRectMake((SCREEN_WIDTH-100)/2, 16, 100, 27)];
|
||||
self.titleLabel.text = QXText(@"选择话题");
|
||||
self.titleLabel.textColor = QXConfig.textColor;
|
||||
self.titleLabel.font = [UIFont boldSystemFontOfSize:18];
|
||||
[self addSubview:self.titleLabel];
|
||||
|
||||
|
||||
self.cancelBtn = [[UIButton alloc] initWithFrame:CGRectMake(0, 12, 65, 35)];
|
||||
[self.cancelBtn setTitle:QXText(@"取消") forState:(UIControlStateNormal)];
|
||||
[self.cancelBtn setTitleColor:RGB16(0x333333) forState:(UIControlStateNormal)];
|
||||
self.cancelBtn.titleLabel.font = [UIFont systemFontOfSize:14];
|
||||
[self.cancelBtn addTarget:self action:@selector(cancelAction) forControlEvents:(UIControlEventTouchUpInside)];
|
||||
[self addSubview:self.cancelBtn];
|
||||
|
||||
self.commitBtn = [[UIButton alloc] initWithFrame:CGRectMake(SCREEN_WIDTH-65, 12, 65, 35)];
|
||||
[self.commitBtn setTitle:QXText(@"确定") forState:(UIControlStateNormal)];
|
||||
[self.commitBtn setTitleColor:QXConfig.themeColor forState:(UIControlStateNormal)];
|
||||
self.commitBtn.titleLabel.font = [UIFont systemFontOfSize:14];
|
||||
// self.commitBtn.backgroundColor = QXConfig.themeColor;
|
||||
[self.commitBtn addRoundedCornersWithRadius:17.5];
|
||||
[self.commitBtn addTarget:self action:@selector(commitAction) forControlEvents:(UIControlEventTouchUpInside)];
|
||||
[self addSubview:self.commitBtn];
|
||||
|
||||
[self addSubview:self.tableView];
|
||||
[self getTopic];
|
||||
}
|
||||
|
||||
-(void)getTopic{
|
||||
MJWeakSelf
|
||||
[weakSelf.selectedArray removeAllObjects];
|
||||
[QXDynamicNetwork getTopicListWithPage:self.page isTopTopic:NO
|
||||
successBlock:^(NSArray<QXTopicModel *> * _Nonnull hotos) {
|
||||
if (weakSelf.page == 1) {
|
||||
[weakSelf.dataArray removeAllObjects];
|
||||
}
|
||||
[weakSelf.dataArray addObjectsFromArray:hotos];
|
||||
[weakSelf.tableView.mj_header endRefreshing];
|
||||
if (hotos.count == 0) {
|
||||
weakSelf.tableView.mj_footer.state = MJRefreshStateNoMoreData;
|
||||
}else{
|
||||
[weakSelf.tableView.mj_footer endRefreshing];
|
||||
}
|
||||
[self.tableView reloadData];
|
||||
} failBlock:^(NSError * _Nonnull error, NSString * _Nonnull msg) {
|
||||
[weakSelf.tableView.mj_header endRefreshing];
|
||||
[weakSelf.tableView.mj_footer endRefreshing];
|
||||
}];
|
||||
}
|
||||
|
||||
-(void)cancelAction{
|
||||
[[QXGlobal shareGlobal] hideViewBlock:^{}];
|
||||
}
|
||||
-(void)commitAction{
|
||||
MJWeakSelf
|
||||
[[QXGlobal shareGlobal] hideViewBlock:^{
|
||||
if (weakSelf.selecctedTopicBlock) {
|
||||
weakSelf.selecctedTopicBlock(weakSelf.selectedArray);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
|
||||
return self.dataArray.count;
|
||||
}
|
||||
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
|
||||
QXTopicListViewCell *cell = [QXTopicListViewCell cellWithTableView:tableView];
|
||||
QXTopicModel *model = self.dataArray[indexPath.row];
|
||||
cell.model = model;
|
||||
return cell;
|
||||
}
|
||||
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
|
||||
QXTopicModel *model = self.dataArray[indexPath.row];
|
||||
model.isSelected = !model.isSelected;
|
||||
[tableView reloadRow:indexPath.row inSection:indexPath.section withRowAnimation:(UITableViewRowAnimationAutomatic)];
|
||||
if (model.isSelected) {
|
||||
[self.selectedArray addObject:model];
|
||||
}else{
|
||||
[self.selectedArray removeObject:model];
|
||||
}
|
||||
}
|
||||
|
||||
-(UITableView *)tableView{
|
||||
if (!_tableView) {
|
||||
_tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, self.titleLabel.bottom+8, self.width, self.height-16-self.titleLabel.bottom-8) style:UITableViewStylePlain];
|
||||
_tableView.backgroundColor = [UIColor clearColor];
|
||||
_tableView.delegate = self;
|
||||
_tableView.dataSource = self;
|
||||
_tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
|
||||
_tableView.rowHeight = 48;
|
||||
MJWeakSelf
|
||||
_tableView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{
|
||||
weakSelf.page = 1;
|
||||
[weakSelf getTopic];
|
||||
}];
|
||||
_tableView.mj_footer = [MJRefreshBackNormalFooter footerWithRefreshingBlock:^{
|
||||
weakSelf.page++;
|
||||
[weakSelf getTopic];
|
||||
}];
|
||||
}
|
||||
return _tableView;
|
||||
}
|
||||
|
||||
-(NSMutableArray *)dataArray{
|
||||
if (!_dataArray) {
|
||||
_dataArray = [NSMutableArray array];
|
||||
}
|
||||
return _dataArray;
|
||||
}
|
||||
-(NSMutableArray *)selectedArray{
|
||||
if (!_selectedArray) {
|
||||
_selectedArray = [NSMutableArray array];
|
||||
}
|
||||
return _selectedArray;
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
@implementation QXTopicListViewCell
|
||||
|
||||
+(instancetype)cellWithTableView:(UITableView *)tableView{
|
||||
static NSString* cellId = @"QXTopicListViewCell";
|
||||
QXTopicListViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellId];
|
||||
if (!cell) {
|
||||
cell = [[QXTopicListViewCell alloc] initWithStyle:(UITableViewCellStyleDefault) reuseIdentifier:cellId];
|
||||
}
|
||||
return cell;
|
||||
}
|
||||
|
||||
-(instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{
|
||||
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
|
||||
[self initSubviews];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
-(void)initSubviews{
|
||||
self.titleLabel = [[UILabel alloc] init];
|
||||
self.titleLabel.textColor = QXConfig.textColor;
|
||||
self.titleLabel.font = [UIFont systemFontOfSize:14];
|
||||
[self.contentView addSubview:self.titleLabel];
|
||||
|
||||
|
||||
self.rightBtn = [[UIButton alloc] init];
|
||||
[self.rightBtn setImage:[UIImage imageNamed:@"login_agreement_sel"] forState:(UIControlStateSelected)];
|
||||
[self.rightBtn setImage:[UIImage imageNamed:@"login_agreement_nor"] forState:(UIControlStateNormal)];
|
||||
[self.contentView addSubview:self.rightBtn];
|
||||
[self.rightBtn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.right.mas_equalTo(-16);
|
||||
make.height.width.mas_equalTo(20);
|
||||
make.centerY.equalTo(self.contentView);
|
||||
}];
|
||||
[self.titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.mas_equalTo(16);
|
||||
make.height.mas_equalTo(24);
|
||||
make.centerY.equalTo(self.contentView);
|
||||
make.right.equalTo(self.rightBtn.mas_left).offset(-10);
|
||||
}];
|
||||
}
|
||||
|
||||
-(void)setModel:(QXTopicModel *)model{
|
||||
_model = model;
|
||||
self.titleLabel.text = model.title;
|
||||
self.rightBtn.selected = model.isSelected;
|
||||
}
|
||||
@end
|
||||
17
QXLive/Dynamic(语圈)/View/QXToppicDynamicTopView.h
Normal file
17
QXLive/Dynamic(语圈)/View/QXToppicDynamicTopView.h
Normal file
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// QXToppicDynamicTopView.h
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/6/3.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "QXDynamicModel.h"
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QXToppicDynamicTopView : UIView
|
||||
-(instancetype)initWithModel:(QXTopicModel*)model;
|
||||
@property (nonatomic,strong)QXTopicModel *model;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
77
QXLive/Dynamic(语圈)/View/QXToppicDynamicTopView.m
Normal file
77
QXLive/Dynamic(语圈)/View/QXToppicDynamicTopView.m
Normal file
@@ -0,0 +1,77 @@
|
||||
//
|
||||
// QXToppicDynamicTopView.m
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/6/3.
|
||||
//
|
||||
|
||||
#import "QXToppicDynamicTopView.h"
|
||||
@interface QXToppicDynamicTopView()
|
||||
@property (nonatomic,strong)UILabel *titleLabel;
|
||||
@property (nonatomic,strong)UIImageView *topicImageView;
|
||||
@property (nonatomic,strong)UIImageView *tagImageView;
|
||||
@property (nonatomic,strong)UILabel *countLabel;
|
||||
@property (nonatomic,strong)UILabel *contentLabel;
|
||||
@end
|
||||
|
||||
@implementation QXToppicDynamicTopView
|
||||
|
||||
-(void)setModel:(QXTopicModel *)model{
|
||||
_model = model;
|
||||
self.titleLabel.text = model.title;
|
||||
[self.topicImageView sd_setImageWithURL:[NSURL URLWithString:model.pic]];
|
||||
self.countLabel.text = [NSString localizedStringWithFormat:QXText(@"%@条动态"),[NSString qx_showHotCountNum:model.count.longLongValue]];
|
||||
self.contentLabel.text = model.content;
|
||||
}
|
||||
|
||||
//- (instancetype)initWithFrame:(CGRect)frame
|
||||
//{
|
||||
// self = [super initWithFrame:frame];
|
||||
// if (self) {
|
||||
// [self initSubviews];
|
||||
// }
|
||||
// return self;
|
||||
//}
|
||||
-(instancetype)initWithModel:(QXTopicModel *)model{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_model = model;
|
||||
[self initSubviews];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
-(void)initSubviews{
|
||||
self.topicImageView = [[UIImageView alloc] initWithFrame:CGRectMake(16, 12, 45, 45)];
|
||||
self.topicImageView.contentMode = UIViewContentModeScaleAspectFill;
|
||||
self.topicImageView.clipsToBounds = YES;
|
||||
[self.topicImageView addRoundedCornersWithRadius:4];
|
||||
[self addSubview:self.topicImageView];
|
||||
|
||||
self.titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(self.topicImageView.right+7, self.topicImageView.top, SCREEN_WIDTH-self.topicImageView.right-7-16, 24)];
|
||||
self.titleLabel.font = [UIFont boldSystemFontOfSize:16.f];
|
||||
self.titleLabel.textColor = QXConfig.textColor;
|
||||
[self addSubview:self.titleLabel];
|
||||
|
||||
self.tagImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"dynamic_topic_tag"]];
|
||||
self.tagImageView.frame = CGRectMake(self.titleLabel.left, self.titleLabel.bottom+7, 37 , 13);
|
||||
[self addSubview:self.tagImageView];
|
||||
|
||||
self.countLabel = [[UILabel alloc] initWithFrame:CGRectMake(self.tagImageView.right+4, self.titleLabel.bottom+4, SCREEN_WIDTH-self.tagImageView.right-4-16, 18)];
|
||||
self.countLabel.font = [UIFont systemFontOfSize:12.f];
|
||||
self.countLabel.textColor = RGB16(0x999999);
|
||||
[self addSubview:self.countLabel];
|
||||
|
||||
self.contentLabel = [[UILabel alloc] initWithFrame:CGRectMake(16, self.topicImageView.bottom+12, SCREEN_WIDTH-32, 20)];
|
||||
self.contentLabel.textColor = RGB16(0x666666);
|
||||
self.contentLabel.font = [UIFont systemFontOfSize:12.f];;
|
||||
self.contentLabel.numberOfLines = 0;
|
||||
[self addSubview:self.contentLabel];
|
||||
[self setModel:self.model];
|
||||
|
||||
[self.contentLabel sizeToFit];
|
||||
self.contentLabel.frame = CGRectMake(16, self.topicImageView.bottom+12, SCREEN_WIDTH-32, self.contentLabel.height);
|
||||
self.frame = CGRectMake(0, 0, SCREEN_WIDTH, self.contentLabel.bottom+3);
|
||||
|
||||
}
|
||||
@end
|
||||
23
QXLive/Dynamic(语圈)/View/详情/QXDynamicCommentCell.h
Normal file
23
QXLive/Dynamic(语圈)/View/详情/QXDynamicCommentCell.h
Normal file
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// QXDynamicCommentCell.h
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/6/4.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QXDynamicCommentCell : UITableViewCell
|
||||
@property (weak, nonatomic) IBOutlet UIView *topCornerView;
|
||||
@property (weak, nonatomic) IBOutlet UIView *bottomCornerView;
|
||||
@property (nonatomic,strong)QXDynamicCommentListModel *model;
|
||||
@property (nonatomic,copy)void(^longPressBlock)(QXDynamicCommentListModel *model);
|
||||
|
||||
@property (weak, nonatomic) IBOutlet UILabel *commentLabel;
|
||||
@property (weak, nonatomic) IBOutlet UILabel *timeLabel;
|
||||
+(instancetype)cellWithTableView:(UITableView *)tableView;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
61
QXLive/Dynamic(语圈)/View/详情/QXDynamicCommentCell.m
Normal file
61
QXLive/Dynamic(语圈)/View/详情/QXDynamicCommentCell.m
Normal file
@@ -0,0 +1,61 @@
|
||||
//
|
||||
// QXDynamicCommentCell.m
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/6/4.
|
||||
//
|
||||
|
||||
#import "QXDynamicCommentCell.h"
|
||||
|
||||
@implementation QXDynamicCommentCell
|
||||
+(instancetype)cellWithTableView:(UITableView *)tableView{
|
||||
static NSString *cellId = @"QXDynamicCommentCell";
|
||||
QXDynamicCommentCell *cell = [tableView dequeueReusableCellWithIdentifier:cellId];
|
||||
if (!cell) {
|
||||
cell = [[NSBundle mainBundle] loadNibNamed:cellId owner:nil options:nil].lastObject;
|
||||
cell.backgroundColor = [UIColor clearColor];
|
||||
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:cell action:@selector(handleLongPress:)];
|
||||
[cell addGestureRecognizer:longPress];
|
||||
}
|
||||
return cell;
|
||||
}
|
||||
-(void)setModel:(QXDynamicCommentListModel *)model{
|
||||
_model = model;
|
||||
NSString *commentUser = @"";
|
||||
if (model.reply_to_user.length == 0) {
|
||||
commentUser = [NSString stringWithFormat:@"%@:",model.nickname];
|
||||
}else{
|
||||
commentUser = [NSString localizedStringWithFormat:QXText(@"%@ 回复 %@:"),model.nickname,model.reply_to_user];
|
||||
}
|
||||
NSString* content = [NSString stringWithFormat:@"%@%@",commentUser,model.content];
|
||||
NSMutableAttributedString *attr = [[NSMutableAttributedString alloc] initWithString:content];
|
||||
[attr yy_setColor:RGB16(0x999999) range:[content rangeOfString:model.content]];
|
||||
[attr yy_setColor:RGB16(0x333333) range:[content rangeOfString:commentUser]];
|
||||
self.commentLabel.attributedText = attr;
|
||||
|
||||
NSDate *date = [NSDate dateWithTimeIntervalSince1970:model.createtime.longLongValue]; //此处根据项目需求,选择是否除以1000 , 如果时间戳精确到秒则去掉1000
|
||||
NSDateFormatter *formatter = [[NSDateFormatter alloc]init];
|
||||
formatter.dateFormat = @"yyyy-MM-dd HH:mm:ss";
|
||||
NSString*time = [formatter stringFromDate:date];
|
||||
self.timeLabel.text = time;
|
||||
}
|
||||
|
||||
-(void)handleLongPress:(UILongPressGestureRecognizer *)gesture{
|
||||
if (gesture.state == UIGestureRecognizerStateBegan) {
|
||||
if (self.longPressBlock) {
|
||||
self.longPressBlock(self.model);
|
||||
}
|
||||
}
|
||||
}
|
||||
- (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
|
||||
}
|
||||
|
||||
@end
|
||||
127
QXLive/Dynamic(语圈)/View/详情/QXDynamicCommentCell.xib
Normal file
127
QXLive/Dynamic(语圈)/View/详情/QXDynamicCommentCell.xib
Normal file
@@ -0,0 +1,127 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23506"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" rowHeight="141" id="KGk-i7-Jjw" customClass="QXDynamicCommentCell">
|
||||
<rect key="frame" x="0.0" y="0.0" width="428" height="141"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM">
|
||||
<rect key="frame" x="0.0" y="0.0" width="428" height="141"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="xpB-b7-lGw">
|
||||
<rect key="frame" x="64" y="0.0" width="348" height="141"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="wj3-tk-zlh">
|
||||
<rect key="frame" x="0.0" y="0.0" width="348" height="24"/>
|
||||
<color key="backgroundColor" red="0.97647058819999999" green="0.97647058819999999" blue="0.97647058819999999" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="24" id="VRd-E6-wjg"/>
|
||||
</constraints>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="boolean" keyPath="layer.masksToBounds" value="YES"/>
|
||||
<userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
|
||||
<integer key="value" value="0"/>
|
||||
</userDefinedRuntimeAttribute>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Ujm-d6-5zi">
|
||||
<rect key="frame" x="0.0" y="12" width="348" height="117"/>
|
||||
<color key="backgroundColor" red="0.97647058819999999" green="0.97647058819999999" blue="0.97647058819999999" alpha="1" colorSpace="calibratedRGB"/>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Tn3-vd-O5b">
|
||||
<rect key="frame" x="0.0" y="117" width="348" height="24"/>
|
||||
<color key="backgroundColor" red="0.97647058819999999" green="0.97647058819999999" blue="0.97647058819999999" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="24" id="WbI-tI-87v"/>
|
||||
</constraints>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="boolean" keyPath="layer.masksToBounds" value="YES"/>
|
||||
<userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
|
||||
<integer key="value" value="0"/>
|
||||
</userDefinedRuntimeAttribute>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</view>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="MH7-oM-77U">
|
||||
<rect key="frame" x="12" y="12" width="324" height="98"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ovO-RW-ILy">
|
||||
<rect key="frame" x="12" y="116" width="31" height="20"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="20" id="PFb-yy-Wz2"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="12"/>
|
||||
<color key="textColor" red="0.57647058823529407" green="0.57647058823529407" blue="0.57647058823529407" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<button opaque="NO" userInteractionEnabled="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="BDR-Dd-yF8">
|
||||
<rect key="frame" x="53" y="116" width="38" height="20"/>
|
||||
<color key="backgroundColor" red="0.96078431372549022" green="0.96078431372549022" blue="0.96078431372549022" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="38" id="DYo-ky-Mwr"/>
|
||||
<constraint firstAttribute="height" constant="20" id="P7V-zS-ieb"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="12"/>
|
||||
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
|
||||
<state key="normal" title="回复">
|
||||
<color key="titleColor" red="0.57647058823529407" green="0.57647058823529407" blue="0.57647058823529407" alpha="1" colorSpace="custom" customColorSpace="calibratedRGB"/>
|
||||
</state>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="boolean" keyPath="layer.masksToBounds" value="YES"/>
|
||||
<userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
|
||||
<integer key="value" value="5"/>
|
||||
</userDefinedRuntimeAttribute>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</button>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="MH7-oM-77U" firstAttribute="top" secondItem="xpB-b7-lGw" secondAttribute="top" constant="12" id="7HG-rN-ZXB"/>
|
||||
<constraint firstItem="ovO-RW-ILy" firstAttribute="top" secondItem="MH7-oM-77U" secondAttribute="bottom" constant="6" id="CDA-7f-DI4"/>
|
||||
<constraint firstItem="wj3-tk-zlh" firstAttribute="top" secondItem="xpB-b7-lGw" secondAttribute="top" id="CtL-8c-2EE"/>
|
||||
<constraint firstItem="Tn3-vd-O5b" firstAttribute="top" secondItem="Ujm-d6-5zi" secondAttribute="bottom" constant="-12" id="DXX-9k-jtw"/>
|
||||
<constraint firstAttribute="trailing" secondItem="Ujm-d6-5zi" secondAttribute="trailing" id="FoU-Ue-edq"/>
|
||||
<constraint firstAttribute="bottom" secondItem="Tn3-vd-O5b" secondAttribute="bottom" id="GrF-LO-MKV"/>
|
||||
<constraint firstItem="wj3-tk-zlh" firstAttribute="leading" secondItem="xpB-b7-lGw" secondAttribute="leading" id="KIq-S2-f5X"/>
|
||||
<constraint firstAttribute="trailing" secondItem="MH7-oM-77U" secondAttribute="trailing" constant="12" id="LbR-uJ-Rnz"/>
|
||||
<constraint firstItem="BDR-Dd-yF8" firstAttribute="centerY" secondItem="ovO-RW-ILy" secondAttribute="centerY" id="Pl5-d4-uSY"/>
|
||||
<constraint firstAttribute="trailing" secondItem="wj3-tk-zlh" secondAttribute="trailing" id="WM9-UL-gVo"/>
|
||||
<constraint firstAttribute="trailing" secondItem="Tn3-vd-O5b" secondAttribute="trailing" id="XBe-4U-aAO"/>
|
||||
<constraint firstItem="Tn3-vd-O5b" firstAttribute="leading" secondItem="xpB-b7-lGw" secondAttribute="leading" id="Z1D-TT-RqS"/>
|
||||
<constraint firstItem="Ujm-d6-5zi" firstAttribute="top" secondItem="wj3-tk-zlh" secondAttribute="bottom" constant="-12" id="foT-ME-nSA"/>
|
||||
<constraint firstItem="BDR-Dd-yF8" firstAttribute="leading" secondItem="ovO-RW-ILy" secondAttribute="trailing" constant="10" id="nVH-R6-2RG"/>
|
||||
<constraint firstItem="Ujm-d6-5zi" firstAttribute="leading" secondItem="xpB-b7-lGw" secondAttribute="leading" id="nqu-b6-z28"/>
|
||||
<constraint firstAttribute="bottom" secondItem="ovO-RW-ILy" secondAttribute="bottom" constant="5" id="tAa-xh-nWW"/>
|
||||
<constraint firstItem="MH7-oM-77U" firstAttribute="leading" secondItem="xpB-b7-lGw" secondAttribute="leading" constant="12" id="vi3-5m-DoP"/>
|
||||
<constraint firstItem="ovO-RW-ILy" firstAttribute="leading" secondItem="xpB-b7-lGw" secondAttribute="leading" constant="12" id="z0e-oe-D3t"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="xpB-b7-lGw" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" constant="64" id="3Yn-bs-fOw"/>
|
||||
<constraint firstItem="xpB-b7-lGw" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="top" id="D52-la-m9V"/>
|
||||
<constraint firstAttribute="bottom" secondItem="xpB-b7-lGw" secondAttribute="bottom" id="Ohy-Rl-W1F"/>
|
||||
<constraint firstAttribute="trailing" secondItem="xpB-b7-lGw" secondAttribute="trailing" constant="16" id="cP3-J2-kVq"/>
|
||||
</constraints>
|
||||
</tableViewCellContentView>
|
||||
<viewLayoutGuide key="safeArea" id="aW0-zy-SZf"/>
|
||||
<connections>
|
||||
<outlet property="bottomCornerView" destination="Tn3-vd-O5b" id="Wgj-q4-Hzn"/>
|
||||
<outlet property="commentLabel" destination="MH7-oM-77U" id="d4v-SC-qU7"/>
|
||||
<outlet property="timeLabel" destination="ovO-RW-ILy" id="lPo-Fk-HLc"/>
|
||||
<outlet property="topCornerView" destination="wj3-tk-zlh" id="xnW-5L-NJs"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="221.37404580152671" y="32.74647887323944"/>
|
||||
</tableViewCell>
|
||||
</objects>
|
||||
</document>
|
||||
25
QXLive/Dynamic(语圈)/View/详情/QXDynamicCommentHeaderView.h
Normal file
25
QXLive/Dynamic(语圈)/View/详情/QXDynamicCommentHeaderView.h
Normal file
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// QXDynamicCommentHeaderView.h
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/6/4.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
@protocol QXDynamicCommentHeaderViewDelegate <NSObject>
|
||||
|
||||
@optional
|
||||
-(void)didClickDeleteComment:(QXDynamicCommentListModel*)model;
|
||||
|
||||
-(void)didClickReplyComment:(QXDynamicCommentListModel*)model;
|
||||
|
||||
@end
|
||||
@interface QXDynamicCommentHeaderView : UIView
|
||||
@property (nonatomic,strong)QXDynamicCommentListModel *model;
|
||||
|
||||
@property (nonatomic,weak)id<QXDynamicCommentHeaderViewDelegate> delegate;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
128
QXLive/Dynamic(语圈)/View/详情/QXDynamicCommentHeaderView.m
Normal file
128
QXLive/Dynamic(语圈)/View/详情/QXDynamicCommentHeaderView.m
Normal file
@@ -0,0 +1,128 @@
|
||||
//
|
||||
// QXDynamicCommentHeaderView.m
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/6/4.
|
||||
//
|
||||
|
||||
#import "QXDynamicCommentHeaderView.h"
|
||||
@interface QXDynamicCommentHeaderView()
|
||||
@property (nonatomic,strong)UIImageView *headerImageView;
|
||||
@property (nonatomic,strong)UILabel *nameLabel;
|
||||
@property (nonatomic,strong)UILabel *contentLabel;
|
||||
@property (nonatomic,strong)UILabel *timeLabel;
|
||||
|
||||
@property (nonatomic,strong)UIButton *replyBtn;
|
||||
@property (nonatomic,strong)UIButton *deleteBtn;
|
||||
@end
|
||||
|
||||
@implementation QXDynamicCommentHeaderView
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame
|
||||
{
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
[self initSubviews];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
-(void)initSubviews{
|
||||
self.headerImageView = [[UIImageView alloc] init];
|
||||
self.headerImageView.contentMode = UIViewContentModeScaleAspectFill;
|
||||
[self.headerImageView addRoundedCornersWithRadius:20];
|
||||
[self addSubview:self.headerImageView];
|
||||
[self.headerImageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.mas_equalTo(16);
|
||||
make.height.width.mas_equalTo(40);
|
||||
make.top.mas_equalTo(12);
|
||||
}];
|
||||
|
||||
self.nameLabel = [[UILabel alloc] init];
|
||||
self.nameLabel.textColor = [UIColor blackColor];
|
||||
self.nameLabel.font = [UIFont systemFontOfSize:12];
|
||||
[self addSubview:self.nameLabel];
|
||||
[self.nameLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(self.headerImageView.mas_right).offset(7);
|
||||
make.height.mas_equalTo(16);
|
||||
make.top.mas_equalTo(12);
|
||||
make.right.mas_equalTo(-16);
|
||||
}];
|
||||
|
||||
self.contentLabel = [[UILabel alloc] init];
|
||||
self.contentLabel.textColor = [UIColor blackColor];
|
||||
self.contentLabel.font = [UIFont systemFontOfSize:14];
|
||||
self.contentLabel.numberOfLines = 0;
|
||||
[self addSubview:self.contentLabel];
|
||||
[self.contentLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(self.nameLabel);
|
||||
make.top.equalTo(self.nameLabel.mas_bottom).offset(7);
|
||||
make.right.mas_equalTo(-16);
|
||||
}];
|
||||
|
||||
self.timeLabel = [[UILabel alloc] init];
|
||||
self.timeLabel.textColor = RGB16(0x939393);
|
||||
self.timeLabel.font = [UIFont systemFontOfSize:12];
|
||||
[self addSubview:self.timeLabel];
|
||||
[self.timeLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(self.nameLabel);
|
||||
make.height.mas_equalTo(20);
|
||||
make.top.equalTo(self.contentLabel.mas_bottom).offset(2);
|
||||
}];
|
||||
|
||||
self.replyBtn = [[UIButton alloc] init];
|
||||
[self.replyBtn setTitle:QXText(@"回复") forState:(UIControlStateNormal)];
|
||||
self.replyBtn.titleLabel.font = [UIFont systemFontOfSize:12];
|
||||
[self.replyBtn setTitleColor:RGB16(0x939393) forState:(UIControlStateNormal)];
|
||||
[self.replyBtn addRoundedCornersWithRadius:5];
|
||||
self.replyBtn.backgroundColor = RGB16(0xF5F5F5);
|
||||
[self.replyBtn addTarget:self action:@selector(replyAction) forControlEvents:(UIControlEventTouchUpInside)];
|
||||
[self addSubview:self.replyBtn];
|
||||
[self.replyBtn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(self.timeLabel.mas_right).offset(12);
|
||||
make.height.mas_equalTo(20);
|
||||
make.width.mas_equalTo(ScaleWidth(38));
|
||||
make.centerY.equalTo(self.timeLabel);
|
||||
}];
|
||||
|
||||
self.deleteBtn = [[UIButton alloc] init];
|
||||
[self.deleteBtn setTitle:QXText(@"删除") forState:(UIControlStateNormal)];
|
||||
self.deleteBtn.titleLabel.font = [UIFont systemFontOfSize:12];
|
||||
[self.deleteBtn setTitleColor:RGB16(0x939393) forState:(UIControlStateNormal)];
|
||||
[self.deleteBtn addTarget:self action:@selector(deleteAction) forControlEvents:(UIControlEventTouchUpInside)];
|
||||
[self addSubview:self.deleteBtn];
|
||||
[self.deleteBtn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(self.replyBtn.mas_right).offset(6);
|
||||
make.height.mas_equalTo(20);
|
||||
make.width.mas_equalTo(ScaleWidth(38));
|
||||
make.centerY.equalTo(self.timeLabel);
|
||||
}];
|
||||
}
|
||||
|
||||
-(void)setModel:(QXDynamicCommentListModel *)model{
|
||||
_model = model;
|
||||
[self.headerImageView sd_setImageWithURL:[NSURL URLWithString:model.avatar] placeholderImage:[UIImage imageNamed:@"user_header_placehoulder"]];
|
||||
self.nameLabel.text = model.nickname;
|
||||
self.contentLabel.text = model.content;
|
||||
NSDate *date = [NSDate dateWithTimeIntervalSince1970:model.createtime.longLongValue]; //此处根据项目需求,选择是否除以1000 , 如果时间戳精确到秒则去掉1000
|
||||
NSDateFormatter *formatter = [[NSDateFormatter alloc]init];
|
||||
formatter.dateFormat = @"yyyy-MM-dd HH:mm:ss";
|
||||
NSString*time = [formatter stringFromDate:date];
|
||||
self.timeLabel.text = time;
|
||||
if ([model.user_id isEqualToString:[QXGlobal shareGlobal].loginModel.user_id]) {
|
||||
self.deleteBtn.hidden = NO;
|
||||
}else{
|
||||
self.deleteBtn.hidden = YES;
|
||||
}
|
||||
}
|
||||
-(void)replyAction{
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(didClickReplyComment:)]) {
|
||||
[self.delegate didClickReplyComment:self.model];
|
||||
}
|
||||
}
|
||||
|
||||
-(void)deleteAction{
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(didClickDeleteComment:)]) {
|
||||
[self.delegate didClickDeleteComment:self.model];
|
||||
}
|
||||
}
|
||||
@end
|
||||
27
QXLive/Dynamic(语圈)/View/详情/QXDynamicCommentInputView.h
Normal file
27
QXLive/Dynamic(语圈)/View/详情/QXDynamicCommentInputView.h
Normal file
@@ -0,0 +1,27 @@
|
||||
//
|
||||
// QXDynamicCommentInputView.h
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/6/4.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
@protocol QXDynamicCommentInputViewDelegate <NSObject>
|
||||
|
||||
@optional
|
||||
|
||||
-(void)didClickSendWithText:(NSString*)text model:(QXDynamicCommentListModel*)model;
|
||||
|
||||
@end
|
||||
|
||||
@interface QXDynamicCommentInputView : UIView
|
||||
@property (nonatomic,strong)UITextField *textField;
|
||||
@property (nonatomic,strong)QXDynamicCommentListModel *model;
|
||||
@property (nonatomic,weak)id<QXDynamicCommentInputViewDelegate>delegate;
|
||||
|
||||
-(void)inputBecomeFirstResponder;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
113
QXLive/Dynamic(语圈)/View/详情/QXDynamicCommentInputView.m
Normal file
113
QXLive/Dynamic(语圈)/View/详情/QXDynamicCommentInputView.m
Normal file
@@ -0,0 +1,113 @@
|
||||
//
|
||||
// QXDynamicCommentInputView.m
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/6/4.
|
||||
//
|
||||
|
||||
#import "QXDynamicCommentInputView.h"
|
||||
|
||||
@interface QXDynamicCommentInputView()<UITextFieldDelegate>
|
||||
@property (nonatomic,strong)UICollectionView *collectionViwew;
|
||||
@property (nonatomic,strong)UIView *inputBgView;
|
||||
@property (nonatomic,strong)UIView *inputShadowView;
|
||||
|
||||
@property (nonatomic,strong)UIButton *sendBtn;
|
||||
@end
|
||||
|
||||
@implementation QXDynamicCommentInputView
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame
|
||||
{
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
[self initSubviews];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
-(void)initSubviews{
|
||||
self.backgroundColor = [UIColor whiteColor];
|
||||
|
||||
self.sendBtn = [[UIButton alloc] init];
|
||||
self.sendBtn.needEventInterval = 0.5;
|
||||
[self.sendBtn setTitle:QXText(@"发送") forState:(UIControlStateNormal)];
|
||||
self.sendBtn.titleLabel.font = [UIFont systemFontOfSize:14];
|
||||
[self.sendBtn setTitleColor:QXConfig.btnTextColor forState:(UIControlStateNormal)];
|
||||
self.sendBtn.backgroundColor = QXConfig.themeColor;
|
||||
[self.sendBtn addRoundedCornersWithRadius:17.5];
|
||||
[self.sendBtn addTarget:self action:@selector(sendAction) forControlEvents:(UIControlEventTouchUpInside)];;
|
||||
[self addSubview:self.sendBtn];
|
||||
[self.sendBtn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.right.mas_equalTo(-16);
|
||||
make.top.mas_equalTo(8);
|
||||
make.height.mas_equalTo(35);
|
||||
make.width.mas_equalTo(80);
|
||||
}];
|
||||
|
||||
|
||||
self.inputBgView = [[UIView alloc] init];
|
||||
self.inputBgView.backgroundColor = RGB16(0xF5F5F5);
|
||||
[self.inputBgView addRoundedCornersWithRadius:8];
|
||||
[self addSubview:self.inputBgView];
|
||||
[self.inputBgView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.mas_equalTo(16);
|
||||
make.right.equalTo(self.sendBtn.mas_left).offset(-12);
|
||||
make.centerY.equalTo(self.sendBtn);
|
||||
make.height.mas_equalTo(35);
|
||||
}];
|
||||
|
||||
|
||||
|
||||
self.textField = [[UITextField alloc] init];
|
||||
self.textField.font = [UIFont systemFontOfSize:14];
|
||||
self.textField.textColor = QXConfig.textColor;
|
||||
self.textField.returnKeyType = UIReturnKeyDone;
|
||||
self.textField.delegate = self;
|
||||
[self.textField addTarget:self action:@selector(textDidChange:) forControlEvents:UIControlEventEditingChanged];
|
||||
[self.inputBgView addSubview:self.textField];
|
||||
[self.textField mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.mas_equalTo(10);
|
||||
make.right.mas_equalTo(-10);
|
||||
make.top.bottom.equalTo(self.inputBgView);
|
||||
}];
|
||||
|
||||
self.inputShadowView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.width, 4)];
|
||||
self.inputShadowView.backgroundColor = [UIColor whiteColor];
|
||||
self.inputShadowView.layer.shadowColor = [UIColor grayColor].CGColor;
|
||||
self.inputShadowView.layer.shadowOpacity = 0.2;
|
||||
self.inputShadowView.layer.shadowOffset = CGSizeMake(0, -2);
|
||||
self.inputShadowView.layer.shadowRadius = 2;
|
||||
self.inputShadowView.layer.shadowPath = [UIBezierPath bezierPathWithRoundedRect:self.inputShadowView.bounds cornerRadius:self.inputShadowView.layer.cornerRadius].CGPath;
|
||||
self.inputShadowView.layer.cornerRadius = 2;
|
||||
self.inputShadowView.layer.masksToBounds = NO;
|
||||
[self addSubview:self.inputShadowView];
|
||||
// self.inputShadowView.layer.shadowColor = [UIColor grayColor].CGColor;
|
||||
// self.inputShadowView.layer.shadowOpacity = 0.5;
|
||||
// self.inputShadowView.layer.shadowOffset = CGSizeMake(0, -2);
|
||||
//// self.inputShadowView.layer.shadowPath = [UIBezierPath bezierPathWithRoundedRect:self.bounds cornerRadius:0].CGPath;
|
||||
// self.inputShadowView.layer.masksToBounds = NO;
|
||||
}
|
||||
-(void)textDidChange:(UITextField*)textField{
|
||||
if (textField.text.length>50) {
|
||||
showToast(@"评论不得超过50个字符");
|
||||
textField.text = [textField.text substringToIndex:50];
|
||||
}
|
||||
}
|
||||
-(BOOL)textFieldShouldReturn:(UITextField *)textField{
|
||||
[textField resignFirstResponder];
|
||||
return YES;
|
||||
}
|
||||
-(void)setModel:(QXDynamicCommentListModel *)model{
|
||||
_model = model;
|
||||
}
|
||||
-(void)inputBecomeFirstResponder{
|
||||
[self.textField becomeFirstResponder];
|
||||
}
|
||||
|
||||
-(void)sendAction{
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(didClickSendWithText:model:)]) {
|
||||
[self.delegate didClickSendWithText:self.textField.text model:self.model];
|
||||
}
|
||||
}
|
||||
@end
|
||||
16
QXLive/HomePage(声播)/Controlller/QXHomeSearchResultVC.h
Normal file
16
QXLive/HomePage(声播)/Controlller/QXHomeSearchResultVC.h
Normal file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// QXHomeSearchResultVC.h
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/7/10.
|
||||
//
|
||||
|
||||
#import "QXBaseViewController.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QXHomeSearchResultVC : QXBaseViewController
|
||||
@property (nonatomic,strong)NSArray *resultArray;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
87
QXLive/HomePage(声播)/Controlller/QXHomeSearchResultVC.m
Normal file
87
QXLive/HomePage(声播)/Controlller/QXHomeSearchResultVC.m
Normal file
@@ -0,0 +1,87 @@
|
||||
//
|
||||
// QXHomeSearchResultVC.m
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/7/10.
|
||||
//
|
||||
|
||||
#import "QXHomeSearchResultVC.h"
|
||||
#import "QXHomeRoomCell.h"
|
||||
|
||||
@interface QXHomeSearchResultVC ()<UICollectionViewDelegate,UICollectionViewDataSource>
|
||||
@property (nonatomic,strong)UICollectionView *collectionView;
|
||||
@end
|
||||
|
||||
@implementation QXHomeSearchResultVC
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
// Do any additional setup after loading the view.
|
||||
}
|
||||
-(void)setNavgationItems{
|
||||
[super setNavgationItems];
|
||||
self.navigationItem.title = @"搜索结果";
|
||||
}
|
||||
-(void)viewWillAppear:(BOOL)animated{
|
||||
[super viewWillAppear:animated];
|
||||
[self.navigationController setNavigationBarHidden:NO animated:YES];
|
||||
}
|
||||
-(void)initSubViews{
|
||||
[self.view addSubview:self.collectionView];
|
||||
}
|
||||
|
||||
-(void)setResultArray:(NSArray *)resultArray{
|
||||
_resultArray = resultArray;
|
||||
[self.collectionView reloadData];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - UICollectionViewDelegate,UICollectionViewDataSource,UICollectionViewDelegateFlowLayout
|
||||
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{
|
||||
return 1;
|
||||
}
|
||||
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
|
||||
return self.resultArray.count;
|
||||
}
|
||||
-(__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
|
||||
QXHomeRoomCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"QXHomeRoomCell" forIndexPath:indexPath];
|
||||
cell.searchModel = self.resultArray[indexPath.row];
|
||||
return cell;
|
||||
}
|
||||
|
||||
-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath{
|
||||
return CGSizeMake((SCREEN_WIDTH-15*3-1)/2.0, (SCREEN_WIDTH-15*3-1)/2.0);
|
||||
}
|
||||
|
||||
|
||||
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
|
||||
QXSearchModel *model = self.resultArray[indexPath.row];
|
||||
[[QXGlobal shareGlobal] joinRoomWithRoomId:model.id isRejoin:NO navagationController:self.navigationController];
|
||||
}
|
||||
|
||||
|
||||
-(UICollectionView *)collectionView{
|
||||
if (!_collectionView) {
|
||||
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
|
||||
layout.minimumLineSpacing = 15;
|
||||
layout.minimumInteritemSpacing = 15;
|
||||
layout.sectionInset = UIEdgeInsetsMake(0, 15, 0, 15);
|
||||
_collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 16, SCREEN_WIDTH, SCREEN_HEIGHT-(NavContentHeight+TabbarContentHeight)) collectionViewLayout:layout];
|
||||
_collectionView.delegate = self;
|
||||
_collectionView.dataSource = self;
|
||||
_collectionView.backgroundColor = [UIColor clearColor];
|
||||
[_collectionView registerNib:[UINib nibWithNibName:@"QXHomeRoomCell" bundle:[NSBundle mainBundle]] forCellWithReuseIdentifier:@"QXHomeRoomCell"];
|
||||
}
|
||||
return _collectionView;
|
||||
}
|
||||
/*
|
||||
#pragma mark - Navigation
|
||||
|
||||
// In a storyboard-based application, you will often want to do a little preparation before navigation
|
||||
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
|
||||
// Get the new view controller using [segue destinationViewController].
|
||||
// Pass the selected object to the new view controller.
|
||||
}
|
||||
*/
|
||||
|
||||
@end
|
||||
18
QXLive/HomePage(声播)/Controlller/QXHomeSubViewController.h
Normal file
18
QXLive/HomePage(声播)/Controlller/QXHomeSubViewController.h
Normal file
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// QXHomeSubViewController.h
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/5/7.
|
||||
//
|
||||
|
||||
#import "QXBaseViewController.h"
|
||||
#import "JXPagerView.h"
|
||||
#import "QXRoomListModel.h"
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QXHomeSubViewController : QXBaseViewController<JXPagerViewListViewDelegate>
|
||||
@property (nonatomic, copy) void(^listScrollCallback)(UIScrollView *scrollView);
|
||||
@property (nonatomic, strong)QXMyRoomType *roomType;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
117
QXLive/HomePage(声播)/Controlller/QXHomeSubViewController.m
Normal file
117
QXLive/HomePage(声播)/Controlller/QXHomeSubViewController.m
Normal file
@@ -0,0 +1,117 @@
|
||||
//
|
||||
// QXHomeSubViewController.m
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/5/7.
|
||||
//
|
||||
|
||||
#import "QXHomeSubViewController.h"
|
||||
#import "QXHomeRoomCell.h"
|
||||
#import "QXHomePageNetwork.h"
|
||||
|
||||
@interface QXHomeSubViewController ()<UICollectionViewDelegate,UICollectionViewDataSource>
|
||||
@property (nonatomic,strong)UICollectionView *collectionView;
|
||||
@property (nonatomic, copy) void(^scrollCallback)(UIScrollView *scrollView);
|
||||
@end
|
||||
|
||||
@implementation QXHomeSubViewController
|
||||
-(UIView *)listView{
|
||||
return self.view;
|
||||
}
|
||||
-(void)listWillAppear{
|
||||
[self getRoomList];
|
||||
}
|
||||
-(UIScrollView *)listScrollView{
|
||||
return self.collectionView;
|
||||
}
|
||||
- (void)listViewDidScrollCallback:(void (^)(UIScrollView *))callback {
|
||||
self.scrollCallback = callback;
|
||||
}
|
||||
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
|
||||
if (self.scrollCallback != nil) {
|
||||
self.scrollCallback(scrollView);
|
||||
}
|
||||
}
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
// Do any additional setup after loading the view.
|
||||
|
||||
}
|
||||
-(void)initSubViews{
|
||||
self.page = 1;
|
||||
[self.view addSubview:self.collectionView];
|
||||
// [self getRoomList];
|
||||
self.bgImageHidden = YES;
|
||||
}
|
||||
-(void)viewDidAppear:(BOOL)animated{
|
||||
[super viewDidAppear:animated];
|
||||
[self.collectionView reloadData];
|
||||
}
|
||||
-(void)setRoomType:(QXMyRoomType *)roomType{
|
||||
_roomType = roomType;
|
||||
[self getRoomList];
|
||||
}
|
||||
- (void)getRoomList {
|
||||
__weak typeof(self)weakSelf = self;
|
||||
[QXHomePageNetwork homeRoomListWithPage:self.page is_top:NO label_id:self.roomType.id successBlock:^(NSArray<QXRoomListModel *> * _Nonnull list, BOOL isAppStore) {
|
||||
if (self.page == 1) {
|
||||
[weakSelf.dataArray removeAllObjects];
|
||||
}
|
||||
[weakSelf.dataArray addObjectsFromArray:list];
|
||||
[self.collectionView reloadData];
|
||||
if (list.count == 0) {
|
||||
self.collectionView.mj_footer.state = MJRefreshStateNoMoreData;
|
||||
}else{
|
||||
[self.collectionView.mj_footer endRefreshing];
|
||||
}
|
||||
} failBlock:^(NSError * _Nonnull error, NSString * _Nonnull msg) {
|
||||
[self.collectionView.mj_footer endRefreshing];
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - UICollectionViewDelegate,UICollectionViewDataSource,UICollectionViewDelegateFlowLayout
|
||||
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{
|
||||
return 1;
|
||||
}
|
||||
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
|
||||
return self.dataArray.count;
|
||||
}
|
||||
-(__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
|
||||
QXHomeRoomCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"QXHomeRoomCell" forIndexPath:indexPath];
|
||||
cell.model = self.dataArray[indexPath.row];
|
||||
return cell;
|
||||
}
|
||||
|
||||
-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath{
|
||||
return CGSizeMake((SCREEN_WIDTH-15*3-1)/2.0, (SCREEN_WIDTH-15*3-1)/2.0);
|
||||
}
|
||||
|
||||
|
||||
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
|
||||
QXRoomListModel *model = self.dataArray[indexPath.row];
|
||||
[[QXGlobal shareGlobal] joinRoomWithRoomId:model.room_id isRejoin:NO navagationController:self.navigationController];
|
||||
}
|
||||
|
||||
|
||||
-(UICollectionView *)collectionView{
|
||||
if (!_collectionView) {
|
||||
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
|
||||
layout.minimumLineSpacing = 15;
|
||||
layout.minimumInteritemSpacing = 15;
|
||||
layout.sectionInset = UIEdgeInsetsMake(0, 15, 0, 15);
|
||||
_collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT-(NavContentHeight+TabbarContentHeight)) collectionViewLayout:layout];
|
||||
_collectionView.delegate = self;
|
||||
_collectionView.dataSource = self;
|
||||
_collectionView.backgroundColor = [UIColor clearColor];
|
||||
[_collectionView registerNib:[UINib nibWithNibName:@"QXHomeRoomCell" bundle:[NSBundle mainBundle]] forCellWithReuseIdentifier:@"QXHomeRoomCell"];
|
||||
MJWeakSelf
|
||||
_collectionView.mj_footer = [MJRefreshBackStateFooter footerWithRefreshingBlock:^{
|
||||
weakSelf.page++;
|
||||
[weakSelf getRoomList];
|
||||
}];
|
||||
}
|
||||
return _collectionView;
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
16
QXLive/HomePage(声播)/Controlller/QXHomeViewController.h
Normal file
16
QXLive/HomePage(声播)/Controlller/QXHomeViewController.h
Normal file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// QXHomeViewController.h
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/4/24.
|
||||
//
|
||||
|
||||
#import "QXBaseViewController.h"
|
||||
#import "QXGiftScrollView.h"
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QXHomeViewController : QXBaseViewController
|
||||
-(void)giftScrollViewShowWithModel:(QXGiftScrollModel*)model;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
470
QXLive/HomePage(声播)/Controlller/QXHomeViewController.m
Normal file
470
QXLive/HomePage(声播)/Controlller/QXHomeViewController.m
Normal file
@@ -0,0 +1,470 @@
|
||||
//
|
||||
// QXHomeViewController.m
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/4/24.
|
||||
//
|
||||
|
||||
#import "QXHomeViewController.h"
|
||||
#import "JXCategoryView.h"
|
||||
#import "GKCycleScrollView.h"
|
||||
#import "QXHomeTopCell.h"
|
||||
#import "QXHomeSubViewController.h"
|
||||
#import "QXSearchViewController.h"
|
||||
#import "QXRankHomeVC.h"
|
||||
#import "SDCycleScrollView.h"
|
||||
#import "JXPagerView.h"
|
||||
#import "QXHomePageNetwork.h"
|
||||
#import "QXMyRoomViewController.h"
|
||||
#import "QXUserHomePageViewController.h"
|
||||
#import "QXFirstRechargePopView.h"
|
||||
#import "QXRechargeView.h"
|
||||
#import "QXAppstoreHomeView.h"
|
||||
|
||||
@interface QXHomeViewController ()<JXPagerViewDelegate,JXCategoryViewDelegate,GKCycleScrollViewDataSource,GKCycleScrollViewDelegate,QXGiftScrollViewDelegate,SDCycleScrollViewDelegate>
|
||||
@property (nonatomic, strong) JXPagerView *pagingView;
|
||||
@property (nonatomic,strong)JXCategoryTitleView *categoryView;
|
||||
@property (nonatomic,strong)NSMutableArray <UIViewController*>*listVCArray;
|
||||
@property (nonatomic,strong)NSMutableArray *titles;
|
||||
@property (nonatomic,strong)NSArray *titleModelArray;
|
||||
@property (nonatomic,strong)GKCycleScrollView *cycleScrollView;
|
||||
@property (nonatomic,strong)JXCategoryIndicatorImageView *indicatorView;
|
||||
@property (nonatomic,strong)UIButton *rankRightBtn;
|
||||
@property (nonatomic,strong)UIButton *searchRightBtn;
|
||||
@property (nonatomic,strong)UIButton *roomBtn;
|
||||
@property (nonatomic,strong)QXGiftScrollView *giftScrollView;
|
||||
@property (nonatomic,strong)SDCycleScrollView *bannerScrollView;
|
||||
@property (nonatomic,assign)BOOL isShowGiftScrollView;
|
||||
@property (nonatomic,strong)NSMutableArray *bannerArry;
|
||||
|
||||
@property (nonatomic,strong)UIView *headerView;
|
||||
@property (nonatomic,strong)UIView *sectionView;
|
||||
|
||||
@property (nonatomic,strong)UIButton *firstRechargeBtn;
|
||||
@property (nonatomic,strong)UIButton *skyDownBtn;
|
||||
@property (nonatomic,strong)QXFirstRechargePopView *firstRechargeView;
|
||||
|
||||
@property (nonatomic,strong)QXAppstoreHomeView *appStoreView;
|
||||
@end
|
||||
|
||||
@implementation QXHomeViewController
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
// Do any additional setup after loading the view.
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(loginSuccess) name:noticeUserLogin object:nil];
|
||||
}
|
||||
-(void)viewWillAppear:(BOOL)animated{
|
||||
[super viewWillAppear:animated];
|
||||
[self.navigationController setNavigationBarHidden:YES animated:YES];
|
||||
}
|
||||
|
||||
- (void)initSubViews{
|
||||
UILabel *tLabel = [[UILabel alloc] init];
|
||||
tLabel.text = QXText(@"羽声");
|
||||
tLabel.font = [UIFont boldSystemFontOfSize:20];
|
||||
[self.view addSubview:tLabel];
|
||||
[tLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.mas_equalTo(16);
|
||||
make.top.mas_equalTo(kSafeAreaTop +10);
|
||||
}];
|
||||
[self.view addSubview:self.rankRightBtn];
|
||||
[self.view addSubview:self.searchRightBtn];
|
||||
[self.view addSubview:self.roomBtn];
|
||||
|
||||
[self.roomBtn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.width.height.mas_equalTo(30);
|
||||
make.centerY.equalTo(tLabel);
|
||||
make.right.equalTo(self.view).offset(-10);
|
||||
}];
|
||||
[self.searchRightBtn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.right.equalTo(self.roomBtn.mas_left).offset(-10);
|
||||
make.centerY.width.height.equalTo(self.roomBtn);
|
||||
}];
|
||||
[self.rankRightBtn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.right.equalTo(self.searchRightBtn.mas_left).offset(-10);
|
||||
make.centerY.equalTo(self.roomBtn);
|
||||
make.width.height.mas_equalTo(30);
|
||||
}];
|
||||
|
||||
self.listVCArray = [NSMutableArray array];
|
||||
[self requestSlideToolData];
|
||||
[self getTopRoomList];
|
||||
_pagingView = [[JXPagerView alloc] initWithDelegate:self];
|
||||
_pagingView.mainTableView.backgroundColor = [UIColor clearColor];
|
||||
self.pagingView.backgroundColor = [UIColor clearColor];
|
||||
[self.view addSubview:self.pagingView];
|
||||
|
||||
self.categoryView.listContainer = (id<JXCategoryViewListContainer>)self.pagingView.listContainerView;
|
||||
self.pagingView.listContainerView.listCellBackgroundColor = [UIColor clearColor];
|
||||
// [self performSelector:@selector(giftScrollViewShow) afterDelay:5];
|
||||
MJWeakSelf
|
||||
self.pagingView.mainTableView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{
|
||||
[weakSelf requestSlideToolData];
|
||||
[weakSelf getTopRoomList];
|
||||
[weakSelf getBanner];
|
||||
}];
|
||||
|
||||
self.firstRechargeBtn.hidden = YES;
|
||||
[self.view addSubview:self.firstRechargeBtn];
|
||||
[self.firstRechargeBtn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.bottom.mas_equalTo(-(TabbarContentHeight+5));
|
||||
make.right.equalTo(self.view).offset(-17);
|
||||
make.width.height.mas_equalTo(ScaleWidth(57));
|
||||
}];
|
||||
[self getBanner];
|
||||
[self getFirstRechargePermission];
|
||||
self.appStoreView.hidden = YES;
|
||||
[self.view addSubview:self.appStoreView];
|
||||
}
|
||||
- (void)viewDidLayoutSubviews {
|
||||
[super viewDidLayoutSubviews];
|
||||
|
||||
self.pagingView.frame = CGRectMake(0, NavContentHeight, SCREEN_WIDTH, SCREEN_HEIGHT-NavContentHeight-TabbarContentHeight);
|
||||
}
|
||||
-(void)loginSuccess{
|
||||
[self requestSlideToolData];
|
||||
[self getTopRoomList];
|
||||
[self getBanner];
|
||||
}
|
||||
- (void)requestSlideToolData {
|
||||
__weak typeof(self) weakSelf = self;
|
||||
[QXHomePageNetwork homeRoomLabelListsuccessBlock:^(NSArray<QXMyRoomType *> * _Nonnull list) {
|
||||
[weakSelf.titles removeAllObjects];
|
||||
NSMutableArray *arr = [NSMutableArray array];
|
||||
[weakSelf.titles addObjectsFromArray:list];
|
||||
for (QXMyRoomType *md in list) {
|
||||
[arr addObject:md.label_name];
|
||||
}
|
||||
weakSelf.categoryView.titles = arr;
|
||||
[weakSelf.categoryView reloadData];
|
||||
[weakSelf.pagingView.mainTableView.mj_header endRefreshing];
|
||||
} failBlock:^(NSError * _Nonnull error, NSString * _Nonnull msg) {
|
||||
[weakSelf.pagingView.mainTableView.mj_header endRefreshing];
|
||||
}];
|
||||
}
|
||||
|
||||
-(void)getFirstRechargePermission{
|
||||
MJWeakSelf
|
||||
[QXHomePageNetwork getFirstRechargePermissionSuccessBlock:^(BOOL isShow) {
|
||||
weakSelf.firstRechargeBtn.hidden = !isShow;
|
||||
} failBlock:^(NSError * _Nonnull error, NSString * _Nonnull msg) {
|
||||
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
-(void)firstAction{
|
||||
[self popFirstRechargeView];
|
||||
}
|
||||
-(void)popFirstRechargeView{
|
||||
MJWeakSelf
|
||||
// view.giftArray = @[@"",@"",@"",@"",@"",@""];
|
||||
self.firstRechargeView.closeActionBlock = ^{
|
||||
[[QXGlobal shareGlobal].alertViewController hideViewFinishBlock:^{
|
||||
QXLOG(@"页面关闭");
|
||||
|
||||
}];
|
||||
};
|
||||
self.firstRechargeView.rechargeActionBlock = ^(NSString * _Nonnull money) {
|
||||
[[QXGlobal shareGlobal].alertViewController hideViewFinishBlock:^{
|
||||
QXLOG(@"页面关闭");
|
||||
QXRechargeView *recharge = [[QXRechargeView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT)];
|
||||
QXRechargeListModel *model = [[QXRechargeListModel alloc] init];
|
||||
model.money = money;
|
||||
recharge.selectedModel = model;
|
||||
recharge.isPop = YES;
|
||||
recharge.isOnlyDisplayPayType = YES;
|
||||
[recharge showInView:KEYWINDOW];
|
||||
}];
|
||||
};
|
||||
[self.firstRechargeView reloadData];
|
||||
[[QXGlobal shareGlobal] showView:self.firstRechargeView popType:(PopViewTypeTopToCenter) tapDismiss:NO finishBlock:^{
|
||||
|
||||
}];
|
||||
}
|
||||
#pragma mark - JXPagingViewDelegate
|
||||
|
||||
- (UIView *)tableHeaderViewInPagerView:(JXPagerView *)pagerView {
|
||||
return self.headerView;
|
||||
}
|
||||
- (NSUInteger)tableHeaderViewHeightInPagerView:(JXPagerView *)pagerView {
|
||||
return self.headerView.height;
|
||||
}
|
||||
|
||||
- (NSUInteger)heightForPinSectionHeaderInPagerView:(JXPagerView *)pagerView {
|
||||
return 48;
|
||||
}
|
||||
- (UIView *)viewForPinSectionHeaderInPagerView:(JXPagerView *)pagerView {
|
||||
return self.sectionView;
|
||||
}
|
||||
|
||||
- (NSInteger)numberOfListsInPagerView:(JXPagerView *)pagerView {
|
||||
return self.titles.count;
|
||||
}
|
||||
|
||||
- (id<JXPagerViewListViewDelegate>)pagerView:(JXPagerView *)pagerView initListAtIndex:(NSInteger)index {
|
||||
QXHomeSubViewController *vc = [[QXHomeSubViewController alloc] init];
|
||||
QXMyRoomType *model = self.titles[index];
|
||||
vc.roomType = model;
|
||||
return vc;
|
||||
}
|
||||
-(void)categoryView:(JXCategoryBaseView *)categoryView didClickSelectedItemAtIndex:(NSInteger)index{
|
||||
|
||||
}
|
||||
|
||||
-(void)giftScrollViewShowWithModel:(QXGiftScrollModel*)model{
|
||||
if (self.isShowGiftScrollView == NO) {
|
||||
// self.categoryView.frame = CGRectMake(15, self.giftScrollView.bottom, SCREEN_WIDTH-30, 44);
|
||||
// self.containerView.frame = CGRectMake(0, self.categoryView.bottom, SCREEN_WIDTH, SCREEN_HEIGHT-self.categoryView.bottom-TabbarHeight);
|
||||
self.bannerScrollView.top = self.giftScrollView.bottom+12;
|
||||
self.headerView.height += 12+self.giftScrollView.height;
|
||||
[self.headerView addSubview:self.giftScrollView];
|
||||
// [self.pagingView reloadData];
|
||||
[self.pagingView resizeTableHeaderViewHeightWithAnimatable:YES duration:0.1 curve:UIViewAnimationCurveLinear];
|
||||
}
|
||||
++self.page;
|
||||
self.giftScrollView.model = model;
|
||||
self.isShowGiftScrollView = YES;
|
||||
}
|
||||
-(void)didClickGiftScrollView:(QXGiftScrollView *)giftScrollView index:(NSInteger)index model:(QXGiftScrollModel *)model{
|
||||
[[QXGlobal shareGlobal] joinRoomWithRoomId:model.roomId isRejoin:NO navagationController:self.navigationController];
|
||||
}
|
||||
- (void)getTopRoomList {
|
||||
__weak typeof(self)weakSelf = self;
|
||||
[QXHomePageNetwork homeRoomListWithPage:0 is_top:YES label_id:@"" successBlock:^(NSArray<QXRoomListModel *> * _Nonnull list, BOOL isAppStore) {
|
||||
[weakSelf.dataArray removeAllObjects];
|
||||
[weakSelf.dataArray addObjectsFromArray:list];
|
||||
if (isAppStore) {
|
||||
self.appStoreView.hidden = NO;
|
||||
}else{
|
||||
self.appStoreView.hidden = YES;
|
||||
}
|
||||
// weakSelf.appStoreView.dataArray = list;
|
||||
[weakSelf.cycleScrollView reloadData];
|
||||
} failBlock:^(NSError * _Nonnull error, NSString * _Nonnull msg) {
|
||||
|
||||
}];
|
||||
|
||||
}
|
||||
-(void)getBanner{
|
||||
MJWeakSelf
|
||||
[QXHomePageNetwork homeBannerSuccessBlock:^(NSArray<QXBanner *> * _Nonnull list) {
|
||||
NSMutableArray *arr = [NSMutableArray array];
|
||||
for (QXBanner *banner in list) {
|
||||
[arr addObject:banner.image];
|
||||
}
|
||||
[weakSelf.bannerArry removeAllObjects];
|
||||
[weakSelf.bannerArry addObjectsFromArray:list];
|
||||
weakSelf.appStoreView.bannerArray = list;
|
||||
weakSelf.bannerScrollView.imageURLStringsGroup = arr;
|
||||
} failBlock:^(NSError * _Nonnull error, NSString * _Nonnull msg) {
|
||||
|
||||
}];
|
||||
}
|
||||
#pragma mark - GKCycleScrollViewDataSource,GKCycleScrollViewDelegate
|
||||
- (NSInteger)numberOfCellsInCycleScrollView:(GKCycleScrollView *)cycleScrollView {
|
||||
return self.dataArray.count;
|
||||
}
|
||||
- (GKCycleScrollViewCell *)cycleScrollView:(GKCycleScrollView *)cycleScrollView cellForViewAtIndex:(NSInteger)index {
|
||||
GKCycleScrollViewCell *cell = [cycleScrollView dequeueReusableCell];
|
||||
if (!cell) {
|
||||
cell = [QXHomeTopCell new];
|
||||
}
|
||||
QXHomeTopCell *topcell = (QXHomeTopCell*)cell;
|
||||
topcell.roomModel = [self.dataArray objectAtIndex:index];
|
||||
return cell;
|
||||
}
|
||||
|
||||
- (CGSize)sizeForCellInCycleScrollView:(GKCycleScrollView *)cycleScrollView {
|
||||
return CGSizeMake((SCREEN_WIDTH)/3, 113);
|
||||
}
|
||||
|
||||
- (void)cycleScrollView:(GKCycleScrollView *)cycleScrollView didSelectCellAtIndex:(NSInteger)index {
|
||||
QXRoomListModel *model = self.dataArray[index];
|
||||
[[QXGlobal shareGlobal] joinRoomWithRoomId:model.room_id isRejoin:NO navagationController:self.navigationController];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - SDCycleScrollViewDelegate
|
||||
-(void)cycleScrollView:(SDCycleScrollView *)cycleScrollView didSelectItemAtIndex:(NSInteger)index{
|
||||
if (!QXGlobal.shareGlobal.isLogin) {
|
||||
[[QXGlobal shareGlobal] logOut];
|
||||
return;
|
||||
}
|
||||
QXBanner *banner = self.bannerArry[index];
|
||||
if ([banner.type isEqualToString:@"2"]) {
|
||||
QXBaseWebViewController *webVc = [[QXBaseWebViewController alloc] init];
|
||||
webVc.urlStr = banner.url;
|
||||
[self.navigationController pushViewController:webVc animated:YES];
|
||||
}else if ([banner.type isEqualToString:@"3"]){
|
||||
[[QXGlobal shareGlobal] joinRoomWithRoomId:banner.aid isRejoin:NO navagationController:self.navigationController];
|
||||
}else if ([banner.type isEqualToString:@"4"]){
|
||||
QXUserHomePageViewController *userHomePage = [[QXUserHomePageViewController alloc] init];
|
||||
userHomePage.user_id = banner.aid;
|
||||
[self.navigationController pushViewController:userHomePage animated:YES];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
-(void)gotoRoom{
|
||||
if (!QXGlobal.shareGlobal.isLogin) {
|
||||
[[QXGlobal shareGlobal] logOut];
|
||||
return;
|
||||
}
|
||||
QXMyRoomViewController *vc = [[QXMyRoomViewController alloc] init];
|
||||
[self.navigationController pushViewController:vc animated:YES];
|
||||
}
|
||||
-(void)gotoSearchVC{
|
||||
if (!QXGlobal.shareGlobal.isLogin) {
|
||||
[[QXGlobal shareGlobal] logOut];
|
||||
return;
|
||||
}
|
||||
QXSearchViewController *vc = [[QXSearchViewController alloc] init];
|
||||
[self.navigationController pushViewController:vc animated:YES];
|
||||
}
|
||||
-(void)gotoRankVC{
|
||||
if (!QXGlobal.shareGlobal.isLogin) {
|
||||
[[QXGlobal shareGlobal] logOut];
|
||||
return;
|
||||
}
|
||||
QXRankHomeVC *vc = [[QXRankHomeVC alloc] init];
|
||||
[self.navigationController pushViewController:vc animated:YES];
|
||||
}
|
||||
-(UIButton *)roomBtn{
|
||||
if (!_roomBtn) {
|
||||
_roomBtn = [[UIButton alloc] init];
|
||||
[_roomBtn setImage:[UIImage imageNamed:@"home_room"] forState:UIControlStateNormal];
|
||||
[_roomBtn setImage:[UIImage imageNamed:@"home_room"] forState:UIControlStateHighlighted];
|
||||
[_roomBtn addTarget:self action:@selector(gotoRoom) forControlEvents:UIControlEventTouchUpInside];
|
||||
}
|
||||
return _roomBtn;
|
||||
}
|
||||
- (UIButton *)rankRightBtn {
|
||||
if (!_rankRightBtn) {
|
||||
_rankRightBtn = [[UIButton alloc] init];
|
||||
[_rankRightBtn setImage:[UIImage imageNamed:@"home_ranking"] forState:UIControlStateNormal];
|
||||
[_rankRightBtn setImage:[UIImage imageNamed:@"home_ranking"] forState:UIControlStateHighlighted];
|
||||
[_rankRightBtn addTarget:self action:@selector(gotoRankVC) forControlEvents:UIControlEventTouchUpInside];
|
||||
}
|
||||
return _rankRightBtn;
|
||||
}
|
||||
|
||||
- (UIButton *)searchRightBtn {
|
||||
if (!_searchRightBtn) {
|
||||
_searchRightBtn = [[UIButton alloc] init];
|
||||
[_searchRightBtn setImage:[UIImage imageNamed:@"home_search"] forState:UIControlStateNormal];
|
||||
[_searchRightBtn setImage:[UIImage imageNamed:@"home_search"] forState:UIControlStateHighlighted];
|
||||
[_searchRightBtn addTarget:self action:@selector(gotoSearchVC) forControlEvents:UIControlEventTouchUpInside];
|
||||
}
|
||||
return _searchRightBtn;
|
||||
}
|
||||
-(UIView *)sectionView{
|
||||
if (!_sectionView) {
|
||||
_sectionView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, 44)];
|
||||
[_sectionView addSubview:self.categoryView];
|
||||
}
|
||||
return _sectionView;
|
||||
}
|
||||
-(JXCategoryTitleView *)categoryView{
|
||||
if (!_categoryView) {
|
||||
_categoryView = [[JXCategoryTitleView alloc] init];
|
||||
_categoryView.frame = CGRectMake(15, 0, SCREEN_WIDTH-30, 44);
|
||||
_categoryView.delegate = self;
|
||||
_categoryView.titleSelectedColor = [UIColor colorWithHexString:@"#333333"];
|
||||
_categoryView.titleColor = [UIColor colorWithHexString:@"#666666"];
|
||||
_categoryView.cellWidth = JXCategoryViewAutomaticDimension;
|
||||
_categoryView.contentEdgeInsetLeft = 3;
|
||||
_categoryView.cellSpacing = 16;
|
||||
_categoryView.titleLabelZoomEnabled = YES;
|
||||
_categoryView.titleFont = [UIFont boldSystemFontOfSize:13];
|
||||
_categoryView.titleSelectedFont = [UIFont boldSystemFontOfSize:18];
|
||||
_categoryView.averageCellSpacingEnabled = NO;
|
||||
JXCategoryIndicatorImageView *indicatorView = [[JXCategoryIndicatorImageView alloc] init];
|
||||
indicatorView.indicatorWidth = JXCategoryViewAutomaticDimension;
|
||||
indicatorView.indicatorImageView.image = [UIImage imageNamed:@"home_slider"];
|
||||
indicatorView.indicatorImageViewSize = CGSizeMake(29, 8);
|
||||
self.indicatorView = indicatorView;
|
||||
indicatorView.verticalMargin = 11;
|
||||
_categoryView.indicators = @[indicatorView];
|
||||
}
|
||||
return _categoryView;
|
||||
}
|
||||
-(UIView *)headerView{
|
||||
if (!_headerView) {
|
||||
_headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, self.cycleScrollView.height+self.bannerScrollView.height)];
|
||||
[_headerView addSubview:self.cycleScrollView];
|
||||
[_headerView addSubview:self.bannerScrollView];
|
||||
}
|
||||
return _headerView;
|
||||
}
|
||||
-(SDCycleScrollView *)bannerScrollView{
|
||||
if (!_bannerScrollView) {
|
||||
_bannerScrollView = [SDCycleScrollView cycleScrollViewWithFrame:CGRectMake(16, self.cycleScrollView.bottom, SCREEN_WIDTH-32, ScaleWidth(95)) delegate:self placeholderImage:nil];
|
||||
_bannerScrollView.backgroundColor = [UIColor clearColor];
|
||||
_bannerScrollView.bannerImageViewContentMode = UIViewContentModeScaleAspectFill;
|
||||
[_bannerScrollView addRoundedCornersWithRadius:8] ;
|
||||
_bannerScrollView.delegate = self;
|
||||
}
|
||||
return _bannerScrollView;
|
||||
}
|
||||
-(GKCycleScrollView *)cycleScrollView{
|
||||
if (!_cycleScrollView) {
|
||||
_cycleScrollView = [[GKCycleScrollView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, ScaleWidth(113))];
|
||||
_cycleScrollView.dataSource = self;
|
||||
_cycleScrollView.delegate = self;
|
||||
_cycleScrollView.minimumCellAlpha = 0.0;
|
||||
_cycleScrollView.leftRightMargin = 16.0f;
|
||||
_cycleScrollView.topBottomMargin = 10.0f;
|
||||
}
|
||||
return _cycleScrollView;
|
||||
}
|
||||
-(QXGiftScrollView *)giftScrollView{
|
||||
if (!_giftScrollView) {
|
||||
_giftScrollView = [[QXGiftScrollView alloc] initWithFrame:CGRectMake(16, self.cycleScrollView.bottom, SCREEN_WIDTH-32, 31)];
|
||||
_giftScrollView.delegate = self;
|
||||
}
|
||||
return _giftScrollView;
|
||||
}
|
||||
-(NSMutableArray *)titles{
|
||||
if (!_titles) {
|
||||
_titles = [NSMutableArray array];
|
||||
}
|
||||
return _titles;
|
||||
}
|
||||
-(NSMutableArray *)bannerArry{
|
||||
if (!_bannerArry) {
|
||||
_bannerArry = [NSMutableArray array];
|
||||
}
|
||||
return _bannerArry;
|
||||
}
|
||||
-(UIButton *)firstRechargeBtn{
|
||||
if (!_firstRechargeBtn) {
|
||||
_firstRechargeBtn = [[UIButton alloc] init];
|
||||
[_firstRechargeBtn setBackgroundImage:[UIImage imageNamed:@"first_recharge_icon"] forState:(UIControlStateNormal)];
|
||||
[_firstRechargeBtn addTarget:self action:@selector(firstAction) forControlEvents:(UIControlEventTouchUpInside)];
|
||||
}
|
||||
return _firstRechargeBtn;
|
||||
}
|
||||
-(UIButton *)skyDownBtn{
|
||||
if (!_skyDownBtn) {
|
||||
_skyDownBtn = [[UIButton alloc] init];
|
||||
[_skyDownBtn setBackgroundImage:[UIImage imageNamed:@"sky_down_gift_icon"] forState:(UIControlStateNormal)];
|
||||
}
|
||||
return _skyDownBtn;
|
||||
}
|
||||
-(QXFirstRechargePopView *)firstRechargeView{
|
||||
if (!_firstRechargeView) {
|
||||
_firstRechargeView = [[QXFirstRechargePopView alloc] init];
|
||||
}
|
||||
return _firstRechargeView;
|
||||
}
|
||||
|
||||
|
||||
-(QXAppstoreHomeView *)appStoreView{
|
||||
if (!_appStoreView) {
|
||||
_appStoreView = [[QXAppstoreHomeView alloc] initWithFrame:CGRectMake(0, NavContentHeight, SCREEN_WIDTH, SCREEN_HEIGHT-NavContentHeight-TabbarContentHeight)];
|
||||
}
|
||||
return _appStoreView;
|
||||
}
|
||||
@end
|
||||
21
QXLive/HomePage(声播)/Controlller/QXRankHomeSubVC.h
Normal file
21
QXLive/HomePage(声播)/Controlller/QXRankHomeSubVC.h
Normal file
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// QXRankHomeSubVC.h
|
||||
// IsLandVoice
|
||||
//
|
||||
// Created by 启星 on 2025/3/3.
|
||||
//
|
||||
|
||||
#import "QXBaseViewController.h"
|
||||
#import "JXCategoryView.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QXRankHomeSubVC : QXBaseViewController<JXCategoryListContentViewDelegate>
|
||||
@property (nonatomic,strong)NSString *roomId;
|
||||
/// 1日 2 周 3月
|
||||
@property (nonatomic,strong)NSString *dataType;
|
||||
/// 1 魅力 2 财富 3 房间 4 cp
|
||||
@property (nonatomic,assign)NSInteger rankType;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
251
QXLive/HomePage(声播)/Controlller/QXRankHomeSubVC.m
Normal file
251
QXLive/HomePage(声播)/Controlller/QXRankHomeSubVC.m
Normal file
@@ -0,0 +1,251 @@
|
||||
//
|
||||
// QXRankHomeSubVC.m
|
||||
// IsLandVoice
|
||||
//
|
||||
// Created by 启星 on 2025/3/3.
|
||||
//
|
||||
|
||||
#import "QXRankHomeSubVC.h"
|
||||
#import "QXRankTypeView.h"
|
||||
#import "QXRankListCell.h"
|
||||
#import "QXRankTopThreeView.h"
|
||||
//#import "SRRankListRequest.h"
|
||||
//#import "SRRankListAdapter.h"
|
||||
#import "QXMyRankView.h"
|
||||
#import "QXRankCPListCell.h"
|
||||
#import "QXRankCPTopThreeView.h"
|
||||
#import "QXHomePageNetwork.h"
|
||||
|
||||
@interface QXRankHomeSubVC ()<UITableViewDelegate,UITableViewDataSource>
|
||||
@property (nonatomic,strong)QXRankTypeView *rankTypeView;
|
||||
@property (nonatomic,strong)UITableView *tableView;
|
||||
@property (nonatomic, strong) QXRankTopThreeView *headerView;
|
||||
@property (nonatomic, strong) QXRankCPTopThreeView *cpHeaderView;
|
||||
@property (nonatomic, strong) QXMyRankView *myRankView;
|
||||
@property (nonatomic, strong) NSMutableArray *topDataArray;
|
||||
@end
|
||||
|
||||
@implementation QXRankHomeSubVC
|
||||
-(UIView *)listView{
|
||||
return self.view;
|
||||
}
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
// Do any additional setup after loading the view.
|
||||
[self initSubViews];
|
||||
}
|
||||
|
||||
-(void)initSubViews{
|
||||
self.bgImageHidden = YES;
|
||||
self.dataType = @"1";
|
||||
self.view.backgroundColor = [UIColor clearColor];
|
||||
[self.view addSubview:self.rankTypeView];
|
||||
[self.view addSubview:self.myRankView];
|
||||
if (self.rankType == 4) {
|
||||
self.tableView.tableHeaderView = self.cpHeaderView;
|
||||
self.myRankView.isCP = YES;
|
||||
}else{
|
||||
self.myRankView.isCP = NO;
|
||||
self.tableView.tableHeaderView = self.headerView;
|
||||
}
|
||||
[self.view addSubview:self.tableView];
|
||||
[self getRankData];
|
||||
}
|
||||
|
||||
|
||||
-(void)getRankData{
|
||||
MJWeakSelf
|
||||
if (self.rankType == 0) {//房间榜
|
||||
[QXHomePageNetwork rankOfRoomWithType:self.dataType successBlock:^(QXRankModel * _Nonnull model) {
|
||||
[weakSelf.headerView resetView];
|
||||
if (weakSelf.page == 1) {
|
||||
[weakSelf.dataArray removeAllObjects];
|
||||
[weakSelf.topDataArray removeAllObjects];
|
||||
for (int i = 0; i < model.lists.count; i++) {
|
||||
if (i < 3) {
|
||||
[weakSelf.topDataArray addObject:model.lists[i]];
|
||||
}else{
|
||||
[weakSelf.dataArray addObject:model.lists[i]];
|
||||
}
|
||||
}
|
||||
}
|
||||
weakSelf.headerView.roomList = weakSelf.topDataArray;
|
||||
weakSelf.myRankView.roomModel = model.my_ranking;
|
||||
weakSelf.tableView.tableHeaderView = weakSelf.headerView;
|
||||
[weakSelf.tableView.mj_header endRefreshing];
|
||||
[weakSelf.tableView reloadData];
|
||||
} failBlock:^(NSError * _Nonnull error, NSString * _Nonnull msg) {
|
||||
[weakSelf.tableView.mj_header endRefreshing];
|
||||
}];
|
||||
}else if (self.rankType == 1){//财富榜
|
||||
[QXHomePageNetwork rankOfCharmWithRankingType:@"1" type:self.dataType page:self.page successBlock:^(QXRankModel * _Nonnull model) {
|
||||
[weakSelf.headerView resetView];
|
||||
if (weakSelf.page == 1) {
|
||||
[weakSelf.dataArray removeAllObjects];
|
||||
[weakSelf.topDataArray removeAllObjects];
|
||||
for (int i = 0; i < model.lists.count; i++) {
|
||||
if (i < 3) {
|
||||
[weakSelf.topDataArray addObject:model.lists[i]];
|
||||
}else{
|
||||
[weakSelf.dataArray addObject:model.lists[i]];
|
||||
}
|
||||
}
|
||||
}
|
||||
weakSelf.headerView.list = weakSelf.topDataArray;
|
||||
weakSelf.myRankView.model = model.my_ranking;
|
||||
weakSelf.tableView.tableHeaderView = weakSelf.headerView;
|
||||
[weakSelf.tableView.mj_header endRefreshing];
|
||||
[weakSelf.tableView reloadData];
|
||||
} failBlock:^(NSError * _Nonnull error, NSString * _Nonnull msg) {
|
||||
[weakSelf.tableView.mj_header endRefreshing];
|
||||
}];
|
||||
}else if (self.rankType == 2){//魅力榜
|
||||
[QXHomePageNetwork rankOfCharmWithRankingType:@"2" type:self.dataType page:self.page successBlock:^(QXRankModel * _Nonnull model) {
|
||||
[weakSelf.headerView resetView];
|
||||
if (weakSelf.page == 1) {
|
||||
[weakSelf.dataArray removeAllObjects];
|
||||
[weakSelf.topDataArray removeAllObjects];
|
||||
for (int i = 0; i < model.lists.count; i++) {
|
||||
if (i < 3) {
|
||||
[weakSelf.topDataArray addObject:model.lists[i]];
|
||||
}else{
|
||||
[weakSelf.dataArray addObject:model.lists[i]];
|
||||
}
|
||||
}
|
||||
}
|
||||
weakSelf.headerView.list = weakSelf.topDataArray;
|
||||
weakSelf.myRankView.model = model.my_ranking;
|
||||
weakSelf.tableView.tableHeaderView = weakSelf.headerView;
|
||||
[weakSelf.tableView.mj_header endRefreshing];
|
||||
[weakSelf.tableView reloadData];
|
||||
} failBlock:^(NSError * _Nonnull error, NSString * _Nonnull msg) {
|
||||
[weakSelf.tableView.mj_header endRefreshing];
|
||||
}];
|
||||
}else if (self.rankType == 3){//公会榜
|
||||
[QXHomePageNetwork rankOfGuildWithType:self.dataType successBlock:^(QXRankModel * _Nonnull model) {
|
||||
[weakSelf.headerView resetView];
|
||||
if (weakSelf.page == 1) {
|
||||
[weakSelf.dataArray removeAllObjects];
|
||||
[weakSelf.topDataArray removeAllObjects];
|
||||
for (int i = 0; i < model.lists.count; i++) {
|
||||
if (i < 3) {
|
||||
[weakSelf.topDataArray addObject:model.lists[i]];
|
||||
}else{
|
||||
[weakSelf.dataArray addObject:model.lists[i]];
|
||||
}
|
||||
}
|
||||
}
|
||||
weakSelf.headerView.guildList = weakSelf.topDataArray;
|
||||
weakSelf.myRankView.guildModel = model.my_ranking;
|
||||
weakSelf.tableView.tableHeaderView = weakSelf.headerView;
|
||||
[weakSelf.tableView.mj_header endRefreshing];
|
||||
[weakSelf.tableView reloadData];
|
||||
} failBlock:^(NSError * _Nonnull error, NSString * _Nonnull msg) {
|
||||
[weakSelf.tableView.mj_header endRefreshing];
|
||||
}];
|
||||
|
||||
}else{//cp榜
|
||||
[QXHomePageNetwork rankOfRealLoveWithType:self.dataType successBlock:^(QXRankModel * _Nonnull model) {
|
||||
[weakSelf.cpHeaderView resetView];
|
||||
if (weakSelf.page == 1) {
|
||||
[weakSelf.dataArray removeAllObjects];
|
||||
[weakSelf.topDataArray removeAllObjects];
|
||||
for (int i = 0; i < model.lists.count; i++) {
|
||||
if (i < 3) {
|
||||
[weakSelf.topDataArray addObject:model.lists[i]];
|
||||
}else{
|
||||
[weakSelf.dataArray addObject:model.lists[i]];
|
||||
}
|
||||
}
|
||||
}
|
||||
weakSelf.cpHeaderView.list = weakSelf.topDataArray;
|
||||
weakSelf.myRankView.cpModel = model.my_ranking;
|
||||
weakSelf.tableView.tableHeaderView = weakSelf.cpHeaderView;
|
||||
[weakSelf.tableView.mj_header endRefreshing];
|
||||
[weakSelf.tableView reloadData];
|
||||
} failBlock:^(NSError * _Nonnull error, NSString * _Nonnull msg) {
|
||||
[weakSelf.tableView.mj_header endRefreshing];
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - <UITableViewDelegate,UITableViewDataSource>
|
||||
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
|
||||
return 1;
|
||||
}
|
||||
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
|
||||
return self.dataArray.count;
|
||||
}
|
||||
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
|
||||
if (self.rankType == 4) {//CP
|
||||
QXRankCPListCell *cell = [QXRankCPListCell cellWithTableView:tableView];
|
||||
// cell.model = self.dataArray[indexPath.row];
|
||||
return cell;
|
||||
}else{
|
||||
QXRankListCell *cell = [QXRankListCell cellWithTableView:tableView];
|
||||
cell.rankType = self.rankType;
|
||||
cell.model = self.dataArray[indexPath.row];
|
||||
return cell;
|
||||
}
|
||||
}
|
||||
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
|
||||
// if (self.rankType != 4) {//CP
|
||||
// QXHomeRoomListModel *model = self.dataArray[indexPath.row];
|
||||
// SRPersonalViewController *pvc = [[SRPersonalViewController alloc] initWithUserId:[model.user_id longLongValue]];
|
||||
// pvc.emchatUsername = model.emchat_username;
|
||||
// [self.navigationController pushViewController:pvc animated:YES];
|
||||
// }
|
||||
}
|
||||
-(QXRankTypeView *)rankTypeView{
|
||||
if (!_rankTypeView) {
|
||||
_rankTypeView = [[QXRankTypeView alloc] initWithFrame:CGRectMake(0, kSafeAreaTop+30, SCREEN_WIDTH, 30)];
|
||||
MJWeakSelf
|
||||
_rankTypeView.rankTypeBlock = ^(QXRankType type) {
|
||||
weakSelf.dataType = [NSString stringWithFormat:@"%ld",type];
|
||||
[weakSelf getRankData];
|
||||
};
|
||||
}
|
||||
return _rankTypeView;
|
||||
}
|
||||
-(QXRankTopThreeView *)headerView{
|
||||
if (!_headerView) {
|
||||
_headerView = [[QXRankTopThreeView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, 230)];
|
||||
}
|
||||
return _headerView;
|
||||
}
|
||||
-(QXRankCPTopThreeView *)cpHeaderView{
|
||||
if (!_cpHeaderView) {
|
||||
_cpHeaderView = [[QXRankCPTopThreeView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, 230)];
|
||||
}
|
||||
return _cpHeaderView;
|
||||
}
|
||||
-(QXMyRankView *)myRankView{
|
||||
if (!_myRankView) {
|
||||
_myRankView = [[QXMyRankView alloc] initWithFrame:CGRectMake(0, SCREEN_HEIGHT-TabbarContentHeight-60-44, SCREEN_WIDTH, 60)];
|
||||
}
|
||||
return _myRankView;
|
||||
}
|
||||
-(UITableView *)tableView{
|
||||
if (!_tableView) {
|
||||
_tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, self.rankTypeView.bottom+10, SCREEN_WIDTH, self.myRankView.top - self.rankTypeView.bottom-10) style:(UITableViewStyleGrouped)];
|
||||
_tableView.dataSource = self;
|
||||
_tableView.delegate = self;
|
||||
_tableView.backgroundColor = [UIColor clearColor];
|
||||
_tableView.tableFooterView = [UIView new];
|
||||
_tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
|
||||
_tableView.rowHeight = 50;
|
||||
MJWeakSelf
|
||||
_tableView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{
|
||||
[weakSelf getRankData];
|
||||
}];
|
||||
}
|
||||
return _tableView;
|
||||
}
|
||||
|
||||
-(NSMutableArray *)topDataArray{
|
||||
if (!_topDataArray) {
|
||||
_topDataArray = [NSMutableArray array] ;
|
||||
}
|
||||
return _topDataArray;
|
||||
}
|
||||
@end
|
||||
16
QXLive/HomePage(声播)/Controlller/QXRankHomeVC.h
Normal file
16
QXLive/HomePage(声播)/Controlller/QXRankHomeVC.h
Normal file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// QXRankHomeVC.h
|
||||
// IsLandVoice
|
||||
//
|
||||
// Created by 启星 on 2025/3/3.
|
||||
//
|
||||
|
||||
#import "QXBaseViewController.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QXRankHomeVC : QXBaseViewController
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
80
QXLive/HomePage(声播)/Controlller/QXRankHomeVC.m
Normal file
80
QXLive/HomePage(声播)/Controlller/QXRankHomeVC.m
Normal file
@@ -0,0 +1,80 @@
|
||||
//
|
||||
// QXRankHomeVC.m
|
||||
// IsLandVoice
|
||||
//
|
||||
// Created by 启星 on 2025/3/3.
|
||||
//
|
||||
|
||||
#import "QXRankHomeVC.h"
|
||||
#import "JXCategoryView.h"
|
||||
#import "QXRankHomeSubVC.h"
|
||||
|
||||
@interface QXRankHomeVC ()<JXCategoryViewDelegate,JXCategoryListContainerViewDelegate>
|
||||
@property (nonatomic,strong)JXCategoryTitleView *categoryView;
|
||||
@property (nonatomic,strong)JXCategoryListContainerView *containerView;
|
||||
@property (nonatomic,strong)NSMutableArray <UIViewController*>*listVCArray;
|
||||
@property (nonatomic,strong)NSArray*titles;
|
||||
@end
|
||||
|
||||
@implementation QXRankHomeVC
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
// Do any additional setup after loading the view.
|
||||
|
||||
}
|
||||
-(void)viewWillAppear:(BOOL)animated{
|
||||
[super viewWillAppear:animated];
|
||||
[self.navigationController setNavigationBarHidden:NO animated:YES];
|
||||
}
|
||||
-(void)initSubViews{
|
||||
self.view.backgroundColor = [UIColor whiteColor];
|
||||
self.titles = @[@"房间榜", @"财富榜", @"魅力榜",@"公会榜",@"真爱榜"];
|
||||
self.listVCArray = [NSMutableArray array];
|
||||
self.categoryView = [[JXCategoryTitleView alloc] init];
|
||||
self.categoryView.frame = CGRectMake(0, 0, SCREEN_WIDTH-100, 44);
|
||||
self.categoryView.delegate = self;
|
||||
self.categoryView.titles = self.titles;
|
||||
self.categoryView.titleSelectedColor = [UIColor colorWithHexString:@"#333333"];
|
||||
self.categoryView.titleColor = [UIColor colorWithHexString:@"#999999"];
|
||||
JXCategoryIndicatorImageView *indicatorImageView = [[JXCategoryIndicatorImageView alloc] init];
|
||||
indicatorImageView.indicatorImageView.image = [UIImage imageNamed:@"home_slider"];
|
||||
indicatorImageView.indicatorWidth = (SCREEN_WIDTH-100)/5.0;
|
||||
indicatorImageView.indicatorHeight = 5;
|
||||
self.categoryView.indicators = @[indicatorImageView];
|
||||
self.categoryView.cellWidth = (SCREEN_WIDTH-100)/5.0;
|
||||
self.categoryView.contentEdgeInsetLeft = 0;
|
||||
self.categoryView.cellSpacing = 0;
|
||||
self.categoryView.titleLabelZoomScale = 1.1;
|
||||
self.categoryView.titleLabelZoomEnabled = YES;
|
||||
self.categoryView.titleFont = [UIFont systemFontOfSize:14];
|
||||
self.categoryView.averageCellSpacingEnabled = NO;
|
||||
|
||||
self.containerView = [[JXCategoryListContainerView alloc] initWithType:(JXCategoryListContainerType_ScrollView) delegate:self];
|
||||
self.containerView.frame = CGRectMake(0, self.categoryView.bottom, SCREEN_WIDTH, SCREEN_HEIGHT-self.categoryView.bottom);
|
||||
self.navigationItem.titleView = self.categoryView;
|
||||
[self.view addSubview:self.containerView];
|
||||
self.categoryView.listContainer = self.containerView;
|
||||
}
|
||||
-(NSInteger)numberOfListsInlistContainerView:(JXCategoryListContainerView *)listContainerView{
|
||||
return self.titles.count;
|
||||
}
|
||||
-(id<JXCategoryListContentViewDelegate>)listContainerView:(JXCategoryListContainerView *)listContainerView initListForIndex:(NSInteger)index{
|
||||
QXRankHomeSubVC *vc = [[QXRankHomeSubVC alloc] init];
|
||||
vc.rankType = index;
|
||||
return vc;
|
||||
}
|
||||
- (void)categoryView:(JXCategoryBaseView *)categoryView didSelectedItemAtIndex:(NSInteger)index {
|
||||
self.navigationController.interactivePopGestureRecognizer.enabled = (index == 0);
|
||||
}
|
||||
/*
|
||||
#pragma mark - Navigation
|
||||
|
||||
// In a storyboard-based application, you will often want to do a little preparation before navigation
|
||||
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
|
||||
// Get the new view controller using [segue destinationViewController].
|
||||
// Pass the selected object to the new view controller.
|
||||
}
|
||||
*/
|
||||
|
||||
@end
|
||||
16
QXLive/HomePage(声播)/Controlller/QXSearchViewController.h
Normal file
16
QXLive/HomePage(声播)/Controlller/QXSearchViewController.h
Normal file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// QXSearchViewController.h
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/5/8.
|
||||
//
|
||||
|
||||
#import "QXBaseViewController.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QXSearchViewController : QXBaseViewController
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
145
QXLive/HomePage(声播)/Controlller/QXSearchViewController.m
Normal file
145
QXLive/HomePage(声播)/Controlller/QXSearchViewController.m
Normal file
@@ -0,0 +1,145 @@
|
||||
//
|
||||
// QXSearchViewController.m
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/5/8.
|
||||
//
|
||||
|
||||
#import "QXSearchViewController.h"
|
||||
#import "ZLCollectionViewVerticalLayout.h"
|
||||
#import "QXSearchTopView.h"
|
||||
#import "QXSearchHeaderView.h"
|
||||
#import "QXSearchCell.h"
|
||||
#import "QXFileManager.h"
|
||||
#import "QXMineNetwork.h"
|
||||
#import "QXSearchModel.h"
|
||||
#import "QXHomeSearchResultVC.h"
|
||||
|
||||
@interface QXSearchViewController ()<UIGestureRecognizerDelegate,UICollectionViewDelegate,UICollectionViewDataSource,ZLCollectionViewBaseFlowLayoutDelegate,QXSearchTopViewDelegate>
|
||||
@property(nonatomic,strong)UICollectionView* collectionView;
|
||||
@property(nonatomic,strong)QXSearchTopView *topView;
|
||||
|
||||
@property(nonatomic,strong)NSMutableArray *resultArray;
|
||||
@end
|
||||
|
||||
@implementation QXSearchViewController
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
// Do any additional setup after loading the view.
|
||||
}
|
||||
-(void)viewWillAppear:(BOOL)animated{
|
||||
[super viewWillAppear:animated];
|
||||
[self.navigationController setNavigationBarHidden:YES animated:YES];
|
||||
}
|
||||
- (void)initSubViews{
|
||||
|
||||
[self.view addSubview:self.topView];
|
||||
[self.view addSubview:self.collectionView];
|
||||
[self getHistoryData];
|
||||
}
|
||||
-(void)getHistoryData{
|
||||
self.dataArray = [NSMutableArray arrayWithArray:[QXFileManager getSearchHistory]];
|
||||
[self.collectionView reloadData];
|
||||
}
|
||||
#pragma mark - QXSearchTopViewDelegate
|
||||
-(void)didClickCancel{
|
||||
[self.navigationController popViewControllerAnimated:YES];
|
||||
}
|
||||
-(void)didClickSearchWithKeywords:(NSString *)keywords{
|
||||
// 搜索
|
||||
[QXFileManager writeSearchHistoryWithContent:keywords];
|
||||
self.dataArray = [NSMutableArray arrayWithArray:[QXFileManager getSearchHistory]];
|
||||
[self.collectionView reloadData];
|
||||
[self searchActionWithKeywords:keywords];
|
||||
}
|
||||
|
||||
-(void)searchActionWithKeywords:(NSString *)keywords{
|
||||
MJWeakSelf
|
||||
[QXMineNetwork searchApiWithType:2 search:keywords successBlock:^(NSDictionary * _Nonnull dict) {
|
||||
[weakSelf.resultArray removeAllObjects];
|
||||
NSArray *arr = [NSArray yy_modelArrayWithClass:[QXSearchModel class] json:dict];
|
||||
if (arr.count == 0) {
|
||||
showToast(@"暂无搜索结果");
|
||||
return;
|
||||
}
|
||||
[weakSelf.resultArray addObjectsFromArray:arr];
|
||||
[weakSelf pushToResultVC];
|
||||
} failBlock:^(NSError * _Nonnull error, NSString * _Nonnull msg) {
|
||||
|
||||
}];
|
||||
}
|
||||
|
||||
-(void)pushToResultVC{
|
||||
QXHomeSearchResultVC *vc = [[QXHomeSearchResultVC alloc] init];
|
||||
vc.resultArray = self.resultArray;
|
||||
[self.navigationController pushViewController:vc animated:YES];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - UICollectionViewDelegate,UICollectionViewDataSource
|
||||
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{
|
||||
return 1;
|
||||
}
|
||||
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
|
||||
return self.dataArray.count;
|
||||
}
|
||||
-(__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
|
||||
QXSearchCell *cell = [QXSearchCell cellWithCollectionView:collectionView forIndexPath:indexPath];
|
||||
cell.titleLabel.text = self.dataArray[indexPath.row];
|
||||
return cell;
|
||||
}
|
||||
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
return CGSizeMake([self.dataArray[indexPath.row] boundingRectWithSize:CGSizeMake(1000000, 22) options:NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName: [UIFont boldSystemFontOfSize:12]} context:nil].size.width + 20, 22);
|
||||
}
|
||||
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {
|
||||
if ([kind isEqualToString : UICollectionElementKindSectionHeader]){
|
||||
QXSearchHeaderView* headerView = [QXSearchHeaderView headerViewWithCollectionView:collectionView forIndexPath:indexPath];
|
||||
headerView.title = QXText(@"历史记录");
|
||||
return headerView;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section{
|
||||
return CGSizeMake(SCREEN_WIDTH, 24);
|
||||
}
|
||||
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
|
||||
return UIEdgeInsetsMake(12, 16, 12, 16);
|
||||
}
|
||||
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
|
||||
NSString *keywords = self.dataArray[indexPath.row];
|
||||
[self searchActionWithKeywords:keywords];
|
||||
}
|
||||
-(UICollectionView *)collectionView{
|
||||
if (!_collectionView) {
|
||||
ZLCollectionViewVerticalLayout *flowLayout = [[ZLCollectionViewVerticalLayout alloc] init];
|
||||
flowLayout.delegate = self;
|
||||
flowLayout.canDrag = NO;
|
||||
flowLayout.isFloor = NO;
|
||||
flowLayout.header_suspension = NO;
|
||||
flowLayout.columnSortType = Sequence;
|
||||
_collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, self.topView.bottom+12, SCREEN_WIDTH, SCREEN_HEIGHT-self.topView.bottom-12) collectionViewLayout:flowLayout];
|
||||
_collectionView.delegate = self;
|
||||
_collectionView.dataSource = self;
|
||||
_collectionView.backgroundColor = [UIColor clearColor];
|
||||
[_collectionView registerClass:[QXSearchHeaderView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:[QXSearchHeaderView headerViewIdentifier]];
|
||||
[_collectionView registerClass:[QXSearchCell class] forCellWithReuseIdentifier:[QXSearchCell cellIdentifier]];
|
||||
_collectionView.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag;
|
||||
}
|
||||
return _collectionView;
|
||||
}
|
||||
-(QXSearchTopView *)topView{
|
||||
if (!_topView) {
|
||||
_topView = [[QXSearchTopView alloc] initWithFrame:CGRectMake(0, kSafeAreaTop, SCREEN_WIDTH, NavHeight)];
|
||||
_topView.delegate = self;
|
||||
}
|
||||
return _topView;
|
||||
}
|
||||
-(NSMutableArray *)resultArray{
|
||||
if (!_resultArray) {
|
||||
_resultArray = [NSMutableArray array];
|
||||
}
|
||||
return _resultArray;
|
||||
}
|
||||
|
||||
@end
|
||||
18
QXLive/HomePage(声播)/Controlller/房间/QXRoomViewController.h
Normal file
18
QXLive/HomePage(声播)/Controlller/房间/QXRoomViewController.h
Normal file
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// QXRoomViewController.h
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/6/7.
|
||||
//
|
||||
|
||||
#import "QXBaseViewController.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QXRoomViewController : QXBaseViewController
|
||||
@property (nonatomic,strong)NSString *roomId;
|
||||
/// 是否为最小化房间进来
|
||||
@property (nonatomic,assign)BOOL isReJoin;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
1732
QXLive/HomePage(声播)/Controlller/房间/QXRoomViewController.m
Normal file
1732
QXLive/HomePage(声播)/Controlller/房间/QXRoomViewController.m
Normal file
File diff suppressed because it is too large
Load Diff
27
QXLive/HomePage(声播)/Model/QXBanner.h
Normal file
27
QXLive/HomePage(声播)/Model/QXBanner.h
Normal file
@@ -0,0 +1,27 @@
|
||||
//
|
||||
// QXBanner.h
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/6/11.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QXBanner : NSObject
|
||||
//ID
|
||||
@property (nonatomic,strong)NSString *bid;
|
||||
//跳转地址id
|
||||
@property (nonatomic,strong)NSString *aid;
|
||||
/// 1纯展示 2文章 3房间 4个人主页
|
||||
@property (nonatomic,strong)NSString *type;
|
||||
/// 1站内引导页 2启动引导页 3首页轮播
|
||||
@property (nonatomic,strong)NSString *show_type;
|
||||
//页面
|
||||
@property (nonatomic,strong)NSString *image;
|
||||
/// type = 2 的跳转地址
|
||||
@property (nonatomic,strong)NSString *url;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
12
QXLive/HomePage(声播)/Model/QXBanner.m
Normal file
12
QXLive/HomePage(声播)/Model/QXBanner.m
Normal file
@@ -0,0 +1,12 @@
|
||||
//
|
||||
// QXBanner.m
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/6/11.
|
||||
//
|
||||
|
||||
#import "QXBanner.h"
|
||||
|
||||
@implementation QXBanner
|
||||
|
||||
@end
|
||||
50
QXLive/HomePage(声播)/Model/QXRankModel.h
Normal file
50
QXLive/HomePage(声播)/Model/QXRankModel.h
Normal file
@@ -0,0 +1,50 @@
|
||||
//
|
||||
// QXRankModel.h
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/7/10.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
@class QXMyRankModel;
|
||||
@interface QXRankModel : NSObject
|
||||
/// 我的排行
|
||||
@property (nonatomic,strong)QXMyRankModel *my_ranking;
|
||||
@property (nonatomic,strong)NSArray<QXMyRankModel *>* lists;
|
||||
@end
|
||||
|
||||
@interface QXMyRankModel : NSObject
|
||||
@property (nonatomic,strong)NSString* avatar;
|
||||
@property (nonatomic,strong)NSString* nickname;
|
||||
@property (nonatomic,strong)NSString* user_id;
|
||||
@property (nonatomic,strong)NSString* user_code;
|
||||
@property (nonatomic,strong)NSString* sex;
|
||||
@property (nonatomic,strong)NSArray* icon;
|
||||
@property (nonatomic,strong)NSString* total;
|
||||
@property (nonatomic,strong)NSString* rank;
|
||||
@property (nonatomic,strong)NSString* diff;
|
||||
|
||||
/// 房间
|
||||
@property (nonatomic,strong)NSString* room_name;
|
||||
@property (nonatomic,strong)NSString* room_id;
|
||||
@property (nonatomic,strong)NSString* room_cover;
|
||||
@property (nonatomic,strong)NSString* room_number;
|
||||
|
||||
/// 公会
|
||||
@property (nonatomic,strong)NSString* cover;
|
||||
@property (nonatomic,strong)NSString* guild_name;
|
||||
@property (nonatomic,strong)NSString* guild_special_id;
|
||||
@property (nonatomic,strong)NSString* id;
|
||||
|
||||
/// cp
|
||||
@property (nonatomic,strong)NSString* user_id1;
|
||||
@property (nonatomic,strong)NSString* nickname1;
|
||||
|
||||
@property (nonatomic,strong)NSString* user_avatar;
|
||||
@property (nonatomic,strong)NSString* user_avatar1;
|
||||
@end
|
||||
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
24
QXLive/HomePage(声播)/Model/QXRankModel.m
Normal file
24
QXLive/HomePage(声播)/Model/QXRankModel.m
Normal file
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// QXRankModel.m
|
||||
// QXLive
|
||||
//
|
||||
// Created by 启星 on 2025/7/10.
|
||||
//
|
||||
|
||||
#import "QXRankModel.h"
|
||||
|
||||
@implementation QXRankModel
|
||||
+(NSDictionary<NSString *,id> *)modelContainerPropertyGenericClass{
|
||||
return @{
|
||||
@"my_ranking" : @"QXMyRankModel",
|
||||
@"lists": @"QXMyRankModel"
|
||||
};
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
@implementation QXMyRankModel
|
||||
|
||||
|
||||
|
||||
@end
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user