Skip to content

Commit a088604

Browse files
lia-viamnjooma
andauthored
RSDK-10304: Button component (#363)
* initial commit of claude button * add to registry * dart format * add button widget * missing semicolon * Fix some package issues * update server intialization * missing import --------- Co-authored-by: Naveed Jooma <[email protected]>
1 parent cf1c20c commit a088604

File tree

11 files changed

+346
-2
lines changed

11 files changed

+346
-2
lines changed

Diff for: example/viam_robot_example_app/lib/main.dart

+5
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import 'package:flutter_dotenv/flutter_dotenv.dart';
33
import 'package:viam_sdk/viam_sdk.dart';
44
import 'package:viam_sdk/widgets.dart';
55

6+
import 'screens/button.dart';
67
import 'screens/screens.dart';
78

89
void main() async {
@@ -88,6 +89,7 @@ class _MyHomePageState extends State<MyHomePage> {
8889
return [
8990
Base.subtype.resourceSubtype,
9091
Board.subtype.resourceSubtype,
92+
Button.subtype.resourceSubtype,
9193
Camera.subtype.resourceSubtype,
9294
Gripper.subtype.resourceSubtype,
9395
Motor.subtype.resourceSubtype,
@@ -113,6 +115,9 @@ class _MyHomePageState extends State<MyHomePage> {
113115
if (rname.subtype == Board.subtype.resourceSubtype) {
114116
return BoardScreen(board: Board.fromRobot(_robot, rname.name), resourceName: rname);
115117
}
118+
if (rname.subtype == Button.subtype.resourceSubtype) {
119+
return ButtonScreen(button: Button.fromRobot(_robot, rname.name), resourceName: rname);
120+
}
116121
if (rname.subtype == Camera.subtype.resourceSubtype) {
117122
return StreamScreen(camera: Camera.fromRobot(_robot, rname.name), client: _getStream(rname), resourceName: rname);
118123
}
+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:flutter/services.dart';
3+
4+
import 'package:viam_sdk/viam_sdk.dart';
5+
import 'package:viam_sdk/widgets.dart';
6+
7+
class ButtonScreen extends StatelessWidget {
8+
final Button button;
9+
final ResourceName resourceName;
10+
11+
const ButtonScreen({super.key, required this.button, required this.resourceName});
12+
13+
@override
14+
Widget build(BuildContext context) {
15+
return Scaffold(
16+
appBar: AppBar(
17+
title: Text(resourceName.name.toUpperCase()),
18+
),
19+
body: Center(
20+
child: Column(
21+
children: [
22+
const SizedBox(height: 8),
23+
Text(
24+
'${resourceName.namespace}:${resourceName.type}:${resourceName.subtype}/${resourceName.name}',
25+
style: const TextStyle(fontWeight: FontWeight.w300),
26+
),
27+
const SizedBox(height: 8),
28+
ViamButtonWidget(button: button),
29+
],
30+
),
31+
),
32+
);
33+
}
34+
}

Diff for: lib/src/components/button/button.dart

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import '../../gen/common/v1/common.pb.dart';
2+
import '../../resource/base.dart';
3+
import '../../robot/client.dart';
4+
5+
/// {@category Components}
6+
/// Button represents a button component.
7+
///
8+
/// For more information, see [Button component](https://docs.viam.com/dev/reference/apis/components/button/).
9+
abstract class Button extends Resource {
10+
static const Subtype subtype = Subtype(resourceNamespaceRDK, resourceTypeComponent, 'button');
11+
12+
/// Push the button.
13+
///
14+
/// ```
15+
/// await myButton.push();
16+
/// ```
17+
///
18+
/// For more information, see [Button component](https://docs.viam.com/dev/reference/apis/components/button/#push).
19+
Future<void> push({Map<String, dynamic>? extra});
20+
21+
/// Get the [ResourceName] for this [Button] with the given [name].
22+
///
23+
/// ```
24+
/// // Example:
25+
/// var name = Button.getResourceName('my_button');
26+
/// ```
27+
///
28+
/// For more information, see [Button component](https://docs.viam.com/dev/reference/apis/components/button/#getresourcename).
29+
static ResourceName getResourceName(String name) {
30+
return Button.subtype.getResourceName(name);
31+
}
32+
33+
/// Get the [Button] named [name] from the provided robot.
34+
///
35+
/// ```
36+
/// final myButton = Button.fromRobot(myRobotClient, "my_button");
37+
/// ```
38+
///
39+
/// For more information, see [Button component](https://docs.viam.com/dev/reference/apis/components/button/).
40+
static Button fromRobot(RobotClient robot, String name) {
41+
return robot.getResource(Button.getResourceName(name));
42+
}
43+
}

Diff for: lib/src/components/button/client.dart

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import 'package:grpc/grpc_connection_interface.dart';
2+
3+
import '../../gen/common/v1/common.pb.dart';
4+
import '../../gen/component/button/v1/button.pbgrpc.dart';
5+
import '../../gen/google/protobuf/struct.pb.dart';
6+
import '../../resource/base.dart';
7+
import '../../utils.dart';
8+
import 'button.dart';
9+
10+
/// {@category Components}
11+
/// gRPC client for the [Button] component.
12+
class ButtonClient extends Button implements ResourceRPCClient {
13+
@override
14+
final String name;
15+
16+
@override
17+
ClientChannelBase channel;
18+
19+
@override
20+
ButtonServiceClient get client => ButtonServiceClient(channel);
21+
22+
ButtonClient(this.name, this.channel);
23+
24+
@override
25+
Future<void> push({Map<String, dynamic>? extra}) async {
26+
final request = PushRequest()
27+
..name = name
28+
..extra = extra?.toStruct() ?? Struct();
29+
await client.push(request);
30+
}
31+
32+
@override
33+
Future<Map<String, dynamic>> doCommand(Map<String, dynamic> command) async {
34+
final request = DoCommandRequest()
35+
..name = name
36+
..command = command.toStruct();
37+
final response = await client.doCommand(request);
38+
return response.result.toMap();
39+
}
40+
}

Diff for: lib/src/components/button/service.dart

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import 'package:grpc/grpc.dart';
2+
3+
import '../../gen/common/v1/common.pb.dart';
4+
import '../../gen/component/button/v1/button.pbgrpc.dart';
5+
import '../../resource/manager.dart';
6+
import '../../utils.dart';
7+
import 'button.dart';
8+
9+
/// {@category Components}
10+
/// gRPC Service for a [Button]
11+
class ButtonService extends ButtonServiceBase {
12+
final ResourceManager _manager;
13+
14+
ButtonService(this._manager);
15+
16+
Button _fromManager(String name) {
17+
try {
18+
return _manager.getResource(Button.getResourceName(name));
19+
} catch (e) {
20+
throw GrpcError.notFound(e.toString());
21+
}
22+
}
23+
24+
@override
25+
Future<PushResponse> push(ServiceCall call, PushRequest request) async {
26+
final button = _fromManager(request.name);
27+
await button.push(extra: request.extra.toMap());
28+
return PushResponse();
29+
}
30+
31+
@override
32+
Future<DoCommandResponse> doCommand(ServiceCall call, DoCommandRequest request) async {
33+
final button = _fromManager(request.name);
34+
final result = await button.doCommand(request.command.toMap());
35+
return DoCommandResponse()..result = result.toStruct();
36+
}
37+
}

Diff for: lib/src/resource/registry.dart

+3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import '../components/base/base.dart';
66
import '../components/base/client.dart';
77
import '../components/board/board.dart';
88
import '../components/board/client.dart';
9+
import '../components/button/button.dart';
10+
import '../components/button/client.dart';
911
import '../components/camera/camera.dart';
1012
import '../components/camera/client.dart';
1113
import '../components/gantry/client.dart';
@@ -62,6 +64,7 @@ class Registry {
6264
registerSubtype(ResourceRegistration(Arm.subtype, (name, channel) => ArmClient(name, channel)));
6365
registerSubtype(ResourceRegistration(Board.subtype, (name, channel) => BoardClient(name, channel)));
6466
registerSubtype(ResourceRegistration(Base.subtype, (name, channel) => BaseClient(name, channel)));
67+
registerSubtype(ResourceRegistration(Button.subtype, (name, channel) => ButtonClient(name, channel)));
6568
registerSubtype(ResourceRegistration(Camera.subtype, (name, channel) => CameraClient(name, channel)));
6669
registerSubtype(ResourceRegistration(Gantry.subtype, (name, channel) => GantryClient(name, channel)));
6770
registerSubtype(ResourceRegistration(Generic.subtype, (name, channel) => GenericClient(name, channel)));

Diff for: lib/viam_sdk.dart

+2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ export 'src/components/base/base.dart';
1515
export 'src/components/base/client.dart';
1616
export 'src/components/board/board.dart';
1717
export 'src/components/board/client.dart';
18+
export 'src/components/button/button.dart';
19+
export 'src/components/button/client.dart';
1820
export 'src/components/camera/camera.dart';
1921
export 'src/components/camera/client.dart';
2022
export 'src/components/gantry/client.dart';

Diff for: lib/widgets.dart

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export 'widgets/multi_camera_stream.dart';
55
export 'widgets/refreshable_data_table.dart';
66
export 'widgets/resources/base.dart';
77
export 'widgets/resources/board.dart';
8+
export 'widgets/resources/button.dart';
89
export 'widgets/resources/gripper.dart';
910
export 'widgets/resources/motor.dart';
1011
export 'widgets/resources/sensor.dart';

Diff for: lib/widgets/resources/button.dart

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import 'package:flutter/material.dart';
2+
3+
import '../../viam_sdk.dart';
4+
import '../button.dart';
5+
6+
class ViamButtonWidget extends StatefulWidget {
7+
final Button button;
8+
9+
const ViamButtonWidget({super.key, required this.button});
10+
11+
@override
12+
State<ViamButtonWidget> createState() {
13+
return _ViamButtonWidgetState();
14+
}
15+
}
16+
17+
class _ViamButtonWidgetState extends State<ViamButtonWidget> {
18+
bool isLoading = false;
19+
Error? error;
20+
21+
Future<void> _pushButton() async {
22+
try {
23+
setState(() {
24+
isLoading = true;
25+
error = null;
26+
});
27+
await widget.button.push();
28+
} catch (e) {
29+
setState(() {
30+
error = e as Error;
31+
});
32+
} finally {
33+
if (mounted) {
34+
setState(() {
35+
isLoading = false;
36+
});
37+
}
38+
}
39+
}
40+
41+
@override
42+
Widget build(BuildContext context) {
43+
return Column(
44+
children: [
45+
ViamButton(
46+
text: 'Push',
47+
onPressed: isLoading ? null : _pushButton,
48+
),
49+
if (error != null)
50+
Padding(
51+
padding: const EdgeInsets.only(top: 8.0),
52+
child: Text('Error: $error', style: const TextStyle(color: Colors.red)),
53+
),
54+
],
55+
);
56+
}
57+
}

Diff for: lib/widgets/resources/switch.dart

+6-2
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@ class _ViamSwitchWidgetState extends State<ViamSwitchWidget> {
3636
});
3737
}
3838
} catch (e) {
39-
error = e as Error;
39+
setState(() {
40+
error = e as Error;
41+
});
4042
}
4143
}
4244

@@ -45,7 +47,9 @@ class _ViamSwitchWidgetState extends State<ViamSwitchWidget> {
4547
await widget.nswitch.setPosition(position);
4648
await _getPosition();
4749
} catch (e) {
48-
error = e as Error;
50+
setState(() {
51+
error = e as Error;
52+
});
4953
}
5054
}
5155

0 commit comments

Comments
 (0)