Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
f73e1e6
Cleanup tech debt for some of the DevTools server APIs
kenzieschmoll Aug 29, 2024
2cf9b57
Cleanup tech debt for the survey-related DevTools server APIs
kenzieschmoll Aug 29, 2024
19ecbce
remove lines
kenzieschmoll Aug 29, 2024
40bfedf
Merge branch 'master' of github.com:flutter/devtools into server-cleanup
kenzieschmoll Aug 29, 2024
9d290d0
Refactor the survey API handlers
kenzieschmoll Aug 29, 2024
16e53af
Merge branch 'master' of github.com:flutter/devtools into survey-hand…
kenzieschmoll Aug 29, 2024
3ca3ae1
fix comment
kenzieschmoll Aug 29, 2024
ef557d8
Migrate get & set preference APIs to use the standard server connection.
kenzieschmoll Aug 29, 2024
9e150ab
Merge branch 'master' of github.com:flutter/devtools into survey-hand…
kenzieschmoll Aug 30, 2024
1832f65
add todo
kenzieschmoll Aug 30, 2024
77efe6f
review comments
kenzieschmoll Aug 30, 2024
83d3841
add changelog
kenzieschmoll Aug 30, 2024
8b57b56
Fix api strings
kenzieschmoll Aug 30, 2024
e658b53
clean up
kenzieschmoll Aug 30, 2024
9d209cf
Increase integration test timeout
kenzieschmoll Aug 30, 2024
7c480d9
Fix type issue
kenzieschmoll Aug 31, 2024
52065ce
enable debug logging on integration tests
kenzieschmoll Sep 4, 2024
03860cb
Logs and update flutter version
kenzieschmoll Sep 4, 2024
846418b
More logging
kenzieschmoll Sep 4, 2024
35fc81c
ridiculous timeout
kenzieschmoll Sep 4, 2024
e8dfe08
Clean up
kenzieschmoll Sep 6, 2024
474c622
Merge branch 'master' of github.com:flutter/devtools into survey-hand…
kenzieschmoll Sep 6, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class FlutterDesktopStorage implements Storage {
}

