Skip to content

Commit

Permalink
support flutter samples (sample_id) (#2787)
Browse files Browse the repository at this point in the history
* support flutter samples (sample_id)

* review feedback

* use switch statement
  • Loading branch information
devoncarew authored Jan 11, 2024
1 parent 982b94f commit ccc88ca
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 39 deletions.
34 changes: 34 additions & 0 deletions pkgs/sketch_pad/lib/flutter_samples.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
// for details. 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:http/http.dart' as http;

class FlutterSampleLoader {
final http.Client client = http.Client();

Future<String> loadFlutterSample({
required String sampleId,
String? channel,
}) async {
// There are only two hosted versions of the docs: master/main and stable.
final sampleUrl = switch (channel) {
'master' => 'https://main-api.flutter.dev/snippets/$sampleId.dart',
'main' => 'https://main-api.flutter.dev/snippets/$sampleId.dart',
_ => 'https://api.flutter.dev/snippets/$sampleId.dart',
};

final response = await client.get(Uri.parse(sampleUrl));

if (response.statusCode != 200) {
throw Exception('Unable to load sample '
'(${response.statusCode} ${response.reasonPhrase}})');
}

return response.body;
}

void dispose() {
client.close();
}
}
30 changes: 19 additions & 11 deletions pkgs/sketch_pad/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@ import 'utils.dart';
import 'versions.dart';
import 'widgets.dart';

// TODO: explore using the monaco editor

// TODO: show documentation on hover

// TODO: implement find / find next
Expand Down Expand Up @@ -112,8 +110,9 @@ class _DartPadAppState extends State<DartPadApp> {
}

Widget _homePageBuilder(BuildContext context, GoRouterState state) {
final idParam = state.uri.queryParameters['id'];
final sampleParam = state.uri.queryParameters['sample'];
final gistId = state.uri.queryParameters['id'];
final builtinSampleId = state.uri.queryParameters['sample'];
final flutterSampleId = state.uri.queryParameters['sample_id'];
final channelParam = state.uri.queryParameters['channel'];
final embedMode = state.uri.queryParameters['embed'] == 'true';
final runOnLoad = state.uri.queryParameters['run'] == 'true';
Expand All @@ -123,8 +122,9 @@ class _DartPadAppState extends State<DartPadApp> {
initialChannel: channelParam,
embedMode: embedMode,
runOnLoad: runOnLoad,
sampleId: sampleParam,
gistId: idParam,
gistId: gistId,
builtinSampleId: builtinSampleId,
flutterSampleId: flutterSampleId,
handleBrightnessChanged: handleBrightnessChanged,
);
}
Expand Down Expand Up @@ -171,21 +171,27 @@ class _DartPadAppState extends State<DartPadApp> {
class DartPadMainPage extends StatefulWidget {
final String title;
final String? initialChannel;
final String? sampleId;
final String? gistId;
final bool embedMode;
final bool runOnLoad;
final void Function(BuildContext, bool) handleBrightnessChanged;
final String? gistId;
final String? builtinSampleId;
final String? flutterSampleId;

DartPadMainPage({
required this.title,
required this.initialChannel,
required this.embedMode,
required this.runOnLoad,
required this.handleBrightnessChanged,
this.sampleId,
this.gistId,
}) : super(key: ValueKey('sample:$sampleId gist:$gistId'));
this.builtinSampleId,
this.flutterSampleId,
}) : super(
key: ValueKey(
'sample:$builtinSampleId gist:$gistId flutter:$flutterSampleId',
),
);

@override
State<DartPadMainPage> createState() => _DartPadMainPageState();
Expand Down Expand Up @@ -222,8 +228,10 @@ class _DartPadMainPageState extends State<DartPadMainPage> {

appServices
.performInitialLoad(
sampleId: widget.sampleId,
gistId: widget.gistId,
sampleId: widget.builtinSampleId,
flutterSampleId: widget.flutterSampleId,
channel: widget.initialChannel,
fallbackSnippet: Samples.getDefault(type: 'dart'))
.then((value) {
if (widget.runOnLoad) {
Expand Down
92 changes: 64 additions & 28 deletions pkgs/sketch_pad/lib/model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

import 'flutter_samples.dart';
import 'gists.dart';
import 'samples.g.dart';
import 'utils.dart';
Expand Down Expand Up @@ -189,8 +190,10 @@ class AppServices {
}

Future<void> performInitialLoad({
String? sampleId,
String? gistId,
String? sampleId,
String? flutterSampleId,
String? channel,
required String fallbackSnippet,
}) async {
// Delay a bit for codemirror to initialize.
Expand All @@ -204,42 +207,75 @@ class AppServices {
return;
}

if (gistId == null) {
appModel.sourceCodeController.text = fallbackSnippet;
appModel.appReady.value = true;
return;
}
if (flutterSampleId != null) {
final loader = FlutterSampleLoader();
final progress =
appModel.editorStatus.showMessage(initialText: 'Loading…');
try {
final sample = await loader.loadFlutterSample(
sampleId: flutterSampleId,
channel: channel,
);
progress.close();

final gistLoader = GistLoader();
final progress = appModel.editorStatus.showMessage(initialText: 'Loading…');
try {
final gist = await gistLoader.load(gistId);
progress.close();
appModel.title.value = flutterSampleId;
appModel.sourceCodeController.text = sample;

appModel.appReady.value = true;
} catch (e) {
appModel.editorStatus.showToast('Error loading sample');
progress.close();

final title = gist.description ?? '';
appModel.title.value =
title.length > 40 ? '${title.substring(0, 40)}…' : title;
appModel.appendLineToConsole('Error loading sample: $e');

final source = gist.mainDartSource;
if (source == null) {
appModel.editorStatus.showToast('main.dart not found');
appModel.sourceCodeController.text = fallbackSnippet;
} else {
appModel.sourceCodeController.text = source;
appModel.appReady.value = true;
} finally {
loader.dispose();
}

appModel.appReady.value = true;
} catch (e) {
appModel.editorStatus.showToast('Error loading gist');
progress.close();
return;
}

appModel.appendLineToConsole('Error loading gist: $e');
if (gistId != null) {
final gistLoader = GistLoader();
final progress =
appModel.editorStatus.showMessage(initialText: 'Loading…');
try {
final gist = await gistLoader.load(gistId);
progress.close();

final title = gist.description ?? '';
appModel.title.value =
title.length > 40 ? '${title.substring(0, 40)}…' : title;

final source = gist.mainDartSource;
if (source == null) {
appModel.editorStatus.showToast('main.dart not found');
appModel.sourceCodeController.text = fallbackSnippet;
} else {
appModel.sourceCodeController.text = source;
}

appModel.appReady.value = true;
} catch (e) {
appModel.editorStatus.showToast('Error loading gist');
progress.close();

appModel.appendLineToConsole('Error loading gist: $e');

appModel.sourceCodeController.text = fallbackSnippet;
appModel.appReady.value = true;
} finally {
gistLoader.dispose();
appModel.sourceCodeController.text = fallbackSnippet;
appModel.appReady.value = true;
} finally {
gistLoader.dispose();
}

return;
}

// Neither gistId nor flutterSampleId were passed in.
appModel.sourceCodeController.text = fallbackSnippet;
appModel.appReady.value = true;
}

Future<FormatResponse> format(SourceRequest request) async {
Expand Down

0 comments on commit ccc88ca

Please sign in to comment.