
- Removed YuMi/Library/ (138 MB, not tracked) - Removed YuMi/Resources/ (23 MB, not tracked) - Removed old version assets (566 files, not tracked) - Excluded Pods/, xcuserdata/ and other build artifacts - Clean repository optimized for company server deployment
324 lines
9.9 KiB
Objective-C
324 lines
9.9 KiB
Objective-C
//
|
||
// FirstRechargeManager.m
|
||
// YuMi
|
||
//
|
||
// Created by P on 2025/6/25.
|
||
//
|
||
|
||
#import "FirstRechargeManager.h"
|
||
#import "FirstRechargeModel.h"
|
||
#import "Api+FirstRecharge.h"
|
||
#import "AccountInfoStorage.h"
|
||
#import "NSDate+DateUtils.h"
|
||
|
||
// 存储键
|
||
static NSString * const kFirstRechargeModelKey = @"FirstRechargeModel";
|
||
static NSString * const kLastCheckDateKey = @"FirstRechargeLastCheckDate";
|
||
static NSString * const kTodayShownKey = @"FirstRechargeTodayShown";
|
||
static NSString * const kCurrentUserIdKey = @"FirstRechargeCurrentUserId";
|
||
|
||
@interface FirstRechargeManager ()
|
||
|
||
@property (nonatomic, strong) FirstRechargeModel *currentFirstRechargeData;
|
||
@property (nonatomic, strong) NSTimer *dailyTimer;
|
||
@property (nonatomic, assign) BOOL isMonitoring;
|
||
@property (nonatomic, copy) NSString *currentUserId;
|
||
|
||
@end
|
||
|
||
@implementation FirstRechargeManager
|
||
|
||
+ (instancetype)sharedManager {
|
||
static FirstRechargeManager *instance = nil;
|
||
static dispatch_once_t onceToken;
|
||
dispatch_once(&onceToken, ^{
|
||
instance = [[FirstRechargeManager alloc] init];
|
||
});
|
||
return instance;
|
||
}
|
||
|
||
- (instancetype)init {
|
||
self = [super init];
|
||
if (self) {
|
||
_isMonitoring = NO;
|
||
[self loadCachedModel];
|
||
[self updateCurrentUserId];
|
||
}
|
||
return self;
|
||
}
|
||
|
||
- (void)dealloc {
|
||
[self stopMonitoring];
|
||
}
|
||
|
||
#pragma mark - Public Methods
|
||
|
||
- (FirstRechargeModel *)loadCurrentModel {
|
||
return self.currentFirstRechargeData;
|
||
}
|
||
|
||
- (void)startMonitoring {
|
||
if (self.isMonitoring) {
|
||
return;
|
||
}
|
||
|
||
self.isMonitoring = YES;
|
||
|
||
// 检查用户是否切换
|
||
[self checkUserSwitch];
|
||
|
||
// 立即检查一次
|
||
[self checkFirstRechargeStatus];
|
||
|
||
// 设置每日定时检查
|
||
[self setupDailyTimer];
|
||
|
||
// 监听应用进入前台事件
|
||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||
selector:@selector(applicationDidBecomeActive)
|
||
name:UIApplicationDidBecomeActiveNotification
|
||
object:nil];
|
||
}
|
||
|
||
- (void)stopMonitoring {
|
||
if (!self.isMonitoring) {
|
||
return;
|
||
}
|
||
|
||
self.isMonitoring = NO;
|
||
|
||
// 停止定时器
|
||
if (self.dailyTimer) {
|
||
[self.dailyTimer invalidate];
|
||
self.dailyTimer = nil;
|
||
}
|
||
|
||
// 移除通知监听
|
||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||
}
|
||
|
||
- (void)manualCheckFirstRecharge {
|
||
[self checkFirstRechargeStatus];
|
||
}
|
||
|
||
- (void)markTodayShown {
|
||
NSString *today = [self getTodayString];
|
||
[self setTodayShownForCurrentUser:today];
|
||
}
|
||
|
||
- (void)updateChargeStatusToCompleted {
|
||
if (self.currentFirstRechargeData && !self.currentFirstRechargeData.chargeStatus) {
|
||
// 更新首充状态为已完成
|
||
self.currentFirstRechargeData.chargeStatus = YES;
|
||
|
||
// 保存更新后的模型
|
||
[self saveCachedModel:self.currentFirstRechargeData];
|
||
|
||
// 通知代理(如果需要)
|
||
[self notifyDelegatesWithModel:self.currentFirstRechargeData shouldShow:NO];
|
||
}
|
||
}
|
||
|
||
#pragma mark - Private Methods
|
||
|
||
- (void)setupDailyTimer {
|
||
// 计算到明天凌晨的时间间隔
|
||
NSTimeInterval secondsUntilMidnight = [self secondsUntilNextMidnight];
|
||
|
||
// 设置定时器在明天凌晨触发,然后每24小时重复
|
||
self.dailyTimer = [NSTimer scheduledTimerWithTimeInterval:secondsUntilMidnight
|
||
target:self
|
||
selector:@selector(dailyTimerFired)
|
||
userInfo:nil
|
||
repeats:NO];
|
||
}
|
||
|
||
- (void)dailyTimerFired {
|
||
// 检查首充状态
|
||
[self checkFirstRechargeStatus];
|
||
|
||
// 重新设置明天的定时器
|
||
[self setupDailyTimer];
|
||
}
|
||
|
||
- (NSTimeInterval)secondsUntilNextMidnight {
|
||
NSCalendar *calendar = [NSCalendar currentCalendar];
|
||
NSDate *now = [NSDate date];
|
||
|
||
// 获取明天
|
||
NSDate *tomorrow = [calendar dateByAddingUnit:NSCalendarUnitDay value:1 toDate:now options:0];
|
||
|
||
// 获取明天的开始时间(凌晨)
|
||
NSDate *tomorrowStart = [calendar startOfDayForDate:tomorrow];
|
||
|
||
// 计算时间差
|
||
return [tomorrowStart timeIntervalSinceDate:now];
|
||
}
|
||
|
||
- (void)applicationDidBecomeActive {
|
||
// 检查用户是否切换
|
||
[self checkUserSwitch];
|
||
|
||
// 应用进入前台时检查是否需要更新
|
||
if ([self shouldCheckToday]) {
|
||
[self checkFirstRechargeStatus];
|
||
}
|
||
}
|
||
|
||
- (BOOL)shouldCheckToday {
|
||
NSString *userSpecificKey = [self getUserSpecificKey:kLastCheckDateKey];
|
||
NSString *lastCheckDate = [[NSUserDefaults standardUserDefaults] objectForKey:userSpecificKey];
|
||
NSString *today = [self getTodayString];
|
||
|
||
return ![today isEqualToString:lastCheckDate];
|
||
}
|
||
|
||
- (void)checkFirstRechargeStatus {
|
||
// 检查是否登录
|
||
if ([AccountInfoStorage instance].getTicket.length == 0 ||
|
||
[AccountInfoStorage instance].getUid.length == 0) {
|
||
return;
|
||
}
|
||
|
||
// 更新当前用户ID
|
||
[self updateCurrentUserId];
|
||
|
||
// 调用API获取首充信息
|
||
@kWeakify(self);
|
||
[Api firstchargeInfo:^(BaseModel * _Nullable data, NSInteger code, NSString * _Nullable msg) {
|
||
@kStrongify(self);
|
||
if (code == 200 && data.data) {
|
||
FirstRechargeModel *model = [FirstRechargeModel modelWithJSON:data.data];
|
||
[self handleFirstRechargeResult:model];
|
||
}
|
||
}];
|
||
}
|
||
|
||
- (void)handleFirstRechargeResult:(FirstRechargeModel *)model {
|
||
if (!model) {
|
||
return;
|
||
}
|
||
|
||
// 保存模型
|
||
self.currentFirstRechargeData = model;
|
||
[self saveCachedModel:model];
|
||
|
||
// 更新检查日期(针对当前用户)
|
||
NSString *today = [self getTodayString];
|
||
NSString *userSpecificKey = [self getUserSpecificKey:kLastCheckDateKey];
|
||
[[NSUserDefaults standardUserDefaults] setObject:today forKey:userSpecificKey];
|
||
[[NSUserDefaults standardUserDefaults] synchronize];
|
||
|
||
// 判断是否需要展示
|
||
BOOL shouldShow = [self shouldShowFirstRecharge:model];
|
||
|
||
// 通知代理
|
||
[self notifyDelegatesWithModel:model shouldShow:shouldShow];
|
||
}
|
||
|
||
- (BOOL)shouldShowFirstRecharge:(FirstRechargeModel *)model {
|
||
// 如果已经首充过,不展示
|
||
if (model.chargeStatus) {
|
||
return NO;
|
||
}
|
||
|
||
// 检查今天是否已经展示过(针对当前用户)
|
||
NSString *shownDate = [self getTodayShownForCurrentUser];
|
||
NSString *today = [self getTodayString];
|
||
|
||
return ![today isEqualToString:shownDate];
|
||
}
|
||
|
||
- (void)notifyDelegatesWithModel:(FirstRechargeModel *)model shouldShow:(BOOL)shouldShow {
|
||
@kWeakify(self);
|
||
dispatch_async(dispatch_get_main_queue(), ^{
|
||
@kStrongify(self);
|
||
if (self.delegate && [self.delegate respondsToSelector:@selector(firstRechargeManager:didCheckFirstRecharge:shouldShow:)]) {
|
||
[self.delegate firstRechargeManager:self didCheckFirstRecharge:model shouldShow:shouldShow];
|
||
}
|
||
});
|
||
}
|
||
|
||
- (NSString *)getTodayString {
|
||
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
|
||
[formatter setDateFormat:@"yyyy-MM-dd"];
|
||
return [formatter stringFromDate:[NSDate date]];
|
||
}
|
||
|
||
#pragma mark - User Switch Detection
|
||
|
||
- (void)updateCurrentUserId {
|
||
NSString *newUserId = [AccountInfoStorage instance].getUid;
|
||
if (newUserId.length > 0) {
|
||
self.currentUserId = newUserId;
|
||
// 保存当前用户ID
|
||
[[NSUserDefaults standardUserDefaults] setObject:newUserId forKey:kCurrentUserIdKey];
|
||
[[NSUserDefaults standardUserDefaults] synchronize];
|
||
}
|
||
}
|
||
|
||
- (void)checkUserSwitch {
|
||
NSString *savedUserId = [[NSUserDefaults standardUserDefaults] objectForKey:kCurrentUserIdKey];
|
||
NSString *currentUserId = [AccountInfoStorage instance].getUid;
|
||
|
||
// 如果用户ID发生变化,说明用户切换了
|
||
if (currentUserId.length > 0 &&
|
||
savedUserId.length > 0 &&
|
||
![currentUserId isEqualToString:savedUserId]) {
|
||
|
||
// 更新当前用户ID
|
||
[self updateCurrentUserId];
|
||
|
||
// 清除当前缓存的模型数据(因为是新用户)
|
||
self.currentFirstRechargeData = nil;
|
||
|
||
// 立即检查新用户的首充状态
|
||
[self checkFirstRechargeStatus];
|
||
} else if (currentUserId.length > 0 && savedUserId.length == 0) {
|
||
// 首次登录的情况
|
||
[self updateCurrentUserId];
|
||
}
|
||
}
|
||
|
||
#pragma mark - User-specific Storage
|
||
|
||
- (NSString *)getUserSpecificKey:(NSString *)baseKey {
|
||
if (self.currentUserId.length == 0) {
|
||
return baseKey;
|
||
}
|
||
return [NSString stringWithFormat:@"%@_%@", baseKey, self.currentUserId];
|
||
}
|
||
|
||
- (NSString *)getTodayShownForCurrentUser {
|
||
NSString *userSpecificKey = [self getUserSpecificKey:kTodayShownKey];
|
||
return [[NSUserDefaults standardUserDefaults] objectForKey:userSpecificKey];
|
||
}
|
||
|
||
- (void)setTodayShownForCurrentUser:(NSString *)date {
|
||
NSString *userSpecificKey = [self getUserSpecificKey:kTodayShownKey];
|
||
[[NSUserDefaults standardUserDefaults] setObject:date forKey:userSpecificKey];
|
||
[[NSUserDefaults standardUserDefaults] synchronize];
|
||
}
|
||
|
||
- (void)saveCachedModel:(FirstRechargeModel *)model {
|
||
if (model) {
|
||
NSString *userSpecificKey = [self getUserSpecificKey:kFirstRechargeModelKey];
|
||
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:model.toJSONObject requiringSecureCoding:NO error:nil];
|
||
[[NSUserDefaults standardUserDefaults] setObject:data forKey:userSpecificKey];
|
||
[[NSUserDefaults standardUserDefaults] synchronize];
|
||
}
|
||
}
|
||
|
||
- (void)loadCachedModel {
|
||
NSString *userSpecificKey = [self getUserSpecificKey:kFirstRechargeModelKey];
|
||
NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:userSpecificKey];
|
||
if (data) {
|
||
NSDictionary *dict = [NSKeyedUnarchiver unarchivedObjectOfClass:[NSDictionary class] fromData:data error:nil];
|
||
if (dict) {
|
||
self.currentFirstRechargeData = [FirstRechargeModel modelWithJSON:dict];
|
||
}
|
||
}
|
||
}
|
||
|
||
@end
|