Files
real-e-party-iOS/YuMi/E-P/NewMoments/Views/EPMomentListView.m
edwinQQQ 90360448a1 fix: 统一应用名称为 "E-Party" 并更新相关描述
主要变更:
1. 在 Info.plist 中将应用名称和描述中的 "E-Parti" 替换为 "E-Party"。
2. 更新多个本地化字符串和提示信息,确保一致性。
3. 修改部分代码中的错误提示信息,使用本地化字符串替代硬编码文本。

此更新旨在提升品牌一致性,确保用户在使用过程中获得统一的体验。
2025-10-15 19:11:01 +08:00

257 lines
9.4 KiB
Objective-C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// EPMomentListView.m
// YuMi
//
// Created by AI on 2025-10-10.
//
#import <UIKit/UIKit.h>
#import "EPMomentListView.h"
#import "EPMomentCell.h"
#import <MJRefresh/MJRefresh.h>
#import "YuMi-Swift.h"
#import "EPEmotionColorStorage.h"
@interface EPMomentListView () <UITableViewDelegate, UITableViewDataSource>
@property (nonatomic, strong) UITableView *tableView;
@property (nonatomic, strong) UIRefreshControl *refreshControl;
@property (nonatomic, strong) NSMutableArray *mutableRawList;
@property (nonatomic, strong) EPMomentAPISwiftHelper *api;
@property (nonatomic, assign) BOOL isLoading;
@property (nonatomic, copy) NSString *nextID;
@property (nonatomic, assign) BOOL isLocalMode;
@property (nonatomic, copy) void (^refreshCallback)(void);
@end
@implementation EPMomentListView
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = [UIColor clearColor];
_api = [[EPMomentAPISwiftHelper alloc] init];
_mutableRawList = [NSMutableArray array];
_sourceType = EPMomentListSourceTypeRecommend;
[self addSubview:self.tableView];
[self.tableView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self);
}];
}
return self;
}
- (NSArray<NSMutableDictionary *> *)rawList {
return [self.mutableRawList copy];
}
- (void)reloadFirstPage {
if (self.isLocalMode) {
// 本地模式:调用外部刷新回调
if (self.refreshCallback) {
self.refreshCallback();
}
[self.refreshControl endRefreshing];
return;
}
// 网络模式:重新请求第一页
self.nextID = @"";
[self.mutableRawList removeAllObjects];
[self.tableView reloadData];
[self.tableView.mj_footer resetNoMoreData];
[self requestNextPage];
}
- (void)loadWithDynamicInfo:(NSArray<MomentsInfoModel *> *)dynamicInfo
refreshCallback:(void (^)(void))refreshCallback {
self.isLocalMode = YES;
self.refreshCallback = refreshCallback;
[self.mutableRawList removeAllObjects];
if (dynamicInfo.count > 0) {
[self.mutableRawList addObjectsFromArray:dynamicInfo];
}
// 隐藏加载更多 footer
self.tableView.mj_footer.hidden = YES;
[self.tableView reloadData];
[self.refreshControl endRefreshing];
}
- (void)requestNextPage {
if (self.isLoading) return;
self.isLoading = YES;
@kWeakify(self);
[self.api fetchLatestMomentsWithNextID:self.nextID
completion:^(NSArray<MomentsInfoModel *> * _Nonnull list, NSString * _Nonnull nextMomentID) {
@kStrongify(self);
[self endLoading];
if (list.count > 0) {
// 处理情绪颜色
[self processEmotionColors:list isFirstPage:(self.nextID.length == 0)];
self.nextID = nextMomentID;
[self.mutableRawList addObjectsFromArray:list];
[self.tableView reloadData];
if (nextMomentID.length > 0) {
[self.tableView.mj_footer endRefreshing];
} else {
[self.tableView.mj_footer endRefreshingWithNoMoreData];
}
} else {
// TODO: 后续补充空数据页面
if (self.nextID.length == 0) {
[self.tableView.mj_footer endRefreshingWithNoMoreData];
} else {
[self.tableView.mj_footer endRefreshing];
}
}
} failure:^(NSInteger code, NSString * _Nonnull msg) {
@kStrongify(self);
[self endLoading];
// TODO: 完全没有数据情况下,后续补充数据异常页面
[self.tableView.mj_footer endRefreshing];
}];
}
- (void)endLoading {
self.isLoading = NO;
[self.refreshControl endRefreshing];
}
/// 处理动态的情绪颜色(从 UserDefaults 匹配 + 处理临时颜色)
- (void)processEmotionColors:(NSArray<MomentsInfoModel *> *)list isFirstPage:(BOOL)isFirstPage {
// 检查是否有待处理的临时情绪颜色
NSString *pendingColor = [[NSUserDefaults standardUserDefaults] stringForKey:@"EP_Pending_Emotion_Color"];
NSNumber *pendingTimestamp = [[NSUserDefaults standardUserDefaults] objectForKey:@"EP_Pending_Emotion_Timestamp"];
for (NSInteger i = 0; i < list.count; i++) {
MomentsInfoModel *model = list[i];
// 优先检查临时颜色(仅第一页第一条)
if (isFirstPage && i == 0 && pendingColor && pendingTimestamp) {
// 检查时间戳5秒内有效避免误匹配
NSTimeInterval now = [[NSDate date] timeIntervalSince1970];
NSTimeInterval pending = pendingTimestamp.doubleValue;
if ((now - pending) < 5.0) {
model.emotionColor = pendingColor;
// 保存到持久化存储
[EPEmotionColorStorage saveColor:pendingColor forDynamicId:model.dynamicId];
// 清除临时数据
[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"EP_Pending_Emotion_Color"];
[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"EP_Pending_Emotion_Timestamp"];
[[NSUserDefaults standardUserDefaults] synchronize];
continue;
}
}
// 从持久化存储中匹配
NSString *savedColor = [EPEmotionColorStorage colorForDynamicId:model.dynamicId];
if (savedColor) {
model.emotionColor = savedColor;
} else {
// 无保存颜色,生成随机颜色并立即持久化
NSString *randomColor = [EPEmotionColorStorage randomEmotionColor];
model.emotionColor = randomColor;
[EPEmotionColorStorage saveColor:randomColor forDynamicId:model.dynamicId];
NSLog(@"[EPMomentListView] 为动态 %@ 分配随机颜色: %@", model.dynamicId, randomColor);
}
}
}
#pragma mark - UITableView
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.mutableRawList.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
EPMomentCell *cell = [tableView dequeueReusableCellWithIdentifier:@"NewMomentCell" forIndexPath:indexPath];
if (indexPath.row < self.mutableRawList.count) {
MomentsInfoModel *model = [self.mutableRawList xpSafeObjectAtIndex:indexPath.row];
[cell configureWithModel:model];
}
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return UITableViewAutomaticDimension;
}
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 200;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
if (self.onSelectMoment) self.onSelectMoment(indexPath.row);
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
// 本地模式下不触发加载更多
if (self.isLocalMode) return;
CGFloat offsetY = scrollView.contentOffset.y;
CGFloat contentHeight = scrollView.contentSize.height;
CGFloat screenHeight = scrollView.frame.size.height;
if (offsetY > contentHeight - screenHeight - 100 && !self.isLoading) {
[self requestNextPage];
}
}
#pragma mark - Lazy
- (UITableView *)tableView {
if (!_tableView) {
_tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
_tableView.delegate = self;
_tableView.dataSource = self;
_tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
_tableView.backgroundColor = [UIColor clearColor];
_tableView.estimatedRowHeight = 200;
_tableView.rowHeight = UITableViewAutomaticDimension;
_tableView.showsVerticalScrollIndicator = NO;
// 底部留出更高空间,避免被悬浮 TabBar 遮挡
_tableView.contentInset = UIEdgeInsetsMake(10, 0, 120, 0);
_tableView.scrollIndicatorInsets = UIEdgeInsetsMake(10, 0, 120, 0);
[_tableView registerClass:[EPMomentCell class] forCellReuseIdentifier:@"NewMomentCell"];
_tableView.refreshControl = self.refreshControl;
// MJRefresh Footer - 加载更多
__weak typeof(self) weakSelf = self;
MJRefreshAutoNormalFooter *footer = [MJRefreshAutoNormalFooter footerWithRefreshingBlock:^{
__strong typeof(weakSelf) self = weakSelf;
if (!self.isLoading && self.nextID.length > 0) {
[self requestNextPage];
} else if (self.nextID.length == 0) {
[self.tableView.mj_footer endRefreshingWithNoMoreData];
} else {
[self.tableView.mj_footer endRefreshing];
}
}];
// 设置白色文字和指示器
footer.stateLabel.textColor = [UIColor whiteColor];
footer.loadingView.color = [UIColor whiteColor];
_tableView.mj_footer = footer;
}
return _tableView;
}
- (UIRefreshControl *)refreshControl {
if (!_refreshControl) {
_refreshControl = [[UIRefreshControl alloc] init];
_refreshControl.tintColor = [UIColor whiteColor]; // 白色加载指示器
[_refreshControl addTarget:self action:@selector(reloadFirstPage) forControlEvents:UIControlEventValueChanged];
}
return _refreshControl;
}
@end