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

324 lines
9.9 KiB
Mathematica
Raw Normal View History

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