blob: 6c2bb7d14a3f9bb0afc7831f1c57957f000342cb [file] [log] [blame]
// Copyright 2019 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:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:pedantic/pedantic.dart';
import 'common_widgets.dart';
import 'framework/framework_core.dart';
import 'globals.dart';
import 'navigation.dart';
import 'notifications.dart';
import 'theme.dart';
import 'url_utils.dart';
import 'utils.dart';
/// The screen in the app responsible for connecting to the Dart VM.
///
/// We need to use this screen to get a guarantee that the app has a Dart VM
/// available.
class ConnectScreenBody extends StatefulWidget {
@override
State<ConnectScreenBody> createState() => _ConnectScreenBodyState();
}
class _ConnectScreenBodyState extends State<ConnectScreenBody> {
TextEditingController controller;
@override
void initState() {
super.initState();
controller = TextEditingController();
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final textTheme = Theme.of(context).textTheme;
return Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Connect',
style: textTheme.headline5,
key: const Key('Connect Title'),
),
const PaddedDivider(),
Text(
'Connect to a Running App',
style: textTheme.bodyText1,
),
const SizedBox(height: denseRowSpacing),
Text(
'Enter a URL to a running Dart or Flutter application',
style: textTheme.caption,
),
const Padding(padding: EdgeInsets.only(top: 20.0)),
_buildTextInput(),
const PaddedDivider(padding: EdgeInsets.symmetric(vertical: 10.0)),
// TODO(https://github.com/flutter/devtools/issues/1111): support
// drag-and-drop of snapshot files here.
],
),
],
);
}
Widget _buildTextInput() {
final CallbackDwell connectDebounce = CallbackDwell(_connect);
return Row(
children: [
SizedBox(
width: 350.0,
child: TextField(
onSubmitted: (str) => connectDebounce.invoke(),
autofocus: true,
decoration: const InputDecoration(
isDense: true,
border: OutlineInputBorder(),
enabledBorder: OutlineInputBorder(
// TODO(jacobr): we need to use themed colors everywhere instead
// of hard coding material colors.
borderSide: BorderSide(width: 0.5, color: Colors.grey),
),
hintText: 'http://127.0.0.1:12345/auth_code=',
),
controller: controller,
),
),
const Padding(
padding: EdgeInsets.only(left: 20.0),
),
RaisedButton(
child: const Text('Connect'),
onPressed: connectDebounce.invoke,
),
],
);
}
Future<void> _connect() async {
if (controller.text?.isEmpty ?? true) {
Notifications.of(context).push(
'Please enter a VM Service URL.',
);
return;
}
final uri = normalizeVmServiceUri(controller.text);
final connected = await FrameworkCore.initVmService(
'',
explicitUri: uri,
errorReporter: (message, error) {
Notifications.of(context).push('$message $error');
},
);
if (connected) {
final connectedUri = serviceManager.service.connectedUri;
unawaited(
Navigator.pushNamed(
context,
routeNameWithQueryParams(context, '/', {'uri': '$connectedUri'}),
),
);
final shortUri = connectedUri.replace(path: '');
Notifications.of(context).push(
'Successfully connected to $shortUri.',
);
} else if (uri == null) {
Notifications.of(context).push(
'Failed to connect to the VM Service at "${controller.text}".\n'
'The link was not valid.',
);
}
}
}