@override
Future setValue(String key, String value) async {
Future<void> setValue(String key, String value) async {
_values[key] = value;

const encoder = JsonEncoder.withIndent(' ');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import 'package:web/web.dart' hide Storage;
import '../../../service/service_manager.dart';
import '../../globals.dart';
import '../../primitives/storage.dart';
import '../../server/server.dart' as server;
import '../../server/server_api_client.dart';

/// Return the url the application is launched from.
Expand All @@ -24,12 +25,14 @@ Future<String> initializePlatform() async {
}.toJS,
);

// TODO(kenz): this server connection initialized listeners that are never
// disposed, so this is likely leaking resources.
// Here, we try and initialize the connection between the DevTools web app and
// its local server. DevTools can be launched without the server however, so
// establishing this connection is a best-effort.
final connection = await DevToolsServerConnection.connect();
if (connection != null) {
setGlobal(Storage, ServerConnectionStorage(connection));
setGlobal(Storage, ServerConnectionStorage());
} else {
setGlobal(Storage, BrowserStorage());
}
Expand Down Expand Up @@ -89,18 +92,15 @@ void _sendKeyPressToParent(KeyboardEvent event) {
}

class ServerConnectionStorage implements Storage {
ServerConnectionStorage(this.connection);

final DevToolsServerConnection connection;

@override
Future<String?> getValue(String key) {
return connection.getPreferenceValue(key);
Future<String?> getValue(String key) async {
final value = await server.getPreferenceValue(key);
return value == null ? null : '$value';
}

@override
Future<void> setValue(String key, String value) async {
await connection.setPreferenceValue(key, value);
await server.setPreferenceValue(key, value);
}
}

Expand Down
67 changes: 48 additions & 19 deletions packages/devtools_app/lib/src/shared/preferences/preferences.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,23 @@ part '_performance_preferences.dart';

const _thirdPartyPathSegment = 'third_party';

/// DevTools preferences for UI-related settings.
enum _UiPreferences {
darkMode,
vmDeveloperMode;

String get storageKey => '$storagePrefix.$name';

static const storagePrefix = 'ui';
}

/// DevTools preferences for general settings.
///
/// These values are not stored in the DevTools storage file with a prefix.
enum _GeneralPreferences {
verboseLogging,
}

/// A controller for global application preferences.
class PreferencesController extends DisposableController
with AutoDisposeControllerMixin {
Expand All @@ -44,7 +61,6 @@ class PreferencesController extends DisposableController

final verboseLoggingEnabled =
ValueNotifier<bool>(Logger.root.level == verboseLoggingLevel);
static const _verboseLoggingStorageId = 'verboseLogging';

// TODO(https://github.com/flutter/devtools/issues/7860): Clean-up after
// Inspector V2 has been released.
Expand All @@ -65,44 +81,57 @@ class PreferencesController extends DisposableController

Future<void> init() async {
// Get the current values and listen for and write back changes.
final darkModeValue = await storage.getValue('ui.darkMode');
await _initDarkMode();
await _initVmDeveloperMode();
await _initVerboseLogging();

await inspector.init();
await memory.init();
await logging.init();
await performance.init();
await devToolsExtensions.init();

setGlobal(PreferencesController, this);
}

Future<void> _initDarkMode() async {
final darkModeValue =
await storage.getValue(_UiPreferences.darkMode.storageKey);
final useDarkMode = (darkModeValue == null && useDarkThemeAsDefault) ||
darkModeValue == 'true';
ga.impression(gac.devToolsMain, gac.startingTheme(darkMode: useDarkMode));
toggleDarkModeTheme(useDarkMode);
addAutoDisposeListener(darkModeEnabled, () {
storage.setValue('ui.darkMode', '${darkModeEnabled.value}');
storage.setValue(
_UiPreferences.darkMode.storageKey,
'${darkModeEnabled.value}',
);
});
}

Future<void> _initVmDeveloperMode() async {
final vmDeveloperModeValue = await boolValueFromStorage(
'ui.vmDeveloperMode',
_UiPreferences.vmDeveloperMode.storageKey,
defaultsTo: false,
);
toggleVmDeveloperMode(vmDeveloperModeValue);
addAutoDisposeListener(vmDeveloperModeEnabled, () {
storage.setValue('ui.vmDeveloperMode', '${vmDeveloperModeEnabled.value}');
storage.setValue(
_UiPreferences.vmDeveloperMode.storageKey,
'${vmDeveloperModeEnabled.value}',
);
});

await _initVerboseLogging();

await inspector.init();
await memory.init();
await logging.init();
await performance.init();
await devToolsExtensions.init();

setGlobal(PreferencesController, this);
}

Future<void> _initVerboseLogging() async {
final verboseLoggingEnabledValue = await boolValueFromStorage(
_verboseLoggingStorageId,
_GeneralPreferences.verboseLogging.name,
defaultsTo: false,
);
toggleVerboseLogging(verboseLoggingEnabledValue);
addAutoDisposeListener(verboseLoggingEnabled, () {
storage.setValue(
'verboseLogging',
_GeneralPreferences.verboseLogging.name,
verboseLoggingEnabled.value.toString(),
);
});
Expand All @@ -118,14 +147,14 @@ class PreferencesController extends DisposableController
super.dispose();
}

/// Change the value for the dark mode setting.
/// Change the value of the dark mode setting.
void toggleDarkModeTheme(bool? useDarkMode) {
if (useDarkMode != null) {
darkModeEnabled.value = useDarkMode;
}
}

/// Change the value for the VM developer mode setting.
/// Change the value of the VM developer mode setting.
void toggleVmDeveloperMode(bool? enableVmDeveloperMode) {
if (enableVmDeveloperMode != null) {
vmDeveloperModeEnabled.value = enableVmDeveloperMode;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright 2024 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be found
// in the LICENSE file.

part of 'server.dart';

/// Requests the DevTools preference for the [key].
///
/// This value is stored in the file '~/.flutter-devtools/.devtools'.
Future<Object?> getPreferenceValue(String key) async {
if (!isDevToolsServerAvailable) return null;

final uri = Uri(
path: PreferencesApi.getPreferenceValue,
queryParameters: {
PreferencesApi.preferenceKeyProperty: key,
},
);
final resp = await request(uri.toString());
if (resp?.statusOk ?? false) {
return jsonDecode(resp!.body);
} else {
logWarning(resp, PreferencesApi.getPreferenceValue);
return null;
}
}

/// Sets the DevTools preference [value] for the [key].
///
/// This value is stored in the file '~/.flutter-devtools/.devtools'.
Future<void> setPreferenceValue(String key, Object value) async {
if (!isDevToolsServerAvailable) return;

final uri = Uri(
path: PreferencesApi.setPreferenceValue,
queryParameters: {
PreferencesApi.preferenceKeyProperty: key,
apiParameterValueKey: value,
},
);
final resp = await request(uri.toString());
if (resp == null || !resp.statusOk) {
logWarning(resp, PreferencesApi.setPreferenceValue);
}
}
1 change: 1 addition & 0 deletions packages/devtools_app/lib/src/shared/server/server.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ part '_analytics_api.dart';
part '_app_size_api.dart';
part '_deep_links_api.dart';
part '_extensions_api.dart';
part '_preferences_api.dart';
part '_release_notes_api.dart';
part '_survey_api.dart';
part '_dtd_api.dart';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,23 +204,6 @@ class DevToolsServerConnection {
unawaited(_callMethod('disconnected'));
}

/// Retrieves a preference value from the DevTools configuration file at
/// ~/.flutter-devtools/.devtools.
Future<String?> getPreferenceValue(String key) {
return _callMethod('getPreferenceValue', {
'key': key,
});
}

/// Sets a preference value in the DevTools configuration file at
/// ~/.flutter-devtools/.devtools.
Future setPreferenceValue(String key, String value) async {
await _callMethod('setPreferenceValue', {
'key': key,
'value': value,
});
}

/// Allows the server to ping the client to see that it is definitely still
/// active and doesn't just appear to be connected because of SSE timeouts.
void ping() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class FlutterTestStorage implements Storage {
}

@override
Future setValue(String key, String value) async {
Future<void> setValue(String key, String value) async {
values[key] = value;
}
}
1 change: 1 addition & 0 deletions packages/devtools_shared/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* Deprecate `apiGetSurveyShownCount` in favor of `SurveyApi.getSurveyShownCount`.
* Deprecate `apiIncrementSurveyShownCount` in favor of `SurveyApi.incrementSurveyShownCount`.
* Support Chrome's new headless mode in the integration test runner.
* Add `PreferencesApi` to get and set preference values.

# 10.0.2
* Update dependency `web_socket_channel: '>=2.4.0 <4.0.0'`.
Expand Down
17 changes: 17 additions & 0 deletions packages/devtools_shared/lib/src/devtools_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,23 @@ const apiSetDevToolsEnabled = '${apiPrefix}setDevToolsEnabled';
/// in queryParameter:
const devToolsEnabledPropertyName = 'enabled';

abstract class PreferencesApi {
/// Returns the preference value in the DevTools store file for the key
/// specified by the [preferenceKeyProperty] query parameter.
static const getPreferenceValue = '${apiPrefix}getPreferenceValue';

/// Sets the preference value in the DevTools store file for the key
/// specified by the [preferenceKeyProperty] query parameter.
///
/// The value must be specified by the [apiParameterValueKey] query parameter.
static const setPreferenceValue = '${apiPrefix}setPreferenceValue';

/// The property name for the query parameter passed along with the
/// [getPreferenceValue] and [setPreferenceValue] requests that describes the
/// preference key in the DevTools store file.
static const preferenceKeyProperty = 'key';
}

@Deprecated(
'Use SurveyApi.setActiveSurvey instead. '
'This field will be removed in devtools_shared >= 11.0.0.',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright 2024 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// ignore_for_file: avoid_classes_with_only_static_members

part of '../server_api.dart';

abstract class _PreferencesApiHandler {
static shelf.Response getPreferenceValue<T>(
ServerApi api,
Map<String, String> queryParams,
DevToolsUsage devToolsStore,
) {
final missingRequiredParams = ServerApi._checkRequiredParameters(
[PreferencesApi.preferenceKeyProperty],
queryParams: queryParams,
api: api,
requestName: PreferencesApi.getPreferenceValue,
);
if (missingRequiredParams != null) return missingRequiredParams;

return _StorageHandler.handleGetStorageValue<T>(
api,
devToolsStore,
key: queryParams[PreferencesApi.preferenceKeyProperty]!,
);
}

static shelf.Response setPreferenceValue<T>(
ServerApi api,
Map<String, String> queryParams,
DevToolsUsage devToolsStore,
) {
final missingRequiredParams = ServerApi._checkRequiredParameters(
[PreferencesApi.preferenceKeyProperty, apiParameterValueKey],
queryParams: queryParams,
api: api,
requestName: PreferencesApi.setPreferenceValue,
);
if (missingRequiredParams != null) return missingRequiredParams;

return _StorageHandler.handleSetStorageValue<T>(
api,
devToolsStore,
key: queryParams[PreferencesApi.preferenceKeyProperty]!,
value: queryParams[apiParameterValueKey]! as T,
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,10 @@ abstract class _StorageHandler {
ServerApi api,
DevToolsUsage devToolsStore, {
required String key,
required T defaultValue,
T? defaultValue,
}) {
final T value = (devToolsStore.properties[key] as T?) ?? defaultValue;
return ServerApi._encodeResponse(
value,
api: api,
);
final T? value = (devToolsStore.properties[key] as T?) ?? defaultValue;
return ServerApi._encodeResponse(value, api: api);
}

static shelf.Response handleSetStorageValue<T>(
Expand Down
16 changes: 16 additions & 0 deletions packages/devtools_shared/lib/src/server/server_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ part 'handlers/_deeplink.dart';
part 'handlers/_devtools_extensions.dart';
part 'handlers/_dtd.dart';
part 'handlers/_general.dart';
part 'handlers/_preferences.dart';
part 'handlers/_release_notes.dart';
part 'handlers/_storage.dart';
part 'handlers/_survey.dart';
Expand Down Expand Up @@ -113,6 +114,21 @@ class ServerApi {
}
return _encodeResponse(_devToolsStore.analyticsEnabled, api: api);

// ----- Preferences api. -----
case PreferencesApi.getPreferenceValue:
return _PreferencesApiHandler.getPreferenceValue(
api,
queryParams,
_devToolsStore,
);

case PreferencesApi.setPreferenceValue:
return _PreferencesApiHandler.setPreferenceValue(
api,
queryParams,
_devToolsStore,
);

// ----- DevTools survey api. -----

case SurveyApi.setActiveSurvey:
Expand Down