This commit is contained in:
Marcos Rodriguez Velez 2024-11-07 22:13:55 -04:00
parent 568209258f
commit d7d79748e2
2 changed files with 88 additions and 155 deletions

View File

@ -9,11 +9,13 @@ import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.modules.core.DeviceEventManagerModule;
import java.util.Map;
public class RNDefaultPreferenceModule extends ReactContextBaseJavaModule {
private String preferencesName;
private final SharedPreferences.OnSharedPreferenceChangeListener preferenceChangeListener;
private final ReactApplicationContext reactContext;
private boolean hasListeners = false; // Flag to track if listeners are active
public RNDefaultPreferenceModule(ReactApplicationContext reactContext) {
super(reactContext);
@ -21,11 +23,11 @@ public class RNDefaultPreferenceModule extends ReactContextBaseJavaModule {
this.preferencesName = reactContext.getPackageName() + "_preferences";
preferenceChangeListener = (sharedPreferences, key) -> {
if (reactContext.hasActiveCatalystInstance()) {
if (hasListeners && reactContext.hasActiveCatalystInstance()) { // Only send events if listeners are active
WritableMap changeInfo = Arguments.createMap();
changeInfo.putString("key", key);
Object value = sharedPreferences.getAll().get(key);
if (value instanceof String) {
changeInfo.putString("value", (String) value);
} else if (value instanceof Integer) {
@ -45,6 +47,7 @@ public class RNDefaultPreferenceModule extends ReactContextBaseJavaModule {
.emit("onPreferenceChange", changeInfo);
}
};
getPreferences().registerOnSharedPreferenceChangeListener(preferenceChangeListener);
}
@ -53,49 +56,61 @@ public class RNDefaultPreferenceModule extends ReactContextBaseJavaModule {
return "RNDefaultPreference";
}
@Override
public void initialize() {
super.initialize();
hasListeners = true; // Mark that listeners are active when the module is initialized
}
@Override
public void onCatalystInstanceDestroy() {
super.onCatalystInstanceDestroy();
hasListeners = false; // Mark that no listeners are active when the module is destroyed
getPreferences().unregisterOnSharedPreferenceChangeListener(preferenceChangeListener);
}
private SharedPreferences getPreferences() {
return getReactApplicationContext().getSharedPreferences(preferencesName, Context.MODE_PRIVATE);
}}
private SharedPreferences.Editor getEditor() {
return getPreferences().edit();
}
private void resolvePreferenceValue(Object value, Promise promise) {
if (value instanceof String) {
promise.resolve((String) value);
} else if (value instanceof Integer) {
promise.resolve((Integer) value);
} else if (value instanceof Boolean) {
promise.resolve((Boolean) value);
} else if (value instanceof Float) {
promise.resolve((Float) value);
} else if (value instanceof Long) {
promise.resolve((Long) value);
} else {
promise.resolve(null);
@ReactMethod
public void setName(String name, Promise promise) {
this.preferencesName = name;
promise.resolve(null);
}
}
private WritableMap resolvePreferenceToMap(String key, Object value) {
WritableMap map = Arguments.createMap();
if (value instanceof String) {
map.putString(key, (String) value);
} else if (value instanceof Integer) {
map.putInt(key, (Integer) value);
} else if (value instanceof Boolean) {
map.putBoolean(key, (Boolean) value);
} else if (value instanceof Float) {
map.putDouble(key, (Float) value);
} else if (value instanceof Long) {
map.putDouble(key, ((Long) value).doubleValue());
@ReactMethod
public void getName(Promise promise) {
promise.resolve(preferencesName);
}
@ReactMethod
public void get(String key, Promise promise) {
Object value = getPreferences().getAll().get(key);
if (value instanceof String) {
promise.resolve((String) value);
} else if (value instanceof Integer) {
promise.resolve((Integer) value);
} else if (value instanceof Boolean) {
promise.resolve((Boolean) value);
} else if (value instanceof Float) {
promise.resolve((Float) value);
} else if (value instanceof Long) {
promise.resolve((Long) value);
} else {
promise.resolve(null);
}
}
@ReactMethod
public void set(String key, String value, Promise promise) {
getPreferences().edit().putString(key, value).apply();
promise.resolve(null);
}
@ReactMethod
public void clear(String key, Promise promise) {
getPreferences().edit().remove(key).apply();
promise.resolve(null);
}
return map;
}
}

View File

@ -1,7 +1,13 @@
#import "RNDefaultPreference.h"
#import <React/RCTEventEmitter.h>
#import <React/RCTBridgeModule.h>
@implementation RNDefaultPreference
@interface RNDefaultPreference : RCTEventEmitter <RCTBridgeModule>
@end
@implementation RNDefaultPreference {
BOOL hasListeners;
}
NSString* defaultSuiteName = nil;
@ -10,8 +16,8 @@ NSString* defaultSuiteName = nil;
return dispatch_get_main_queue();
}
- (NSUserDefaults *) getDefaultUser{
if(defaultSuiteName == nil){
- (NSUserDefaults *)getDefaultUser {
if (defaultSuiteName == nil) {
return [NSUserDefaults standardUserDefaults];
} else {
return [[NSUserDefaults alloc] initWithSuiteName:defaultSuiteName];
@ -25,11 +31,22 @@ RCT_EXPORT_MODULE()
return YES;
}
// Implement required method for RCTEventEmitter
- (NSArray<NSString *> *)supportedEvents
{
return @[@"onPreferenceChange"];
}
// Called when the first listener is added
- (void)startObserving {
hasListeners = YES;
}
// Called when the last listener is removed or when the module is deallocated
- (void)stopObserving {
hasListeners = NO;
}
- (instancetype)init
{
if (self = [super init]) {
@ -43,13 +60,16 @@ RCT_EXPORT_MODULE()
- (void)userDefaultsDidChange:(NSNotification *)notification
{
NSUserDefaults *defaults = [self getDefaultUser];
NSDictionary *changedKeys = defaults.dictionaryRepresentation;
[changedKeys enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
NSDictionary *changeInfo = @{@"key": key, @"value": obj};
[self sendEventWithName:@"onPreferenceChange" body:changeInfo];
}];
if (hasListeners) { // Only send events if there are listeners
NSUserDefaults *defaults = [self getDefaultUser];
NSDictionary *changedKeys = defaults.dictionaryRepresentation;
for (NSString *key in changedKeys) {
id value = [defaults objectForKey:key];
NSDictionary *changeInfo = @{@"key": key, @"value": value ?: [NSNull null]};
[self sendEventWithName:@"onPreferenceChange" body:changeInfo];
}
}
}
- (void)dealloc
@ -57,146 +77,44 @@ RCT_EXPORT_MODULE()
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
RCT_EXPORT_METHOD(set:(NSString *)key value:(id)value
resolve:(RCTPromiseResolveBlock)resolve
reject:(RCTPromiseRejectBlock)reject)
{
if ([value isKindOfClass:[NSString class]]) {
[[self getDefaultUser] setObject:value forKey:key];
} else if ([value isKindOfClass:[NSNumber class]]) {
[[self getDefaultUser] setObject:value forKey:key];
}
[[self getDefaultUser] synchronize];
resolve([NSNull null]);
}
RCT_EXPORT_METHOD(setName:(NSString *)name
resolve:(RCTPromiseResolveBlock)resolve
reject:(__unused RCTPromiseRejectBlock)reject)
reject:(RCTPromiseRejectBlock)reject)
{
defaultSuiteName = name;
resolve([NSNull null]);
}
RCT_EXPORT_METHOD(getName:(RCTPromiseResolveBlock)resolve
reject:(__unused RCTPromiseRejectBlock)reject)
reject:(RCTPromiseRejectBlock)reject)
{
resolve(defaultSuiteName);
}
RCT_EXPORT_METHOD(get:(NSString *)key
resolve:(RCTPromiseResolveBlock)resolve
reject:(__unused RCTPromiseRejectBlock)reject)
reject:(RCTPromiseRejectBlock)reject)
{
id value = [[self getDefaultUser] objectForKey:key];
if ([value isKindOfClass:[NSString class]]) {
resolve(value);
} else if ([value isKindOfClass:[NSNumber class]]) {
resolve([NSString stringWithFormat:@"%@", value]);
} else if ([value isKindOfClass:[NSArray class]] || [value isKindOfClass:[NSDictionary class]]) {
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:value options:0 error:&error];
if (!jsonData) {
reject(@"error_serializing", @"Could not serialize JSON data", error);
} else {
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
resolve(jsonString);
}
} else {
resolve([NSNull null]);
}
resolve(value ?: [NSNull null]);
}
RCT_EXPORT_METHOD(set:(NSString *)key value:(id)value
resolve:(RCTPromiseResolveBlock)resolve
reject:(__unused RCTPromiseRejectBlock)reject)
reject:(RCTPromiseRejectBlock)reject)
{
if ([value isKindOfClass:[NSString class]]) {
[[self getDefaultUser] setObject:value forKey:key];
} else if ([value isKindOfClass:[NSNumber class]]) {
[[self getDefaultUser] setObject:value forKey:key];
} else if ([value isKindOfClass:[NSArray class]] || [value isKindOfClass:[NSDictionary class]]) {
[[self getDefaultUser] setObject:value forKey:key];
}
NSUserDefaults *defaults = [self getDefaultUser];
[defaults setObject:value forKey:key];
[defaults synchronize];
resolve([NSNull null]);
}
RCT_EXPORT_METHOD(clear:(NSString *)key
resolve:(RCTPromiseResolveBlock)resolve
reject:(__unused RCTPromiseRejectBlock)reject)
reject:(RCTPromiseRejectBlock)reject)
{
[[self getDefaultUser] removeObjectForKey:key];
resolve([NSNull null]);
}
RCT_EXPORT_METHOD(getMultiple:(NSArray *)keys
resolve:(RCTPromiseResolveBlock)resolve
reject:(__unused RCTPromiseRejectBlock)reject)
{
NSMutableArray *result = [NSMutableArray array];
for (NSString *key in keys) {
id value = [[self getDefaultUser] objectForKey:key];
if ([value isKindOfClass:[NSString class]] || [value isKindOfClass:[NSNumber class]]) {
[result addObject:value];
} else if ([value isKindOfClass:[NSArray class]] || [value isKindOfClass:[NSDictionary class]]) {
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:value options:0 error:&error];
NSString *jsonString = jsonData ? [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding] : [NSNull null];
[result addObject:jsonString];
} else {
[result addObject:[NSNull null]];
}
}
resolve(result);
}
RCT_EXPORT_METHOD(setMultiple:(NSDictionary *)data
resolve:(RCTPromiseResolveBlock)resolve
reject:(__unused RCTPromiseRejectBlock)reject)
{
for (id key in data) {
id value = data[key];
[[self getDefaultUser] setObject:value forKey:key];
}
resolve([NSNull null]);
}
RCT_EXPORT_METHOD(clearMultiple:(NSArray *)keys
resolve:(RCTPromiseResolveBlock)resolve
reject:(__unused RCTPromiseRejectBlock)reject)
{
for (NSString *key in keys) {
[[self getDefaultUser] removeObjectForKey:key];
}
resolve([NSNull null]);
}
RCT_EXPORT_METHOD(getAll:(RCTPromiseResolveBlock)resolve
reject:(__unused RCTPromiseRejectBlock)reject)
{
NSArray *keys = [[[self getDefaultUser] dictionaryRepresentation] allKeys];
NSMutableDictionary *result = [NSMutableDictionary dictionary];
for (NSString *key in keys) {
id value = [[self getDefaultUser] objectForKey:key];
if ([value isKindOfClass:[NSString class]] || [value isKindOfClass:[NSNumber class]]) {
result[key] = value;
} else if ([value isKindOfClass:[NSArray class]] || [value isKindOfClass:[NSDictionary class]]) {
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:value options:0 error:&error];
result[key] = jsonData ? [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding] : [NSNull null];
} else {
result[key] = [NSNull null];
}
}
resolve(result);
}
RCT_EXPORT_METHOD(clearAll:(RCTPromiseResolveBlock)resolve
reject:(RCTPromiseRejectBlock)reject)
{
NSArray *keys = [[[self getDefaultUser] dictionaryRepresentation] allKeys];
[self clearMultiple:keys resolve:resolve reject:reject];
}
@end