单军华
2018-07-11 7b02207537d35bfa1714bf8beafc921f717d100a
screendisplay/Pods/HMEmoticon/????/Emoticon/HMEmoticonManager.m
New file
@@ -0,0 +1,235 @@
//
//  HMEmoticonManager.m
//  表情键盘
//
//  Created by 刘凡 on 16/3/3.
//  Copyright © 2016年 itcast. All rights reserved.
//
#import "HMEmoticonManager.h"
#import "NSBundle+HMEmoticon.h"
#import "HMEmoticonAttachment.h"
/// 每页显示的表情数量
static NSInteger kEmoticonsCountOfPage = 20;
/// 命名空间常量
NSString *const HMEmoticonNamespace = @"cn.itcast";
/// 默认用户标识符
NSString *const HMEmoticonDefaultUserIdentifier = @"DefaultUser";
/// 表情文件名
NSString *const HMEmoticonFileName = @".emoticons.json";
@implementation HMEmoticonManager {
    NSMutableArray <HMEmoticon *> *_recentEmoticonList;
}
#pragma mark - 单例 & 构造函数
+ (instancetype)sharedManager {
    static id instance;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[self alloc] init];
    });
    return instance;
}
- (instancetype)init {
    self = [super init];
    if (self) {
        _packages = [NSMutableArray array];
        [self loadPackages];
    }
    return self;
}
#pragma mark - 字符串转换
- (NSAttributedString *)emoticonStringWithString:(NSString *)string font:(UIFont *)font textColor:(UIColor *)textColor {
    NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc]
                                                   initWithString:string
                                                   attributes:@{NSFontAttributeName: font,
                                                                NSForegroundColorAttributeName: textColor}];
    NSString *pattern = @"\\[.*?\\]";
    NSRegularExpression *regx = [NSRegularExpression regularExpressionWithPattern:pattern options:0 error:NULL];
    NSArray *matches = [regx matchesInString:string options:0 range:NSMakeRange(0, string.length)];
    for (NSTextCheckingResult *result in matches.reverseObjectEnumerator) {
        NSRange range = [result rangeAtIndex:0];
        NSString *str = [string substringWithRange:range];
        HMEmoticon *emoticon = [self emoticonWithString:str];
        if (emoticon != nil) {
            NSAttributedString *emoticonString = [HMEmoticonAttachment emoticonStringWithEmoticon:emoticon font:font textColor:textColor];
            [attributedString replaceCharactersInRange:range withAttributedString:emoticonString];
        }
    }
    return attributedString.copy;
}
- (HMEmoticon *)emoticonWithString:(NSString *)string {
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"chs == %@", string];
    HMEmoticon *emoticon = nil;
    for (NSInteger i = 1; i < _packages.count; i++) {
        HMEmoticonPackage *package = _packages[i];
        NSArray *filter = [package.emoticonsList filteredArrayUsingPredicate:predicate];
        if (filter.count == 1) {
            emoticon = filter[0];
            break;
        }
    }
    return emoticon;
}
#pragma mark - 数据源方法
- (NSInteger)numberOfPagesInSection:(NSInteger)section {
    HMEmoticonPackage *package = _packages[section];
    return ((NSInteger)package.emoticonsList.count - 1) / kEmoticonsCountOfPage + 1;
}
- (NSArray *)emoticonsWithIndexPath:(NSIndexPath *)indexPath {
    HMEmoticonPackage *package = self.packages[indexPath.section];
    NSInteger location = indexPath.item * kEmoticonsCountOfPage;
    NSInteger length = kEmoticonsCountOfPage;
    // 判断是否越界
    if ((location + length) > package.emoticonsList.count) {
        length = package.emoticonsList.count - location;
    }
    NSRange range = NSMakeRange(location, length);
    return [package.emoticonsList subarrayWithRange:range];
}
#pragma mark - 最近使用表情
- (void)addRecentEmoticon:(HMEmoticon *)emoticon {
    // 0. 表情计数 ++
    emoticon.times++;
    // 1. 判断表情是否已经存在
    if (![_recentEmoticonList containsObject:emoticon]) {
        [_recentEmoticonList addObject:emoticon];
    }
    // 2. 排序
    [_recentEmoticonList sortUsingComparator:^NSComparisonResult(HMEmoticon *obj1, HMEmoticon *obj2) {
        return obj1.times < obj2.times;
    }];
    // 3. 更新最近表情包
    [self updateRecentPackage];
    // 4. 保存表情包
    [self saveRecentEmoticonList];
}
/// 更新最近表情包数组
- (void)updateRecentPackage {
    NSInteger length = _recentEmoticonList.count < kEmoticonsCountOfPage ? _recentEmoticonList.count : kEmoticonsCountOfPage;
    _packages[0].emoticonsList = [_recentEmoticonList subarrayWithRange:NSMakeRange(0, length)].mutableCopy;
}
/// 保存最近表情数组
- (void)saveRecentEmoticonList {
    NSMutableArray *jsonDict = [NSMutableArray array];
    for (HMEmoticon *emoticon in _recentEmoticonList) {
        [jsonDict addObject:[emoticon dictionary]];
    }
    NSData *data = [NSJSONSerialization dataWithJSONObject:jsonDict options:NSJSONWritingPrettyPrinted error:NULL];
    [data writeToFile:[self filePathForRecentEmoticon] atomically:YES];
}
/// 加载最近表情数组
///
/// @return 最近表情数组
- (NSMutableArray <HMEmoticon *>*)loadRecentEmoticonList {
    NSMutableArray *arrayM = [NSMutableArray array];
    NSData *data = [NSData dataWithContentsOfFile:[self filePathForRecentEmoticon]];
    if (data == nil) {
        return arrayM;
    }
    NSArray *array = [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL];
    for (NSDictionary *dict in array) {
        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"chs CONTAINS %@ || code CONTAINS %@", dict[@"chs"], dict[@"code"]];
        for (NSInteger i = 1; i < _packages.count; i++) {
            HMEmoticonPackage *package = _packages[i];
            NSArray *filter = [package.emoticonsList filteredArrayUsingPredicate:predicate];
            if (filter.count == 1) {
                [arrayM addObject:filter[0]];
                break;
            }
        }
    }
    return arrayM;
}
/// 最近表情文件路径
- (NSString *)filePathForRecentEmoticon {
    NSString *dir = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).lastObject;
    return [[dir stringByAppendingPathComponent:self.userIdentifier] stringByAppendingString:HMEmoticonFileName];
}
#pragma mark - 加载表情包数据
- (void)loadPackages {
    // 1. 读取 emoticons.plist
    NSString *path = [[NSBundle hm_emoticonBundle] pathForResource:@"emoticons.plist" ofType:nil];
    NSArray *array = [NSArray arrayWithContentsOfFile:path];
    // 2. 遍历数组,生成 packages 模型
    for (NSDictionary *dict in array) {
        [_packages addObject:[HMEmoticonPackage packageWithDict:dict]];
    }
    // 3. 加载最近使用表情列表
    _recentEmoticonList = [self loadRecentEmoticonList];
    // 4. 更新最近表情包
    [self updateRecentPackage];
}
#pragma mark - 用户标识符
@synthesize userIdentifier = _userIdentifier;
- (void)setUserIdentifier:(NSString *)userIdentifier {
    _userIdentifier = userIdentifier.copy;
    _recentEmoticonList = [self loadRecentEmoticonList];
    [self updateRecentPackage];
}
- (NSString *)userIdentifier {
    if (_userIdentifier == nil) {
        _userIdentifier = HMEmoticonDefaultUserIdentifier;
    }
    return [NSString stringWithFormat:@"%@.%@", HMEmoticonNamespace, _userIdentifier];;
}
@end