feat: 添加情绪颜色选择功能及相关存储管理
主要变更: 1. 在 EPMomentPublishViewController 中添加情绪颜色选择按钮,用户可通过色轮选择情绪颜色。 2. 新增 EPEmotionColorStorage 类,提供情绪颜色的保存、获取和删除功能,支持动态 ID 的关联。 3. 新增 EPEmotionColorPicker 视图,提供环形布局的颜色选择器,增强用户体验。 4. 更新 EPMomentCell 和 EPMomentListView,以支持情绪颜色的显示和处理,确保动态展示的情绪效果。 此更新旨在提升用户交互体验,丰富动态发布功能,确保情绪颜色的有效管理和展示。
This commit is contained in:
@@ -768,6 +768,8 @@
|
||||
4CD47BCC2E61ADE400BCDA46 /* XPSocialAction.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CD47BCB2E61ADE400BCDA46 /* XPSocialAction.m */; };
|
||||
4CD6FF662D673A5C00262AB7 /* AgentMessageModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CD6FF652D673A5C00262AB7 /* AgentMessageModel.m */; };
|
||||
4CD6FF692D673F7F00262AB7 /* AgentMessageTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CD6FF682D673F7F00262AB7 /* AgentMessageTableViewCell.m */; };
|
||||
4CDF7F3F2E9E580E00113F54 /* EPEmotionColorStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CDF7F3E2E9E580E00113F54 /* EPEmotionColorStorage.m */; };
|
||||
4CDF7F422E9E581900113F54 /* EPEmotionColorPicker.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CDF7F412E9E581900113F54 /* EPEmotionColorPicker.m */; };
|
||||
4CE3A9462D22754C003F0796 /* RechargeUserModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CE3A9452D22754C003F0796 /* RechargeUserModel.m */; };
|
||||
4CE746C32D9290430094E496 /* RoomBoomManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CE746C22D9290430094E496 /* RoomBoomManager.m */; };
|
||||
4CE746C62D9297C30094E496 /* BravoGiftTipModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CE746C52D9297C30094E496 /* BravoGiftTipModel.m */; };
|
||||
@@ -2991,6 +2993,10 @@
|
||||
4CD6FF652D673A5C00262AB7 /* AgentMessageModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AgentMessageModel.m; sourceTree = "<group>"; };
|
||||
4CD6FF672D673F7F00262AB7 /* AgentMessageTableViewCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AgentMessageTableViewCell.h; sourceTree = "<group>"; };
|
||||
4CD6FF682D673F7F00262AB7 /* AgentMessageTableViewCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AgentMessageTableViewCell.m; sourceTree = "<group>"; };
|
||||
4CDF7F3D2E9E580E00113F54 /* EPEmotionColorStorage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EPEmotionColorStorage.h; sourceTree = "<group>"; };
|
||||
4CDF7F3E2E9E580E00113F54 /* EPEmotionColorStorage.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = EPEmotionColorStorage.m; sourceTree = "<group>"; };
|
||||
4CDF7F402E9E581900113F54 /* EPEmotionColorPicker.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EPEmotionColorPicker.h; sourceTree = "<group>"; };
|
||||
4CDF7F412E9E581900113F54 /* EPEmotionColorPicker.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = EPEmotionColorPicker.m; sourceTree = "<group>"; };
|
||||
4CE3A9442D22754C003F0796 /* RechargeUserModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RechargeUserModel.h; sourceTree = "<group>"; };
|
||||
4CE3A9452D22754C003F0796 /* RechargeUserModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RechargeUserModel.m; sourceTree = "<group>"; };
|
||||
4CE746C12D9290430094E496 /* RoomBoomManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RoomBoomManager.h; sourceTree = "<group>"; };
|
||||
@@ -6415,6 +6421,8 @@
|
||||
4C06427B2E97BD6D00BAF413 /* Views */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4CDF7F402E9E581900113F54 /* EPEmotionColorPicker.h */,
|
||||
4CDF7F412E9E581900113F54 /* EPEmotionColorPicker.m */,
|
||||
4C0642972E98F77900BAF413 /* EPMomentListView.h */,
|
||||
4C0642982E98F77900BAF413 /* EPMomentListView.m */,
|
||||
4C0642792E97BD6D00BAF413 /* EPMomentCell.h */,
|
||||
@@ -6456,6 +6464,8 @@
|
||||
4C0642952E98F76F00BAF413 /* Services */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4CDF7F3D2E9E580E00113F54 /* EPEmotionColorStorage.h */,
|
||||
4CDF7F3E2E9E580E00113F54 /* EPEmotionColorStorage.m */,
|
||||
4C1E98C52E9A45BC0031AE79 /* EPMomentAPISwiftHelper.swift */,
|
||||
);
|
||||
path = Services;
|
||||
@@ -12967,6 +12977,7 @@
|
||||
5456F3C82C6EF962000E1805 /* VIPCenterViewController.m in Sources */,
|
||||
E8EEB90926FC579A007C6EBA /* XPMineUserInfoEditTableViewCell.m in Sources */,
|
||||
E8F1559028125E2D00EE8C06 /* MessageAudioCenter.m in Sources */,
|
||||
4CDF7F3F2E9E580E00113F54 /* EPEmotionColorStorage.m in Sources */,
|
||||
E8901CF628B38D89001E9A92 /* XPGraffitiGiftView.m in Sources */,
|
||||
E89DA67527009ACD008483C1 /* XPMineRechargeNavView.m in Sources */,
|
||||
E81A6546283519CA00F55894 /* MomentsTopicModel.m in Sources */,
|
||||
@@ -13201,6 +13212,7 @@
|
||||
189DD75026E21D9000AB55B1 /* GCDHelper.m in Sources */,
|
||||
E82D5C76276AEB5100858D6D /* NameplateModel.m in Sources */,
|
||||
142721AF29A75F6F00C7C423 /* SJXCSMIPHelper.m in Sources */,
|
||||
4CDF7F422E9E581900113F54 /* EPEmotionColorPicker.m in Sources */,
|
||||
E87E62742A3F5907002F68C9 /* XPHomeBannerTableViewCell.m in Sources */,
|
||||
E88C72A3282917590047FB2B /* XPRoomMusicVoiceSettingView.m in Sources */,
|
||||
239D0FA82BFCB88D002977CE /* XPRoomBackContainerView.m in Sources */,
|
||||
|
@@ -16,6 +16,8 @@
|
||||
#import "DJDKMIMOMColor.h"
|
||||
#import "SZTextView.h"
|
||||
#import "YuMi-Swift.h"
|
||||
#import "EPEmotionColorPicker.h"
|
||||
#import "EPEmotionColorStorage.h"
|
||||
|
||||
// 发布成功通知
|
||||
NSString *const EPMomentPublishSuccessNotification = @"EPMomentPublishSuccessNotification";
|
||||
@@ -31,9 +33,11 @@ NSString *const EPMomentPublishSuccessNotification = @"EPMomentPublishSuccessNot
|
||||
@property (nonatomic, strong) SZTextView *textView;
|
||||
@property (nonatomic, strong) UILabel *limitLabel;
|
||||
@property (nonatomic, strong) UIView *lineView;
|
||||
@property (nonatomic, strong) UIButton *emotionButton;
|
||||
@property (nonatomic, strong) UICollectionView *collectionView;
|
||||
@property (nonatomic, strong) NSMutableArray<UIImage *> *images;
|
||||
@property (nonatomic, strong) NSMutableArray *selectedAssets; // TZImagePicker 已选资源
|
||||
@property (nonatomic, copy) NSString *selectedEmotionColor; // 选中的情绪颜色
|
||||
|
||||
@end
|
||||
|
||||
@@ -54,6 +58,7 @@ NSString *const EPMomentPublishSuccessNotification = @"EPMomentPublishSuccessNot
|
||||
[self.contentView addSubview:self.textView];
|
||||
[self.contentView addSubview:self.limitLabel];
|
||||
[self.contentView addSubview:self.lineView];
|
||||
[self.contentView addSubview:self.emotionButton];
|
||||
[self.contentView addSubview:self.collectionView];
|
||||
[self.contentView addSubview:self.publishButton];
|
||||
|
||||
@@ -90,6 +95,14 @@ NSString *const EPMomentPublishSuccessNotification = @"EPMomentPublishSuccessNot
|
||||
make.leading.trailing.equalTo(self.textView);
|
||||
make.height.mas_equalTo(1);
|
||||
}];
|
||||
|
||||
// 情绪按钮
|
||||
[self.emotionButton mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.leading.trailing.equalTo(self.contentView).inset(15);
|
||||
make.top.equalTo(self.lineView.mas_bottom).offset(10);
|
||||
make.height.mas_equalTo(44);
|
||||
}];
|
||||
|
||||
// 计算显示3行图片所需的高度
|
||||
// itemW = (屏幕宽度 - 左右边距30 - 列间距20) / 3
|
||||
// 总高度 = 3行itemW + 2个行间距(10*2)
|
||||
@@ -98,7 +111,7 @@ NSString *const EPMomentPublishSuccessNotification = @"EPMomentPublishSuccessNot
|
||||
|
||||
[self.collectionView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.leading.trailing.equalTo(self.contentView).inset(15);
|
||||
make.top.equalTo(self.lineView.mas_bottom).offset(10);
|
||||
make.top.equalTo(self.emotionButton.mas_bottom).offset(10);
|
||||
make.height.mas_equalTo(collectionHeight);
|
||||
}];
|
||||
|
||||
@@ -116,6 +129,55 @@ NSString *const EPMomentPublishSuccessNotification = @"EPMomentPublishSuccessNot
|
||||
[self dismissViewControllerAnimated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (void)onEmotionButtonTapped {
|
||||
EPEmotionColorPicker *picker = [[EPEmotionColorPicker alloc] init];
|
||||
__weak typeof(self) weakSelf = self;
|
||||
picker.onColorSelected = ^(NSString *hexColor) {
|
||||
__strong typeof(weakSelf) self = weakSelf;
|
||||
self.selectedEmotionColor = hexColor;
|
||||
[self updateEmotionButtonAppearance];
|
||||
};
|
||||
[picker showInView:self.view];
|
||||
}
|
||||
|
||||
- (void)updateEmotionButtonAppearance {
|
||||
if (self.selectedEmotionColor) {
|
||||
// 显示选中的颜色
|
||||
UIColor *color = [self colorFromHex:self.selectedEmotionColor];
|
||||
|
||||
// 创建色块视图
|
||||
UIView *colorDot = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 20, 20)];
|
||||
colorDot.backgroundColor = color;
|
||||
colorDot.layer.cornerRadius = 10;
|
||||
colorDot.layer.masksToBounds = YES;
|
||||
colorDot.layer.borderWidth = 2;
|
||||
colorDot.layer.borderColor = [UIColor whiteColor].CGColor;
|
||||
|
||||
// 转换为 UIImage
|
||||
UIGraphicsBeginImageContextWithOptions(colorDot.bounds.size, NO, 0);
|
||||
[colorDot.layer renderInContext:UIGraphicsGetCurrentContext()];
|
||||
UIImage *colorDotImage = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
|
||||
[self.emotionButton setImage:colorDotImage forState:UIControlStateNormal];
|
||||
[self.emotionButton setTitle:@" Emotion Selected" forState:UIControlStateNormal];
|
||||
} else {
|
||||
[self.emotionButton setImage:nil forState:UIControlStateNormal];
|
||||
[self.emotionButton setTitle:@"🎨 Add Emotion" forState:UIControlStateNormal];
|
||||
}
|
||||
}
|
||||
|
||||
- (UIColor *)colorFromHex:(NSString *)hexString {
|
||||
unsigned rgbValue = 0;
|
||||
NSScanner *scanner = [NSScanner scannerWithString:hexString];
|
||||
[scanner setScanLocation:1]; // 跳过 #
|
||||
[scanner scanHexInt:&rgbValue];
|
||||
return [UIColor colorWithRed:((rgbValue & 0xFF0000) >> 16)/255.0
|
||||
green:((rgbValue & 0xFF00) >> 8)/255.0
|
||||
blue:(rgbValue & 0xFF)/255.0
|
||||
alpha:1.0];
|
||||
}
|
||||
|
||||
- (void)onPublish {
|
||||
[self.view endEditing:YES];
|
||||
|
||||
@@ -129,6 +191,9 @@ NSString *const EPMomentPublishSuccessNotification = @"EPMomentPublishSuccessNot
|
||||
// 创建 Swift API Helper
|
||||
EPMomentAPISwiftHelper *apiHelper = [[EPMomentAPISwiftHelper alloc] init];
|
||||
|
||||
// 保存情绪颜色用于发布后关联
|
||||
NSString *emotionColorToSave = self.selectedEmotionColor;
|
||||
|
||||
if (self.images.count > 0) {
|
||||
// 有图片:上传后发布(统一入口)
|
||||
[[EPSDKManager shared] uploadImages:self.images
|
||||
@@ -141,6 +206,10 @@ NSString *const EPMomentPublishSuccessNotification = @"EPMomentPublishSuccessNot
|
||||
content:self.textView.text ?: @""
|
||||
resList:resList
|
||||
completion:^{
|
||||
// 保存临时情绪颜色(等待列表刷新后匹配)
|
||||
if (emotionColorToSave) {
|
||||
[self savePendingEmotionColor:emotionColorToSave];
|
||||
}
|
||||
// 发送发布成功通知
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:EPMomentPublishSuccessNotification object:nil];
|
||||
[self dismissViewControllerAnimated:YES completion:nil];
|
||||
@@ -160,6 +229,10 @@ NSString *const EPMomentPublishSuccessNotification = @"EPMomentPublishSuccessNot
|
||||
content:self.textView.text
|
||||
resList:@[]
|
||||
completion:^{
|
||||
// 保存临时情绪颜色(等待列表刷新后匹配)
|
||||
if (emotionColorToSave) {
|
||||
[self savePendingEmotionColor:emotionColorToSave];
|
||||
}
|
||||
// 发送发布成功通知
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:EPMomentPublishSuccessNotification object:nil];
|
||||
[self dismissViewControllerAnimated:YES completion:nil];
|
||||
@@ -170,6 +243,13 @@ NSString *const EPMomentPublishSuccessNotification = @"EPMomentPublishSuccessNot
|
||||
}
|
||||
}
|
||||
|
||||
/// 保存待处理的情绪颜色(临时存储,供列表刷新后匹配)
|
||||
- (void)savePendingEmotionColor:(NSString *)color {
|
||||
[[NSUserDefaults standardUserDefaults] setObject:color forKey:@"EP_Pending_Emotion_Color"];
|
||||
[[NSUserDefaults standardUserDefaults] setObject:@([[NSDate date] timeIntervalSince1970]) forKey:@"EP_Pending_Emotion_Timestamp"];
|
||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||
}
|
||||
|
||||
#pragma mark - UICollectionView
|
||||
|
||||
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
|
||||
@@ -261,6 +341,21 @@ NSString *const EPMomentPublishSuccessNotification = @"EPMomentPublishSuccessNot
|
||||
- (SZTextView *)textView { if (!_textView) { _textView = [SZTextView new]; _textView.placeholder = @"Enter Content"; _textView.textColor = [DJDKMIMOMColor mainTextColor]; _textView.placeholderTextColor = [DJDKMIMOMColor secondTextColor]; _textView.font = [UIFont systemFontOfSize:15]; _textView.delegate = self; } return _textView; }
|
||||
- (UILabel *)limitLabel { if (!_limitLabel) { _limitLabel = [UILabel new]; _limitLabel.text = @"0/500"; _limitLabel.textColor = [DJDKMIMOMColor mainTextColor]; _limitLabel.font = [UIFont systemFontOfSize:12]; } return _limitLabel; }
|
||||
- (UIView *)lineView { if (!_lineView) { _lineView = [UIView new]; _lineView.backgroundColor = [DJDKMIMOMColor dividerColor]; } return _lineView; }
|
||||
- (UIButton *)emotionButton {
|
||||
if (!_emotionButton) {
|
||||
_emotionButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
[_emotionButton setTitle:@"🎨 Add Emotion" forState:UIControlStateNormal];
|
||||
[_emotionButton setTitleColor:[DJDKMIMOMColor mainTextColor] forState:UIControlStateNormal];
|
||||
_emotionButton.titleLabel.font = [UIFont systemFontOfSize:15];
|
||||
_emotionButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
|
||||
_emotionButton.contentEdgeInsets = UIEdgeInsetsMake(0, 15, 0, 0);
|
||||
_emotionButton.backgroundColor = [[UIColor whiteColor] colorWithAlphaComponent:0.06];
|
||||
_emotionButton.layer.cornerRadius = 8;
|
||||
_emotionButton.layer.masksToBounds = YES;
|
||||
[_emotionButton addTarget:self action:@selector(onEmotionButtonTapped) forControlEvents:UIControlEventTouchUpInside];
|
||||
}
|
||||
return _emotionButton;
|
||||
}
|
||||
- (UICollectionView *)collectionView { if (!_collectionView) { UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; layout.minimumLineSpacing = 10; layout.minimumInteritemSpacing = 10; CGFloat itemW = (KScreenWidth - 15*2 - 10*2)/3.0; layout.itemSize = CGSizeMake(itemW, itemW); _collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout]; _collectionView.delegate = self; _collectionView.dataSource = self; _collectionView.backgroundColor = [UIColor clearColor]; [_collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"ep.publish.cell"]; } return _collectionView; }
|
||||
- (NSMutableArray<UIImage *> *)images { if (!_images) { _images = [NSMutableArray array]; } return _images; }
|
||||
- (NSMutableArray *)selectedAssets { if (!_selectedAssets) { _selectedAssets = [NSMutableArray array]; } return _selectedAssets; }
|
||||
|
39
YuMi/E-P/NewMoments/Services/EPEmotionColorStorage.h
Normal file
39
YuMi/E-P/NewMoments/Services/EPEmotionColorStorage.h
Normal file
@@ -0,0 +1,39 @@
|
||||
//
|
||||
// EPEmotionColorStorage.h
|
||||
// YuMi
|
||||
//
|
||||
// Created by AI on 2025-10-14.
|
||||
// 本地情绪颜色存储管理器(基于 UserDefaults)
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface EPEmotionColorStorage : NSObject
|
||||
|
||||
/// 保存动态的情绪颜色
|
||||
/// @param hexColor Hex 格式颜色值,如 #FF0000
|
||||
/// @param dynamicId 动态 ID
|
||||
+ (void)saveColor:(NSString *)hexColor forDynamicId:(NSString *)dynamicId;
|
||||
|
||||
/// 获取动态关联的情绪颜色
|
||||
/// @param dynamicId 动态 ID
|
||||
/// @return Hex 格式颜色值,若未设置则返回 nil
|
||||
+ (nullable NSString *)colorForDynamicId:(NSString *)dynamicId;
|
||||
|
||||
/// 删除动态的情绪颜色
|
||||
/// @param dynamicId 动态 ID
|
||||
+ (void)removeColorForDynamicId:(NSString *)dynamicId;
|
||||
|
||||
/// 获取所有预设情绪颜色(6种基础情绪)
|
||||
/// @return Hex 颜色数组
|
||||
+ (NSArray<NSString *> *)allEmotionColors;
|
||||
|
||||
/// 获取随机情绪颜色(不持久化)
|
||||
+ (NSString *)randomEmotionColor;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
70
YuMi/E-P/NewMoments/Services/EPEmotionColorStorage.m
Normal file
70
YuMi/E-P/NewMoments/Services/EPEmotionColorStorage.m
Normal file
@@ -0,0 +1,70 @@
|
||||
//
|
||||
// EPEmotionColorStorage.m
|
||||
// YuMi
|
||||
//
|
||||
// Created by AI on 2025-10-14.
|
||||
//
|
||||
|
||||
#import "EPEmotionColorStorage.h"
|
||||
|
||||
static NSString *const kEmotionColorStorageKey = @"EP_Emotion_Colors";
|
||||
|
||||
@implementation EPEmotionColorStorage
|
||||
|
||||
#pragma mark - Public Methods
|
||||
|
||||
+ (void)saveColor:(NSString *)hexColor forDynamicId:(NSString *)dynamicId {
|
||||
if (!hexColor || !dynamicId) return;
|
||||
|
||||
NSMutableDictionary *colorDict = [[self loadColorDictionary] mutableCopy];
|
||||
colorDict[dynamicId] = hexColor;
|
||||
|
||||
[[NSUserDefaults standardUserDefaults] setObject:colorDict forKey:kEmotionColorStorageKey];
|
||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||
}
|
||||
|
||||
+ (NSString *)colorForDynamicId:(NSString *)dynamicId {
|
||||
if (!dynamicId) return nil;
|
||||
|
||||
NSDictionary *colorDict = [self loadColorDictionary];
|
||||
return colorDict[dynamicId];
|
||||
}
|
||||
|
||||
+ (void)removeColorForDynamicId:(NSString *)dynamicId {
|
||||
if (!dynamicId) return;
|
||||
|
||||
NSMutableDictionary *colorDict = [[self loadColorDictionary] mutableCopy];
|
||||
[colorDict removeObjectForKey:dynamicId];
|
||||
|
||||
[[NSUserDefaults standardUserDefaults] setObject:colorDict forKey:kEmotionColorStorageKey];
|
||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||
}
|
||||
|
||||
+ (NSArray<NSString *> *)allEmotionColors {
|
||||
return @[
|
||||
@"#FFD700", // 喜悦 Joy(金黄)- 降低亮度,更温暖
|
||||
@"#4A90E2", // 悲伤 Sadness(天蓝)- 提高亮度,更柔和
|
||||
@"#E74C3C", // 愤怒 Anger(珊瑚红)- 降低饱和度
|
||||
@"#9B59B6", // 恐惧 Fear(紫罗兰)- 稍微提亮
|
||||
@"#FF9A3D", // 惊讶 Surprise(柔和橙)- 略微调暗
|
||||
@"#2ECC71", // 厌恶 Disgust(翡翠绿)- 大幅降低亮度
|
||||
@"#3498DB", // 信任 Trust(亮蓝)- 清新明亮
|
||||
@"#F39C12" // 期待 Anticipation(琥珀色)- 温暖期待
|
||||
];
|
||||
}
|
||||
|
||||
+ (NSString *)randomEmotionColor {
|
||||
NSArray *colors = [self allEmotionColors];
|
||||
uint32_t randomIndex = arc4random_uniform((uint32_t)colors.count);
|
||||
return colors[randomIndex];
|
||||
}
|
||||
|
||||
#pragma mark - Private Methods
|
||||
|
||||
+ (NSDictionary *)loadColorDictionary {
|
||||
NSDictionary *dict = [[NSUserDefaults standardUserDefaults] dictionaryForKey:kEmotionColorStorageKey];
|
||||
return dict ?: @{};
|
||||
}
|
||||
|
||||
@end
|
||||
|
28
YuMi/E-P/NewMoments/Views/EPEmotionColorPicker.h
Normal file
28
YuMi/E-P/NewMoments/Views/EPEmotionColorPicker.h
Normal file
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// EPEmotionColorPicker.h
|
||||
// YuMi
|
||||
//
|
||||
// Created by AI on 2025-10-14.
|
||||
// 情绪色轮选择器 - 环形布局
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface EPEmotionColorPicker : UIView
|
||||
|
||||
/// 颜色选择回调
|
||||
@property (nonatomic, copy) void(^onColorSelected)(NSString *hexColor);
|
||||
|
||||
/// 在指定视图中显示选择器
|
||||
/// @param parentView 父视图(通常是 ViewController 的 view)
|
||||
- (void)showInView:(UIView *)parentView;
|
||||
|
||||
/// 关闭选择器
|
||||
- (void)dismiss;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
236
YuMi/E-P/NewMoments/Views/EPEmotionColorPicker.m
Normal file
236
YuMi/E-P/NewMoments/Views/EPEmotionColorPicker.m
Normal file
@@ -0,0 +1,236 @@
|
||||
//
|
||||
// EPEmotionColorPicker.m
|
||||
// YuMi
|
||||
//
|
||||
// Created by AI on 2025-10-14.
|
||||
//
|
||||
|
||||
#import "EPEmotionColorPicker.h"
|
||||
#import "EPEmotionColorStorage.h"
|
||||
#import <Masonry/Masonry.h>
|
||||
|
||||
@interface EPEmotionColorPicker ()
|
||||
|
||||
@property (nonatomic, strong) UIView *backgroundMask;
|
||||
@property (nonatomic, strong) UIView *containerView;
|
||||
@property (nonatomic, strong) UILabel *titleLabel;
|
||||
@property (nonatomic, strong) UIView *colorWheelContainer;
|
||||
@property (nonatomic, strong) NSMutableArray<UIButton *> *colorButtons;
|
||||
|
||||
@end
|
||||
|
||||
@implementation EPEmotionColorPicker
|
||||
|
||||
#pragma mark - Lifecycle
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
if (self = [super initWithFrame:frame]) {
|
||||
[self setupUI];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setupUI {
|
||||
self.backgroundColor = [UIColor clearColor];
|
||||
|
||||
// 背景遮罩
|
||||
[self addSubview:self.backgroundMask];
|
||||
[self.backgroundMask mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.edges.equalTo(self);
|
||||
}];
|
||||
|
||||
// 底部卡片容器
|
||||
[self addSubview:self.containerView];
|
||||
[self.containerView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.leading.trailing.bottom.equalTo(self);
|
||||
make.height.mas_equalTo(320);
|
||||
}];
|
||||
|
||||
// 标题
|
||||
[self.containerView addSubview:self.titleLabel];
|
||||
[self.titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.equalTo(self.containerView).offset(20);
|
||||
make.centerX.equalTo(self.containerView);
|
||||
}];
|
||||
|
||||
// 色轮容器
|
||||
[self.containerView addSubview:self.colorWheelContainer];
|
||||
[self.colorWheelContainer mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.centerX.equalTo(self.containerView);
|
||||
make.top.equalTo(self.titleLabel.mas_bottom).offset(30);
|
||||
make.size.mas_equalTo(CGSizeMake(240, 240));
|
||||
}];
|
||||
|
||||
// 创建环形排列的颜色按钮
|
||||
[self createColorButtons];
|
||||
}
|
||||
|
||||
- (void)createColorButtons {
|
||||
NSArray<NSString *> *colors = [EPEmotionColorStorage allEmotionColors];
|
||||
NSArray<NSString *> *emotions = @[@"Joy", @"Sadness", @"Anger", @"Fear", @"Surprise", @"Disgust", @"Trust", @"Anticipation"];
|
||||
|
||||
CGFloat radius = 80.0; // 圆周半径
|
||||
CGFloat buttonSize = 50.0; // 按钮直径
|
||||
CGFloat angleStep = M_PI * 2.0 / colors.count;
|
||||
CGFloat centerX = 120.0; // 容器中心 X
|
||||
CGFloat centerY = 120.0; // 容器中心 Y
|
||||
|
||||
for (NSInteger i = 0; i < colors.count; i++) {
|
||||
// 从顶部开始,顺时针排列
|
||||
CGFloat angle = angleStep * i - M_PI_2;
|
||||
CGFloat x = centerX + radius * cos(angle) - buttonSize / 2.0;
|
||||
CGFloat y = centerY + radius * sin(angle) - buttonSize / 2.0;
|
||||
|
||||
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
button.frame = CGRectMake(x, y, buttonSize, buttonSize);
|
||||
button.backgroundColor = [self colorFromHex:colors[i]];
|
||||
button.layer.cornerRadius = buttonSize / 2.0;
|
||||
button.layer.masksToBounds = YES;
|
||||
button.layer.borderWidth = 3.0;
|
||||
button.layer.borderColor = [UIColor whiteColor].CGColor;
|
||||
button.tag = i;
|
||||
[button addTarget:self action:@selector(onColorButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
|
||||
|
||||
// 添加阴影效果
|
||||
button.layer.shadowColor = [self colorFromHex:colors[i]].CGColor;
|
||||
button.layer.shadowOffset = CGSizeMake(0, 2);
|
||||
button.layer.shadowOpacity = 0.6;
|
||||
button.layer.shadowRadius = 8;
|
||||
button.layer.masksToBounds = NO;
|
||||
|
||||
// 添加情绪标签(可选)
|
||||
UILabel *emotionLabel = [[UILabel alloc] init];
|
||||
emotionLabel.text = emotions[i];
|
||||
emotionLabel.textColor = [UIColor whiteColor];
|
||||
emotionLabel.font = [UIFont systemFontOfSize:10 weight:UIFontWeightMedium];
|
||||
emotionLabel.textAlignment = NSTextAlignmentCenter;
|
||||
emotionLabel.frame = CGRectMake(0, buttonSize - 2, buttonSize, 12);
|
||||
emotionLabel.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.5];
|
||||
emotionLabel.layer.cornerRadius = 6;
|
||||
emotionLabel.layer.masksToBounds = YES;
|
||||
[button addSubview:emotionLabel];
|
||||
|
||||
[self.colorWheelContainer addSubview:button];
|
||||
[self.colorButtons addObject:button];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Actions
|
||||
|
||||
- (void)onColorButtonTapped:(UIButton *)sender {
|
||||
NSInteger index = sender.tag;
|
||||
NSArray<NSString *> *colors = [EPEmotionColorStorage allEmotionColors];
|
||||
NSString *selectedColor = colors[index];
|
||||
|
||||
// 点击动画
|
||||
[UIView animateWithDuration:0.1 animations:^{
|
||||
sender.transform = CGAffineTransformMakeScale(0.9, 0.9);
|
||||
} completion:^(BOOL finished) {
|
||||
[UIView animateWithDuration:0.1 animations:^{
|
||||
sender.transform = CGAffineTransformIdentity;
|
||||
} completion:^(BOOL finished) {
|
||||
// 执行回调
|
||||
if (self.onColorSelected) {
|
||||
self.onColorSelected(selectedColor);
|
||||
}
|
||||
[self dismiss];
|
||||
}];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)onBackgroundTapped {
|
||||
[self dismiss];
|
||||
}
|
||||
|
||||
#pragma mark - Public Methods
|
||||
|
||||
- (void)showInView:(UIView *)parentView {
|
||||
[parentView addSubview:self];
|
||||
[self mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.edges.equalTo(parentView);
|
||||
}];
|
||||
|
||||
// 初始状态
|
||||
self.backgroundMask.alpha = 0;
|
||||
self.containerView.transform = CGAffineTransformMakeTranslation(0, 320);
|
||||
|
||||
// 弹出动画
|
||||
[UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
|
||||
self.backgroundMask.alpha = 1;
|
||||
self.containerView.transform = CGAffineTransformIdentity;
|
||||
} completion:nil];
|
||||
}
|
||||
|
||||
- (void)dismiss {
|
||||
[UIView animateWithDuration:0.25 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{
|
||||
self.backgroundMask.alpha = 0;
|
||||
self.containerView.transform = CGAffineTransformMakeTranslation(0, 320);
|
||||
} completion:^(BOOL finished) {
|
||||
[self removeFromSuperview];
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - Utilities
|
||||
|
||||
- (UIColor *)colorFromHex:(NSString *)hexString {
|
||||
unsigned rgbValue = 0;
|
||||
NSScanner *scanner = [NSScanner scannerWithString:hexString];
|
||||
[scanner setScanLocation:1]; // 跳过 #
|
||||
[scanner scanHexInt:&rgbValue];
|
||||
return [UIColor colorWithRed:((rgbValue & 0xFF0000) >> 16)/255.0
|
||||
green:((rgbValue & 0xFF00) >> 8)/255.0
|
||||
blue:(rgbValue & 0xFF)/255.0
|
||||
alpha:1.0];
|
||||
}
|
||||
|
||||
#pragma mark - Lazy Loading
|
||||
|
||||
- (UIView *)backgroundMask {
|
||||
if (!_backgroundMask) {
|
||||
_backgroundMask = [[UIView alloc] init];
|
||||
_backgroundMask.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.5];
|
||||
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onBackgroundTapped)];
|
||||
[_backgroundMask addGestureRecognizer:tap];
|
||||
}
|
||||
return _backgroundMask;
|
||||
}
|
||||
|
||||
- (UIView *)containerView {
|
||||
if (!_containerView) {
|
||||
_containerView = [[UIView alloc] init];
|
||||
_containerView.backgroundColor = [UIColor colorWithRed:0x0C/255.0 green:0x05/255.0 blue:0x27/255.0 alpha:1.0];
|
||||
_containerView.layer.cornerRadius = 20;
|
||||
_containerView.layer.maskedCorners = kCALayerMinXMinYCorner | kCALayerMaxXMinYCorner;
|
||||
_containerView.layer.masksToBounds = YES;
|
||||
}
|
||||
return _containerView;
|
||||
}
|
||||
|
||||
- (UILabel *)titleLabel {
|
||||
if (!_titleLabel) {
|
||||
_titleLabel = [[UILabel alloc] init];
|
||||
_titleLabel.text = @"Choose your emotion";
|
||||
_titleLabel.textColor = [UIColor whiteColor];
|
||||
_titleLabel.font = [UIFont systemFontOfSize:20 weight:UIFontWeightSemibold];
|
||||
_titleLabel.textAlignment = NSTextAlignmentCenter;
|
||||
}
|
||||
return _titleLabel;
|
||||
}
|
||||
|
||||
- (UIView *)colorWheelContainer {
|
||||
if (!_colorWheelContainer) {
|
||||
_colorWheelContainer = [[UIView alloc] init];
|
||||
_colorWheelContainer.backgroundColor = [UIColor clearColor];
|
||||
}
|
||||
return _colorWheelContainer;
|
||||
}
|
||||
|
||||
- (NSMutableArray<UIButton *> *)colorButtons {
|
||||
if (!_colorButtons) {
|
||||
_colorButtons = [NSMutableArray array];
|
||||
}
|
||||
return _colorButtons;
|
||||
}
|
||||
|
||||
@end
|
||||
|
@@ -11,6 +11,7 @@
|
||||
#import "AccountInfoStorage.h"
|
||||
#import "Api+Moments.h"
|
||||
#import "NetImageView.h"
|
||||
#import "EPEmotionColorStorage.h"
|
||||
|
||||
@interface EPMomentCell ()
|
||||
|
||||
@@ -167,6 +168,43 @@
|
||||
[self.commentButton setTitle:[NSString stringWithFormat:@"💬 %ld", (long)cmtCnt] forState:UIControlStateNormal];
|
||||
|
||||
self.avatarImageView.imageUrl = model.avatar;
|
||||
|
||||
// 配置情绪颜色 border 和 shadow
|
||||
[self applyEmotionColorEffect:model.emotionColor];
|
||||
}
|
||||
|
||||
/// 应用情绪颜色视觉效果(Border + Shadow)
|
||||
- (void)applyEmotionColorEffect:(NSString *)emotionColorHex {
|
||||
NSString *displayColorHex = emotionColorHex;
|
||||
|
||||
// 如果没有保存的颜色,使用随机颜色(不持久化)
|
||||
if (!displayColorHex) {
|
||||
displayColorHex = [EPEmotionColorStorage randomEmotionColor];
|
||||
}
|
||||
|
||||
UIColor *color = [self colorFromHex:displayColorHex];
|
||||
|
||||
// 设置 border
|
||||
self.cardView.layer.borderWidth = 3.0;
|
||||
self.cardView.layer.borderColor = color.CGColor;
|
||||
|
||||
// 设置 shadow(使用情绪颜色)
|
||||
self.cardView.layer.shadowColor = color.CGColor;
|
||||
self.cardView.layer.shadowOffset = CGSizeMake(0, 2);
|
||||
self.cardView.layer.shadowOpacity = 0.5;
|
||||
self.cardView.layer.shadowRadius = 16.0;
|
||||
}
|
||||
|
||||
/// Hex 转 UIColor
|
||||
- (UIColor *)colorFromHex:(NSString *)hexString {
|
||||
unsigned rgbValue = 0;
|
||||
NSScanner *scanner = [NSScanner scannerWithString:hexString];
|
||||
[scanner setScanLocation:1]; // 跳过 #
|
||||
[scanner scanHexInt:&rgbValue];
|
||||
return [UIColor colorWithRed:((rgbValue & 0xFF0000) >> 16)/255.0
|
||||
green:((rgbValue & 0xFF00) >> 8)/255.0
|
||||
blue:(rgbValue & 0xFF)/255.0
|
||||
alpha:1.0];
|
||||
}
|
||||
|
||||
// MARK: - Images Grid
|
||||
@@ -294,10 +332,7 @@
|
||||
_cardView = [[UIView alloc] init];
|
||||
_cardView.backgroundColor = [UIColor whiteColor];
|
||||
_cardView.layer.cornerRadius = 12; // 圆角
|
||||
_cardView.layer.shadowColor = [UIColor blackColor].CGColor;
|
||||
_cardView.layer.shadowOffset = CGSizeMake(0, 2);
|
||||
_cardView.layer.shadowOpacity = 0.1;
|
||||
_cardView.layer.shadowRadius = 8;
|
||||
// Shadow 和 Border 将由 applyEmotionColorEffect 动态设置
|
||||
_cardView.layer.masksToBounds = NO;
|
||||
}
|
||||
return _cardView;
|
||||
|
@@ -10,6 +10,7 @@
|
||||
#import "EPMomentCell.h"
|
||||
#import <MJRefresh/MJRefresh.h>
|
||||
#import "YuMi-Swift.h"
|
||||
#import "EPEmotionColorStorage.h"
|
||||
|
||||
|
||||
@interface EPMomentListView () <UITableViewDelegate, UITableViewDataSource>
|
||||
@@ -91,6 +92,9 @@
|
||||
@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];
|
||||
@@ -120,6 +124,41 @@
|
||||
[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;
|
||||
}
|
||||
// 不设置则保持 nil,Cell 渲染时会随机生成
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - UITableView
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
|
@@ -77,6 +77,8 @@ typedef NS_ENUM(NSInteger, MonentsContentType) {
|
||||
@property (nonatomic, copy) NSString *worldName;
|
||||
///动态的id
|
||||
@property (nonatomic,copy) NSString *dynamicId;
|
||||
///情绪颜色(本地标注,Hex格式如 #FF0000)
|
||||
@property (nonatomic, copy) NSString *emotionColor;
|
||||
///是否是折叠起来的
|
||||
@property (nonatomic,assign) BOOL isFold;
|
||||
///cell的高度
|
||||
|
Reference in New Issue
Block a user