Skip to content

Commit

Permalink
Add an example directory to devtools_app_shared (#6230)
Browse files Browse the repository at this point in the history
  • Loading branch information
kenzieschmoll committed Aug 22, 2023
1 parent 0dfdc8e commit 2308099
Show file tree
Hide file tree
Showing 11 changed files with 470 additions and 55 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ class MockDartToolingApi extends DartToolingApiImpl {
final Stream<String> log;

/// Simulates executing a VS Code command requested by the embedded panel.
Future<void> initialize() async {
void initialize() {
connectDevices();
}

Expand Down
2 changes: 1 addition & 1 deletion packages/devtools_app_shared/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ void main() {
// Use the [connectedState] notifier to listen for connection updates.
serviceManager.connectedState.addListener(() {
if (connectedState.value.connected) {
if (serviceManager.connectedState.value.connected) {
print('Manager connected to VM service');
} else {
print('Manager not connected to VM service');
Expand Down
67 changes: 67 additions & 0 deletions packages/devtools_app_shared/example/service_example.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Copyright 2023 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: unused_local_variable

import 'dart:async';

import 'package:devtools_app_shared/service.dart';
import 'package:devtools_app_shared/service_extensions.dart' as extensions;
import 'package:devtools_shared/service.dart';
import 'package:flutter/foundation.dart';
import 'package:vm_service/vm_service.dart';

void main() async {
final serviceManager = ServiceManager();

// Example: use [connectedState] to listen for connection updates.
serviceManager.connectedState.addListener(() {
if (serviceManager.connectedState.value.connected) {
print('Manager connected to VM service');
} else {
print('Manager not connected to VM service');
}
});

// Example: establish a vm service connection.
// To get a [VmService] object from a vm service URI, consider importing
// `package:devtools_shared/service.dart` from `package:devtools_shared`.
const someVmServiceUri = 'http://127.0.0.1:60851/fH-kAEXc7MQ=/';
final finishedCompleter = Completer<void>();
final vmService = await connect<VmService>(
uri: Uri.parse(someVmServiceUri),
finishedCompleter: finishedCompleter,
createService: ({
// ignore: avoid-dynamic, code needs to match API from VmService.
required Stream<dynamic> /*String|List<int>*/ inStream,
required void Function(String message) writeMessage,
required Uri connectedUri,
}) {
return VmService(inStream, writeMessage);
},
);

await serviceManager.vmServiceOpened(
vmService,
onClosed: finishedCompleter.future,
);

/// Example: Get a service extension state.
final ValueListenable<ServiceExtensionState> performanceOverlayEnabled =
serviceManager.serviceExtensionManager.getServiceExtensionState(
extensions.performanceOverlay.extension,
);

// Example: Set a service extension state.
await serviceManager.serviceExtensionManager.setServiceExtensionState(
extensions.performanceOverlay.extension,
enabled: true,
value: true,
);

// Example: Access isolates.
final myIsolate = serviceManager.isolateManager.mainIsolate.value;

// Etc.
}
31 changes: 31 additions & 0 deletions packages/devtools_app_shared/example/ui/common_example.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright 2023 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.

import 'package:devtools_app_shared/ui.dart' as devtools_shared_ui;
import 'package:flutter/material.dart';

class ExampleWidget extends StatelessWidget {
const ExampleWidget({super.key});

@override
Widget build(BuildContext context) {
return devtools_shared_ui.RoundedOutlinedBorder(
child: Column(
children: [
const devtools_shared_ui.AreaPaneHeader(
roundedTopBorder: false,
includeTopBorder: false,
title: Text('This is a section header'),
),
Expanded(
child: Text(
'Foo',
style: Theme.of(context).subtleTextStyle, // Shared style
),
),
],
),
);
}
}
38 changes: 38 additions & 0 deletions packages/devtools_app_shared/example/ui/dialog_example.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright 2023 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.

import 'package:devtools_app_shared/ui.dart' as devtools_shared_ui;
import 'package:flutter/material.dart';

/// Example of using a [DevToolsDialog] widget from
/// 'package:devtools_app_shared/ui.dart'.
class MyDialog extends StatelessWidget {
const MyDialog({super.key});

@override
Widget build(BuildContext context) {
return devtools_shared_ui.DevToolsDialog(
title: const devtools_shared_ui.DialogTitleText('My Cool Dialog'),
content: const Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Here is the body of my dialog.'),
SizedBox(height: devtools_shared_ui.denseSpacing),
Text('It communicates something important'),
],
),
actions: [
devtools_shared_ui.DialogTextButton(
onPressed: () {
// Do someting and then remove the dialog.
Navigator.of(context).pop(devtools_shared_ui.dialogDefaultContext);
},
child: const Text('DO SOMETHING'),
),
const devtools_shared_ui.DialogCancelButton(),
],
);
}
}
73 changes: 73 additions & 0 deletions packages/devtools_app_shared/example/ui/split_example.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Copyright 2023 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.

import 'package:devtools_app_shared/ui.dart' as devtools_shared_ui;
import 'package:flutter/material.dart';

/// Example of using the [Split] widget from
/// 'package:devtools_app_shared/ui.dart' with two children laid across a
/// horizontal axis.
///
/// This example does not specify the [Split.splitters] parameter, so a
/// default splitter is used.
class SplitExample extends StatelessWidget {
const SplitExample({super.key});

@override
Widget build(BuildContext context) {
return devtools_shared_ui.Split(
axis: Axis.horizontal,
initialFractions: const [0.3, 0.7],
minSizes: const [50.0, 100.0],
children: const [
Text('Left side'),
Text('Right side'),
],
);
}
}

/// Example of using the [Split] widget from
/// 'package:devtools_app_shared/ui.dart' with three children laid across a
/// vertical axis.
///
/// This example uses custom splitters.
class MultiSplitExample extends StatelessWidget {
const MultiSplitExample({super.key});

@override
Widget build(BuildContext context) {
return devtools_shared_ui.Split(
axis: Axis.vertical,
initialFractions: const [0.3, 0.3, 0.4],
minSizes: const [50.0, 50.0, 100.0],
splitters: const [
CustomSplitter(),
CustomSplitter(),
],
children: const [
Text('Top'),
Text('Middle'),
Text('Bottom'),
],
);
}
}

class CustomSplitter extends StatelessWidget implements PreferredSizeWidget {
const CustomSplitter({super.key});

static const _size = 50.0;

@override
Widget build(BuildContext context) {
return const SizedBox(
height: _size,
child: Icon(Icons.front_hand),
);
}

@override
Size get preferredSize => const Size.fromHeight(_size);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// Copyright 2023 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.

import 'package:devtools_app_shared/utils.dart';
import 'package:flutter/widgets.dart';

/// This is an example of a [StatefulWidget] that uses the [AutoDisposeMixin] on
/// its state.
///
/// [AutoDisposeMixin] is exposed by 'package:devtools_app_shared/utils.dart'.
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({super.key, required this.someNotifier});

final ValueNotifier<String> someNotifier;

@override
State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}

// This is a State class that mixes in [AutoDisoposeMixin].
class _MyStatefulWidgetState extends State<MyStatefulWidget>
with AutoDisposeMixin {
late final MyController controller;
late String foo;

@override
void initState() {
super.initState();
_init();
}

@override
void didUpdateWidget(MyStatefulWidget oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.someNotifier != widget.someNotifier) {
_init();
}
}

@override
void dispose() {
controller.dispose();
super.dispose();
}

void _init() {
// This kicks off initialization in [controller] which uses the
// [AutoDisposeControllerMixin].
controller = MyController(widget.someNotifier)..init();

// Cancel any existing listeners in situations like this where we could be
// "re-initializing" in [didUpdateWidget].
cancelListeners();

foo = widget.someNotifier.value;

// Adds a listener to [widget.someNotifier] that will be automatically
// disposed as part of this stateful widget lifecycle.
addAutoDisposeListener(widget.someNotifier, () {
setState(() {
foo = widget.someNotifier.value;
});
});
}

@override
Widget build(BuildContext context) {
return Text(foo);
}
}

/// This is an example of a controller that uses the
/// [AutoDisposeControllerMixin] exposed by
/// 'package:devtools_app_shared/utils.dart'.
///
/// When [dispose] is called on this controller, any listeners or stream
/// subscriptions added using the [AutoDisposeControllerMixin] will be disposed
/// or canceled.
class MyController extends DisposableController
with AutoDisposeControllerMixin {
MyController(this.notifier);

final ValueNotifier<String> notifier;

void init() {
addAutoDisposeListener(notifier, () {
// Do something.
});
}
}
30 changes: 30 additions & 0 deletions packages/devtools_app_shared/example/utils/globals_example.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright 2023 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.

import 'package:devtools_app_shared/utils.dart';

void main() {
setAndAccessGlobal();
}

/// This method demonstrates setting and accessing globals, which is
/// functionality exposed by 'package:devtools_app_shared/utils.dart'.
void setAndAccessGlobal() {
// Creates a globally accessible variable (`globals[ServiceManager]`);
setGlobal(MyCoolClass, MyCoolClass());
// Access the variable directory from [globals].
final coolClassFromGlobals = globals[MyCoolClass] as MyCoolClass;
coolClassFromGlobals.foo();

// OR (recommended) access the global from a top level getter.
coolClass.foo();
}

MyCoolClass get coolClass => globals[MyCoolClass] as MyCoolClass;

class MyCoolClass {
void foo() {
print('foo');
}
}
35 changes: 35 additions & 0 deletions packages/devtools_app_shared/example/utils/list_example.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright 2023 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.

import 'package:devtools_app_shared/utils.dart';
import 'package:flutter/widgets.dart';

void main() {
useListValueNotifier();
}

/// This is an example of using the [ListValueNotifier] that is exposed from
/// 'package:devtools_app_shared/utils.dart'.
///
/// A [ListValueNotifier] will holds a list object, and will notify listeners
/// on modifications to the list.
///
/// This should be used in place of ValueNotifier<List<Object>> when list
/// updates should notify listeners, and not just changing the notifier's value
/// with a new list.
void useListValueNotifier() {
final myListNotifier = ListValueNotifier<int>([1, 2, 3]);

// These calls will notify all listeners of [myListNotifier].
myListNotifier.add(4);
myListNotifier.removeAt(0);
// ...

// As opposed to:
final myValueNotifierWithAList = ValueNotifier<List<int>>([1, 2, 3]);

// These calls will not notify listeners of [myValueNotifierWithAList]
myValueNotifierWithAList.value.add(4);
myValueNotifierWithAList.value.removeAt(0);
}
Loading

0 comments on commit 2308099

Please sign in to comment.