initial commit

This commit is contained in:
Caleb
2026-03-01 15:59:27 +08:00
commit a9e97d56cb
1426 changed files with 172367 additions and 0 deletions

View File

@@ -0,0 +1,260 @@
//
// SCPlayerDebugView.m
// SellyCloudSDK_Example
//
// Created by Caleb on 07/1/26.
// Copyright © 2026 Caleb. All rights reserved.
//
#import "SCPlayerDebugView.h"
#import <Masonry/Masonry.h>
@interface SCPlayerDebugView ()
@property (nonatomic, strong) UIVisualEffectView *blurView;
@property (nonatomic, strong) UIView *headerView;
@property (nonatomic, strong) UIView *contentView;
@property (nonatomic, strong) UIScrollView *scrollView;
@property (nonatomic, strong) UILabel *titleLabel;
@property (nonatomic, strong) UILabel *logLabel;
@property (nonatomic, strong) UIButton *toggleButton;
@property (nonatomic, strong) UIButton *clearButton;
@property (nonatomic, strong) MASConstraint *contentViewHeightConstraint;
@property (nonatomic, strong) NSMutableArray<NSString *> *logs;
@property (nonatomic, strong) NSDateFormatter *dateFormatter;
@end
@implementation SCPlayerDebugView
- (instancetype)init {
self = [super init];
if (self) {
_isExpanded = YES; //
_logs = [NSMutableArray array];
//
_dateFormatter = [[NSDateFormatter alloc] init];
_dateFormatter.dateFormat = @"HH:mm:ss.SSS";
[self setupView];
}
return self;
}
- (void)setupView {
//
UIBlurEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleSystemUltraThinMaterialDark];
_blurView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
_blurView.layer.cornerRadius = 12;
_blurView.layer.masksToBounds = YES;
[self addSubview:_blurView];
[_blurView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self);
}];
//
self.layer.cornerRadius = 12;
self.layer.borderWidth = 0.5;
self.layer.borderColor = [[UIColor whiteColor] colorWithAlphaComponent:0.3].CGColor;
//
_headerView = [[UIView alloc] init];
[_blurView.contentView addSubview:_headerView];
[_headerView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.left.right.equalTo(_blurView.contentView);
make.height.offset(44);
}];
//
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(toggleButtonTapped)];
[_headerView addGestureRecognizer:tap];
//
_titleLabel = [[UILabel alloc] init];
_titleLabel.text = @"🐛 调试日志";
_titleLabel.font = [UIFont systemFontOfSize:14 weight:UIFontWeightSemibold];
_titleLabel.textColor = [UIColor whiteColor];
[_headerView addSubview:_titleLabel];
[_titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.equalTo(_headerView);
make.left.offset(12);
}];
//
_clearButton = [UIButton buttonWithType:UIButtonTypeSystem];
[_clearButton setImage:[UIImage systemImageNamed:@"trash.circle.fill"] forState:UIControlStateNormal];
_clearButton.tintColor = [[UIColor whiteColor] colorWithAlphaComponent:0.8];
[_clearButton addTarget:self action:@selector(clearButtonTapped) forControlEvents:UIControlEventTouchUpInside];
[_headerView addSubview:_clearButton];
[_clearButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.equalTo(_headerView);
make.right.offset(-44);
make.width.height.offset(24);
}];
// /
_toggleButton = [UIButton buttonWithType:UIButtonTypeSystem];
//
[_toggleButton setImage:[UIImage systemImageNamed:@"chevron.up.circle.fill"] forState:UIControlStateNormal];
_toggleButton.tintColor = [[UIColor whiteColor] colorWithAlphaComponent:0.8];
[_toggleButton addTarget:self action:@selector(toggleButtonTapped) forControlEvents:UIControlEventTouchUpInside];
[_headerView addSubview:_toggleButton];
[_toggleButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.equalTo(_headerView);
make.right.offset(-12);
make.width.height.offset(24);
}];
// 线
UIView *separatorLine = [[UIView alloc] init];
separatorLine.backgroundColor = [[UIColor whiteColor] colorWithAlphaComponent:0.2];
[_blurView.contentView addSubview:separatorLine];
[separatorLine mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(_headerView.mas_bottom);
make.left.offset(12);
make.right.offset(-12);
make.height.offset(0.5);
}];
//
_contentView = [[UIView alloc] init];
_contentView.clipsToBounds = YES;
[_blurView.contentView addSubview:_contentView];
[_contentView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(separatorLine.mas_bottom);
make.left.right.bottom.equalTo(_blurView.contentView);
//
self.contentViewHeightConstraint = make.height.offset(200); //
}];
// ScrollView
_scrollView = [[UIScrollView alloc] init];
_scrollView.showsVerticalScrollIndicator = YES;
_scrollView.showsHorizontalScrollIndicator = NO;
_scrollView.alwaysBounceVertical = YES;
[_contentView addSubview:_scrollView];
[_scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(_contentView).insets(UIEdgeInsetsMake(8, 12, 8, 12));
}];
//
_logLabel = [[UILabel alloc] init];
_logLabel.font = [UIFont monospacedSystemFontOfSize:10 weight:UIFontWeightRegular];
_logLabel.textColor = [UIColor whiteColor];
_logLabel.numberOfLines = 0; //
_logLabel.lineBreakMode = NSLineBreakByCharWrapping;
_logLabel.text = @""; //
[_scrollView addSubview:_logLabel];
[_logLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(_scrollView);
make.width.equalTo(_scrollView); //
}];
}
- (void)toggleButtonTapped {
//
[self setIsExpanded:!self.isExpanded];
}
- (void)clearButtonTapped {
[self clearLogs];
//
UIImpactFeedbackGenerator *feedback = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleMedium];
[feedback impactOccurred];
}
#pragma mark - Public Methods
- (void)appendLog:(NSString *)message {
[self appendLog:message withPrefix:nil];
}
- (void)appendLog:(NSString *)message withPrefix:(nullable NSString *)prefix {
if (!message || message.length == 0) {
return;
}
//
NSString *timestamp = [self.dateFormatter stringFromDate:[NSDate date]];
//
NSString *logEntry;
// if (prefix && prefix.length > 0) {
// logEntry = [NSString stringWithFormat:@"[%@] %@ %@", timestamp, prefix, message];
// } else {
logEntry = [NSString stringWithFormat:@"[%@] %@", timestamp, message];
// }
//
[self.logs addObject:logEntry];
// 200
if (self.logs.count > 200) {
[self.logs removeObjectAtIndex:0];
}
// UI
[self updateLogDisplay];
}
- (void)clearLogs {
[self.logs removeAllObjects];
[self updateLogDisplay];
}
#pragma mark - Private Methods
- (void)updateLogDisplay {
//
NSString *allLogs = [self.logs componentsJoinedByString:@"\n"];
self.logLabel.text = allLogs;
//
[self.logLabel mas_updateConstraints:^(MASConstraintMaker *make) {
//
}];
[self.logLabel layoutIfNeeded];
//
dispatch_async(dispatch_get_main_queue(), ^{
CGFloat bottomOffset = MAX(0, self.scrollView.contentSize.height - self.scrollView.bounds.size.height);
[self.scrollView setContentOffset:CGPointMake(0, bottomOffset) animated:YES];
});
}
- (void)setIsExpanded:(BOOL)isExpanded {
if (_isExpanded == isExpanded) {
return; //
}
_isExpanded = isExpanded;
// UI
CGFloat expandedHeight = 200; //
CGFloat collapsedHeight = 0; //
[UIView animateWithDuration:0.3 delay:0 usingSpringWithDamping:0.8 initialSpringVelocity:0.5 options:UIViewAnimationOptionCurveEaseInOut animations:^{
if (self.isExpanded) {
//
[self.toggleButton setImage:[UIImage systemImageNamed:@"chevron.up.circle.fill"] forState:UIControlStateNormal];
[self.contentViewHeightConstraint setOffset:expandedHeight];
} else {
//
[self.toggleButton setImage:[UIImage systemImageNamed:@"chevron.down.circle.fill"] forState:UIControlStateNormal];
[self.contentViewHeightConstraint setOffset:collapsedHeight];
}
// / alpha
self.contentView.alpha = self.isExpanded ? 1.0 : 0.0;
//
[self.superview layoutIfNeeded];
} completion:nil];
//
UIImpactFeedbackGenerator *feedback = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleLight];
[feedback impactOccurred];
}
@end