Files
real-e-party-iOS/YuMi/Tools/FirstCharge/FirstRechargeManager.m
edwinQQQ a35a711be6 chore: Initial clean commit
- 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
2025-10-09 16:19:14 +08:00

324 lines
9.9 KiB
Objective-C
Raw Permalink 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.

//
// 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