// // EPMomentListView.m // YuMi // // Created by AI on 2025-10-10. // #import #import "EPMomentListView.h" #import "EPMomentCell.h" #import #import "YuMi-Swift.h" #import "EPEmotionColorStorage.h" @interface EPMomentListView () @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; _isLocalMode = NO; // 明确初始化为网络模式 [self addSubview:self.tableView]; [self.tableView mas_makeConstraints:^(MASConstraintMaker *make) { make.edges.equalTo(self); }]; } return self; } - (NSArray *)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 *)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 * _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 { // 返回空数据:显示 "no more data" 状态 [self.tableView.mj_footer endRefreshingWithNoMoreData]; } } 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 *)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