Compare commits

...

1 Commits

Author SHA1 Message Date
Milan Burda
2791af2a66 feat: add APIs for accessing NSUserDefaults in the given domain 2020-05-04 20:34:04 +02:00
5 changed files with 264 additions and 133 deletions

View File

@@ -165,7 +165,7 @@ Add the specified defaults to your application's `NSUserDefaults`.
* `type` String - Can be `string`, `boolean`, `integer`, `float`, `double`,
`url`, `array` or `dictionary`.
Returns `any` - The value of `key` in `NSUserDefaults`.
Returns `any` - The value of `key` in `NSUserDefaults` for the app and current user.
Some popular `key` and `type`s are:
@@ -177,13 +177,22 @@ Some popular `key` and `type`s are:
* `NSPreferredWebServices`: `dictionary`
* `NSUserDictionaryReplacementItems`: `array`
### `systemPreferences.getUserDefaultInDomain(domain, key, type)` _macOS_
* `domain` String
* `key` String
* `type` String - Can be `string`, `boolean`, `integer`, `float`, `double`,
`url`, `array` or `dictionary`.
Returns `any` - The value of `key` in `NSUserDefaults` for the given `domain`.
### `systemPreferences.setUserDefault(key, type, value)` _macOS_
* `key` String
* `type` String - Can be `string`, `boolean`, `integer`, `float`, `double`, `url`, `array` or `dictionary`.
* `value` String
Set the value of `key` in `NSUserDefaults`.
Set the value of `key` in `NSUserDefaults` for the app and current user.
Note that `type` should match actual type of `value`. An exception is thrown
if they don't.
@@ -192,12 +201,31 @@ Some popular `key` and `type`s are:
* `ApplePressAndHoldEnabled`: `boolean`
### `systemPreferences.setUserDefaultInDomain(domain, key, type, value)` _macOS_
* `domain` String
* `key` String
* `type` String - See [`getUserDefault`](#systempreferencesgetuserdefaultkey-type-macos).
* `value` String
Set the value of `key` in `NSUserDefaults` for the given `domain`.
Note that `type` should match actual type of `value`. An exception is thrown
if they don't.
### `systemPreferences.removeUserDefault(key)` _macOS_
* `key` String
Removes the `key` in `NSUserDefaults`. This can be used to restore the default
or global value of a `key` previously set with `setUserDefault`.
Removes the `key` in `NSUserDefaults` for the app and current user.
This can be used to restore the default or global value of a `key` previously set with `setUserDefault`.
### `systemPreferences.removeUserDefaultInDomain(domain, key)` _macOS_
* `domain` String
* `key` String
Removes the `key` in `NSUserDefaults` for the given `domain`.
### `systemPreferences.isAeroGlassEnabled()` _Windows_

View File

@@ -97,8 +97,14 @@ void SystemPreferences::BuildPrototype(
&SystemPreferences::UnsubscribeWorkspaceNotification)
.SetMethod("registerDefaults", &SystemPreferences::RegisterDefaults)
.SetMethod("getUserDefault", &SystemPreferences::GetUserDefault)
.SetMethod("getUserDefaultInDomain",
&SystemPreferences::GetUserDefaultInDomain)
.SetMethod("setUserDefault", &SystemPreferences::SetUserDefault)
.SetMethod("setUserDefaultInDomain",
&SystemPreferences::SetUserDefaultInDomain)
.SetMethod("removeUserDefault", &SystemPreferences::RemoveUserDefault)
.SetMethod("removeUserDefaultInDomain",
&SystemPreferences::RemoveUserDefaultInDomain)
.SetMethod("isSwipeTrackingFromScrollEventsEnabled",
&SystemPreferences::IsSwipeTrackingFromScrollEventsEnabled)
.SetMethod("getEffectiveAppearance",

View File

@@ -81,13 +81,22 @@ class SystemPreferences : public gin_helper::EventEmitter<SystemPreferences>
int SubscribeWorkspaceNotification(const std::string& name,
const NotificationCallback& callback);
void UnsubscribeWorkspaceNotification(int request_id);
v8::Local<v8::Value> GetUserDefault(const std::string& name,
v8::Local<v8::Value> GetUserDefault(const std::string& key,
const std::string& type);
v8::Local<v8::Value> GetUserDefaultInDomain(const std::string& domain,
const std::string& key,
const std::string& type);
void RegisterDefaults(gin_helper::Arguments* args);
void SetUserDefault(const std::string& name,
void SetUserDefault(const std::string& key,
const std::string& type,
gin_helper::Arguments* args);
void RemoveUserDefault(const std::string& name);
void SetUserDefaultInDomain(const std::string& domain,
const std::string& key,
const std::string& type,
gin_helper::Arguments* args);
void RemoveUserDefault(const std::string& key);
void RemoveUserDefaultInDomain(const std::string& domain,
const std::string& key);
bool IsSwipeTrackingFromScrollEventsEnabled();
std::string GetSystemColor(gin_helper::ErrorThrower thrower,

View File

@@ -121,6 +121,103 @@ std::string ConvertSystemPermission(
}
}
v8::Local<v8::Value> GetUserDefaultImpl(v8::Isolate* isolate,
NSUserDefaults* defaults,
const std::string& name,
const std::string& type) {
NSString* key = base::SysUTF8ToNSString(name);
if (type == "string") {
return gin::StringToV8(
isolate, base::SysNSStringToUTF8([defaults stringForKey:key]));
} else if (type == "boolean") {
return v8::Boolean::New(isolate, [defaults boolForKey:key]);
} else if (type == "float") {
return v8::Number::New(isolate, [defaults floatForKey:key]);
} else if (type == "integer") {
return v8::Integer::New(isolate, [defaults integerForKey:key]);
} else if (type == "double") {
return v8::Number::New(isolate, [defaults doubleForKey:key]);
} else if (type == "url") {
return gin::ConvertToV8(isolate,
net::GURLWithNSURL([defaults URLForKey:key]));
} else if (type == "array") {
return gin::ConvertToV8(isolate,
NSArrayToListValue([defaults arrayForKey:key]));
} else if (type == "dictionary") {
return gin::ConvertToV8(isolate, NSDictionaryToDictionaryValue(
[defaults dictionaryForKey:key]));
} else {
return v8::Undefined(isolate);
}
}
void SetUserDefaultImpl(NSUserDefaults* defaults,
const std::string& name,
const std::string& type,
gin_helper::Arguments* args) {
NSString* key = base::SysUTF8ToNSString(name);
if (type == "string") {
std::string value;
if (args->GetNext(&value)) {
[defaults setObject:base::SysUTF8ToNSString(value) forKey:key];
return;
}
} else if (type == "boolean") {
bool value;
if (args->GetNext(&value)) {
[defaults setBool:value forKey:key];
return;
}
} else if (type == "float") {
float value;
if (args->GetNext(&value)) {
[defaults setFloat:value forKey:key];
return;
}
} else if (type == "integer") {
int value;
if (args->GetNext(&value)) {
[defaults setInteger:value forKey:key];
return;
}
} else if (type == "double") {
double value;
if (args->GetNext(&value)) {
[defaults setDouble:value forKey:key];
return;
}
} else if (type == "url") {
GURL value;
if (args->GetNext(&value)) {
if (NSURL* url = net::NSURLWithGURL(value)) {
[defaults setURL:url forKey:key];
return;
}
}
} else if (type == "array") {
base::ListValue value;
if (args->GetNext(&value)) {
if (NSArray* array = ListValueToNSArray(value)) {
[defaults setObject:array forKey:key];
return;
}
}
} else if (type == "dictionary") {
base::DictionaryValue value;
if (args->GetNext(&value)) {
if (NSDictionary* dict = DictionaryValueToNSDictionary(value)) {
[defaults setObject:dict forKey:key];
return;
}
}
} else {
args->ThrowError("Invalid type: " + type);
return;
}
args->ThrowError("Unable to convert value to: " + type);
}
} // namespace
void SystemPreferences::PostNotification(const std::string& name,
@@ -257,33 +354,19 @@ void SystemPreferences::DoUnsubscribeNotification(int request_id,
}
v8::Local<v8::Value> SystemPreferences::GetUserDefault(
const std::string& name,
const std::string& key,
const std::string& type) {
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
NSString* key = base::SysUTF8ToNSString(name);
if (type == "string") {
return gin::StringToV8(
isolate(), base::SysNSStringToUTF8([defaults stringForKey:key]));
} else if (type == "boolean") {
return v8::Boolean::New(isolate(), [defaults boolForKey:key]);
} else if (type == "float") {
return v8::Number::New(isolate(), [defaults floatForKey:key]);
} else if (type == "integer") {
return v8::Integer::New(isolate(), [defaults integerForKey:key]);
} else if (type == "double") {
return v8::Number::New(isolate(), [defaults doubleForKey:key]);
} else if (type == "url") {
return gin::ConvertToV8(isolate(),
net::GURLWithNSURL([defaults URLForKey:key]));
} else if (type == "array") {
return gin::ConvertToV8(isolate(),
NSArrayToListValue([defaults arrayForKey:key]));
} else if (type == "dictionary") {
return gin::ConvertToV8(isolate(), NSDictionaryToDictionaryValue(
[defaults dictionaryForKey:key]));
} else {
return v8::Undefined(isolate());
}
return GetUserDefaultImpl(isolate(), defaults, key, type);
}
v8::Local<v8::Value> SystemPreferences::GetUserDefaultInDomain(
const std::string& domain,
const std::string& key,
const std::string& type) {
base::scoped_nsobject<NSUserDefaults> defaults([[NSUserDefaults alloc]
initWithSuiteName:base::SysUTF8ToNSString(domain)]);
return GetUserDefaultImpl(isolate(), defaults, key, type);
}
void SystemPreferences::RegisterDefaults(gin_helper::Arguments* args) {
@@ -308,89 +391,20 @@ void SystemPreferences::RegisterDefaults(gin_helper::Arguments* args) {
}
}
void SystemPreferences::SetUserDefault(const std::string& name,
void SystemPreferences::SetUserDefault(const std::string& key,
const std::string& type,
gin_helper::Arguments* args) {
const auto throwConversionError = [&] {
args->ThrowError("Unable to convert value to: " + type);
};
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
NSString* key = base::SysUTF8ToNSString(name);
if (type == "string") {
std::string value;
if (!args->GetNext(&value)) {
throwConversionError();
return;
}
SetUserDefaultImpl(defaults, key, type, args);
}
[defaults setObject:base::SysUTF8ToNSString(value) forKey:key];
} else if (type == "boolean") {
bool value;
if (!args->GetNext(&value)) {
throwConversionError();
return;
}
[defaults setBool:value forKey:key];
} else if (type == "float") {
float value;
if (!args->GetNext(&value)) {
throwConversionError();
return;
}
[defaults setFloat:value forKey:key];
} else if (type == "integer") {
int value;
if (!args->GetNext(&value)) {
throwConversionError();
return;
}
[defaults setInteger:value forKey:key];
} else if (type == "double") {
double value;
if (!args->GetNext(&value)) {
throwConversionError();
return;
}
[defaults setDouble:value forKey:key];
} else if (type == "url") {
GURL value;
if (!args->GetNext(&value)) {
throwConversionError();
return;
}
if (NSURL* url = net::NSURLWithGURL(value)) {
[defaults setURL:url forKey:key];
}
} else if (type == "array") {
base::ListValue value;
if (!args->GetNext(&value)) {
throwConversionError();
return;
}
if (NSArray* array = ListValueToNSArray(value)) {
[defaults setObject:array forKey:key];
}
} else if (type == "dictionary") {
base::DictionaryValue value;
if (!args->GetNext(&value)) {
throwConversionError();
return;
}
if (NSDictionary* dict = DictionaryValueToNSDictionary(value)) {
[defaults setObject:dict forKey:key];
}
} else {
args->ThrowError("Invalid type: " + type);
return;
}
void SystemPreferences::SetUserDefaultInDomain(const std::string& domain,
const std::string& key,
const std::string& type,
gin_helper::Arguments* args) {
base::scoped_nsobject<NSUserDefaults> defaults([[NSUserDefaults alloc]
initWithSuiteName:base::SysUTF8ToNSString(domain)]);
SetUserDefaultImpl(defaults, key, type, args);
}
std::string SystemPreferences::GetAccentColor() {
@@ -633,9 +647,16 @@ v8::Local<v8::Promise> SystemPreferences::AskForMediaAccess(
return handle;
}
void SystemPreferences::RemoveUserDefault(const std::string& name) {
void SystemPreferences::RemoveUserDefault(const std::string& key) {
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
[defaults removeObjectForKey:base::SysUTF8ToNSString(name)];
[defaults removeObjectForKey:base::SysUTF8ToNSString(key)];
}
void SystemPreferences::RemoveUserDefaultInDomain(const std::string& domain,
const std::string& key) {
base::scoped_nsobject<NSUserDefaults> defaults([[NSUserDefaults alloc]
initWithSuiteName:base::SysUTF8ToNSString(domain)]);
[defaults removeObjectForKey:base::SysUTF8ToNSString(key)];
}
bool SystemPreferences::IsDarkMode() {

View File

@@ -68,30 +68,55 @@ describe('systemPreferences module', () => {
});
it('returns values for unknown user defaults', () => {
expect(systemPreferences.getUserDefault('UserDefaultDoesNotExist', 'boolean')).to.equal(false);
expect(systemPreferences.getUserDefault('UserDefaultDoesNotExist', 'integer')).to.equal(0);
expect(systemPreferences.getUserDefault('UserDefaultDoesNotExist', 'float')).to.equal(0);
expect(systemPreferences.getUserDefault('UserDefaultDoesNotExist', 'double')).to.equal(0);
expect(systemPreferences.getUserDefault('UserDefaultDoesNotExist', 'string')).to.equal('');
expect(systemPreferences.getUserDefault('UserDefaultDoesNotExist', 'url')).to.equal('');
expect(systemPreferences.getUserDefault('UserDefaultDoesNotExist', 'badtype' as any)).to.be.undefined('user default');
expect(systemPreferences.getUserDefault('UserDefaultDoesNotExist', 'array')).to.deep.equal([]);
expect(systemPreferences.getUserDefault('UserDefaultDoesNotExist', 'dictionary')).to.deep.equal({});
const KEY = 'UserDefaultDoesNotExist';
expect(systemPreferences.getUserDefault(KEY, 'boolean')).to.equal(false);
expect(systemPreferences.getUserDefault(KEY, 'integer')).to.equal(0);
expect(systemPreferences.getUserDefault(KEY, 'float')).to.equal(0);
expect(systemPreferences.getUserDefault(KEY, 'double')).to.equal(0);
expect(systemPreferences.getUserDefault(KEY, 'string')).to.equal('');
expect(systemPreferences.getUserDefault(KEY, 'url')).to.equal('');
expect(systemPreferences.getUserDefault(KEY, 'badtype' as any)).to.be.undefined('user default');
expect(systemPreferences.getUserDefault(KEY, 'array')).to.deep.equal([]);
expect(systemPreferences.getUserDefault(KEY, 'dictionary')).to.deep.equal({});
});
});
ifdescribe(process.platform === 'darwin')('systemPreferences.getUserDefaultInDomain(domain, key, type)', () => {
it('returns values for known user defaults', () => {
const value = systemPreferences.getUserDefaultInDomain('com.apple.notificationcenterui', 'doNotDisturb', 'boolean');
expect(value).to.be.a('boolean');
});
it('returns values for unknown user defaults', () => {
const DOMAIN = 'DomainDoesNotExist';
const KEY = 'UserDefaultDoesNotExist';
expect(systemPreferences.getUserDefaultInDomain(DOMAIN, KEY, 'boolean')).to.equal(false);
expect(systemPreferences.getUserDefaultInDomain(DOMAIN, KEY, 'integer')).to.equal(0);
expect(systemPreferences.getUserDefaultInDomain(DOMAIN, KEY, 'float')).to.equal(0);
expect(systemPreferences.getUserDefaultInDomain(DOMAIN, KEY, 'double')).to.equal(0);
expect(systemPreferences.getUserDefaultInDomain(DOMAIN, KEY, 'string')).to.equal('');
expect(systemPreferences.getUserDefaultInDomain(DOMAIN, KEY, 'url')).to.equal('');
expect(systemPreferences.getUserDefaultInDomain(DOMAIN, KEY, 'badtype' as any)).to.be.undefined('user default');
expect(systemPreferences.getUserDefaultInDomain(DOMAIN, KEY, 'array')).to.deep.equal([]);
expect(systemPreferences.getUserDefaultInDomain(DOMAIN, KEY, 'dictionary')).to.deep.equal({});
});
});
const TEST_CASES = [
['string', 'abc'],
['boolean', true],
['float', 2.5],
['double', 10.1],
['integer', 11],
['url', 'https://github.com/electron'],
['array', [1, 2, 3]],
['dictionary', { 'a': 1, 'b': 2 }]
];
ifdescribe(process.platform === 'darwin')('systemPreferences.setUserDefault(key, type, value)', () => {
const KEY = 'SystemPreferencesTest';
const TEST_CASES = [
['string', 'abc'],
['boolean', true],
['float', 2.5],
['double', 10.1],
['integer', 11],
['url', 'https://github.com/electron'],
['array', [1, 2, 3]],
['dictionary', { a: 1, b: 2 }]
];
it('sets values', () => {
for (const [type, value] of TEST_CASES) {
@@ -116,6 +141,33 @@ describe('systemPreferences module', () => {
});
});
ifdescribe(process.platform === 'darwin')('systemPreferences.setUserDefaultInDomain(domain, key, type, value)', () => {
const DOMAIN = 'org.electronjs.spec';
const KEY = 'SystemPreferencesTest';
it('sets values', () => {
for (const [type, value] of TEST_CASES) {
systemPreferences.setUserDefaultInDomain(DOMAIN, KEY, type as any, value as any);
const retrievedValue = systemPreferences.getUserDefaultInDomain(DOMAIN, KEY, type as any);
expect(retrievedValue).to.deep.equal(value);
}
});
it('throws when type and value conflict', () => {
for (const [type, value] of TEST_CASES) {
expect(() => {
systemPreferences.setUserDefaultInDomain(DOMAIN, KEY, type as any, typeof value === 'string' ? {} : 'foo' as any);
}).to.throw(`Unable to convert value to: ${type}`);
}
});
it('throws when type is not valid', () => {
expect(() => {
systemPreferences.setUserDefaultInDomain(DOMAIN, KEY, 'abc', 'foo');
}).to.throw('Invalid type: abc');
});
});
ifdescribe(process.platform === 'darwin')('systemPreferences.getSystemColor(color)', () => {
it('throws on invalid system colors', () => {
const color = 'bad-color';
@@ -231,7 +283,7 @@ describe('systemPreferences module', () => {
});
});
ifdescribe(process.platform === 'darwin')('systemPreferences.setUserDefault(key, type, value)', () => {
ifdescribe(process.platform === 'darwin')('systemPreferences.removeUserDefault(key)', () => {
it('removes keys', () => {
const KEY = 'SystemPreferencesTest';
systemPreferences.setUserDefault(KEY, 'string', 'foo');
@@ -244,6 +296,21 @@ describe('systemPreferences module', () => {
});
});
ifdescribe(process.platform === 'darwin')('systemPreferences.removeUserDefaultInDomain(domain, key)', () => {
const DOMAIN = 'org.electronjs.spec';
it('removes keys', () => {
const KEY = 'SystemPreferencesTest';
systemPreferences.setUserDefaultInDomain(DOMAIN, KEY, 'string', 'foo');
systemPreferences.removeUserDefaultInDomain(DOMAIN, KEY);
expect(systemPreferences.getUserDefaultInDomain(DOMAIN, KEY, 'string')).to.equal('');
});
it('does not throw for missing keys', () => {
systemPreferences.removeUserDefaultInDomain(DOMAIN, 'some-missing-key');
});
});
describe('systemPreferences.isInvertedColorScheme()', () => {
it('returns a boolean', () => {
expect(systemPreferences.isInvertedColorScheme()).to.be.a('boolean');