Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Open in IDX feature #2995

Merged
merged 5 commits into from
Jun 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
30 changes: 30 additions & 0 deletions pkgs/dart_services/lib/src/common_server.dart
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,36 @@ class CommonServerApi {
return ok(version().toJson());
}

@Route.post('$apiPrefix/openInIDX')
Future<Response> openInIdx(Request request, String apiVersion) async {
final code = api.OpenInIdxRequest.fromJson(await request.readAsJson()).code;
final idxUrl = Uri.parse('https://idx.google.com/run.api');

final data = {
'project[files][lib/main.dart]': code,
devoncarew marked this conversation as resolved.
Show resolved Hide resolved
'project[settings]': '{"baselineEnvironment": "flutter"}',
};
try {
final response = await http.post(
idxUrl,
body: data,
devoncarew marked this conversation as resolved.
Show resolved Hide resolved
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
);

if (response.statusCode == 302) {
return ok(api.OpenInIdxResponse(idxUrl: response.headers['location']!)
.toJson());
} else {
return Response.internalServerError(
body:
'Failed to read response from IDX server. Response: $response');
}
} catch (error) {
return Response.internalServerError(
body: 'Failed to read response from IDX server. Error: $error');
}
}

static final String? geminiApiKey = Platform.environment['GEMINI_API_KEY'];
http.Client? geminiHttpClient;

Expand Down
5 changes: 5 additions & 0 deletions pkgs/dart_services/lib/src/common_server.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

34 changes: 34 additions & 0 deletions pkgs/dartpad_shared/lib/model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,40 @@ class GeminiResponse {
String toString() => 'GeminiResponse[response=$response]';
}

@JsonSerializable()
class OpenInIdxRequest {
final String code;

OpenInIdxRequest({
required this.code,
});

factory OpenInIdxRequest.fromJson(Map<String, dynamic> json) =>
_$OpenInIdxRequestFromJson(json);

Map<String, dynamic> toJson() => _$OpenInIdxRequestToJson(this);

@override
String toString() => 'OpenInIdxRequest [${code.substring(0, 10)} (...)';
}

@JsonSerializable()
class OpenInIdxResponse {
final String idxUrl;

OpenInIdxResponse({
required this.idxUrl,
});

factory OpenInIdxResponse.fromJson(Map<String, dynamic> json) =>
_$OpenInIdxResponseFromJson(json);

Map<String, dynamic> toJson() => _$OpenInIdxResponseToJson(this);

@override
String toString() => 'OpenInIdxResponse [$idxUrl]';
}

@JsonSerializable()
class PackageInfo {
final String name;
Expand Down
20 changes: 20 additions & 0 deletions pkgs/dartpad_shared/lib/model.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions pkgs/dartpad_shared/lib/services.dart
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ class ServicesClient {
Future<CompileDDCResponse> compileDDC(CompileRequest request) =>
_requestPost('compileDDC', request.toJson(), CompileDDCResponse.fromJson);

Future<OpenInIdxResponse> openInIdx(OpenInIdxRequest request) =>
_requestPost('openInIDX', request.toJson(), OpenInIdxResponse.fromJson);

/// Note: this API is experimental and could change or be removed at any time.
@experimental
Future<GeminiResponse> gemini(SourceRequest request) =>
Expand Down
Binary file added pkgs/dartpad_ui/assets/idx_192.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
66 changes: 43 additions & 23 deletions pkgs/dartpad_ui/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -703,19 +703,8 @@ class DartPadAppBar extends StatelessWidget implements PreferredSizeWidget {
actions: [
// Hide the Install SDK button when the screen width is too small.
if (constraints.maxWidth > smallScreenWidth)
TextButton(
onPressed: () {
url_launcher.launchUrl(
Uri.parse('https://docs.flutter.dev/get-started/install'),
);
},
child: const Row(
children: [
Text('Install SDK'),
SizedBox(width: denseSpacing),
Icon(Icons.launch, size: 18),
],
),
ContinueInMenu(
openInIdx: _openInIDX,
),
const SizedBox(width: denseSpacing),
_BrightnessButton(
Expand All @@ -732,6 +721,13 @@ class DartPadAppBar extends StatelessWidget implements PreferredSizeWidget {
Size get preferredSize => bottom == null
? const Size(double.infinity, 56.0)
: const Size(double.infinity, 112.0);

Future<void> _openInIDX() async {
final code = appModel.sourceCodeController.text;
final request = OpenInIdxRequest(code: code);
final response = await appServices.services.openInIdx(request);
url_launcher.launchUrl(Uri.parse(response.idxUrl));
}
}

class EditorWithButtons extends StatelessWidget {
Expand Down Expand Up @@ -1110,21 +1106,13 @@ class OverflowMenu extends StatelessWidget {

static const _menuItems = [
(
label: 'dart.dev',
uri: 'https://dart.dev',
),
(
label: 'flutter.dev',
uri: 'https://flutter.dev',
label: 'Install SDK',
uri: 'https://docs.flutter.dev/get-started/install',
),
(
label: 'Sharing guide',
uri: 'https:/dart-lang/dart-pad/wiki/Sharing-Guide'
),
(
label: 'DartPad on GitHub',
uri: 'https:/dart-lang/dart-pad',
),
];

@override
Expand Down Expand Up @@ -1157,6 +1145,38 @@ class OverflowMenu extends StatelessWidget {
}
}

class ContinueInMenu extends StatelessWidget {
final VoidCallback openInIdx;
const ContinueInMenu({super.key, required this.openInIdx});

@override
Widget build(BuildContext context) {
return MenuAnchor(
builder: (context, MenuController controller, Widget? child) {
return TextButton.icon(
onPressed: () => controller.toggleMenuState(),
icon: const Icon(Icons.file_download_outlined),
label: const Text('Open in'),
);
},
menuChildren: [
...[
MenuItemButton(
trailingIcon: const Logo(type: 'idx'),
onPressed: () {
openInIdx();
},
child: const Padding(
padding: EdgeInsets.fromLTRB(0, 0, 32, 0),
child: Text('IDX'),
),
),
].map((widget) => PointerInterceptor(child: widget))
],
);
}
}

class KeyBindingsTable extends StatelessWidget {
final List<(String, List<ShortcutActivator>)> bindings;

Expand Down
2 changes: 1 addition & 1 deletion pkgs/dartpad_ui/lib/samples.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pkgs/dartpad_ui/lib/widgets.dart
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ final class Logo extends StatelessWidget {
'flutter' => 'assets/flutter_logo_192.png',
'flame' => 'assets/flame_logo_192.png',
'gemini' => 'assets/gemini_sparkle_192.png',
'idx' => 'assets/idx_192.png',
_ => 'assets/dart_logo_192.png',
};
return Image.asset(assetPath, width: width);
Expand Down
1 change: 1 addition & 0 deletions pkgs/dartpad_ui/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ flutter:
- assets/flame_logo_192.png
- assets/flutter_logo_192.png
- assets/gemini_sparkle_192.png
- assets/idx_192.png
- assets/RobotoMono-Bold.ttf
- assets/RobotoMono-Regular.ttf

Expand Down
2 changes: 1 addition & 1 deletion pkgs/samples/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class MyApp extends StatelessWidget {
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
colorSchemeSeed: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
Expand Down