Files
peko-ios/YuMi/Tools/FirstCharge/FirstRechargeManager.m

246 lines
7.0 KiB
Objective-C
Raw 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";
@interface FirstRechargeManager ()
@property (nonatomic, strong) FirstRechargeModel *currentFirstRechargeData;
@property (nonatomic, strong) NSTimer *dailyTimer;
@property (nonatomic, assign) BOOL isMonitoring;
@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];
}
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 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];
[[NSUserDefaults standardUserDefaults] setObject:today forKey:kTodayShownKey];
[[NSUserDefaults standardUserDefaults] synchronize];
}
#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 {
// 应用进入前台时检查是否需要更新
if ([self shouldCheckToday]) {
[self checkFirstRechargeStatus];
}
}
- (BOOL)shouldCheckToday {
NSString *lastCheckDate = [[NSUserDefaults standardUserDefaults] objectForKey:kLastCheckDateKey];
NSString *today = [self getTodayString];
return ![today isEqualToString:lastCheckDate];
}
- (void)checkFirstRechargeStatus {
// 检查是否登录
if ([AccountInfoStorage instance].getTicket.length == 0 ||
[AccountInfoStorage instance].getUid.length == 0) {
return;
}
// 调用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];
[[NSUserDefaults standardUserDefaults] setObject:today forKey:kLastCheckDateKey];
[[NSUserDefaults standardUserDefaults] synchronize];
// 判断是否需要展示
BOOL shouldShow = [self shouldShowFirstRecharge:model];
// 通知代理
[self notifyDelegatesWithModel:model shouldShow:shouldShow];
}
- (BOOL)shouldShowFirstRecharge:(FirstRechargeModel *)model {
#if DEBUG
return YES;
#endif
// 如果已经首充过,不展示
if (model.chargeStatus) {
return NO;
}
// 检查今天是否已经展示过
NSString *shownDate = [[NSUserDefaults standardUserDefaults] objectForKey:kTodayShownKey];
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]];
}
- (void)saveCachedModel:(FirstRechargeModel *)model {
if (model) {
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:model.toJSONObject requiringSecureCoding:NO error:nil];
[[NSUserDefaults standardUserDefaults] setObject:data forKey:kFirstRechargeModelKey];
[[NSUserDefaults standardUserDefaults] synchronize];
}
}
- (void)loadCachedModel {
NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:kFirstRechargeModelKey];
if (data) {
NSDictionary *dict = [NSKeyedUnarchiver unarchivedObjectOfClass:[NSDictionary class] fromData:data error:nil];
if (dict) {
self.currentFirstRechargeData = [FirstRechargeModel modelWithJSON:dict];
}
}
}
@end