mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00

* Update project.pbxproj files to say Flutter rather than Chromium Also, the templates now have an empty organization so that we don't cause people to give their apps a Flutter copyright. * Update the copyright notice checker to require a standard notice on all files * Update copyrights on Dart files. (This was a mechanical commit.) * Fix weird license headers on Dart files that deviate from our conventions; relicense Shrine. Some were already marked "The Flutter Authors", not clear why. Their dates have been normalized. Some were missing the blank line after the license. Some were randomly different in trivial ways for no apparent reason (e.g. missing the trailing period). * Clean up the copyrights in non-Dart files. (Manual edits.) Also, make sure templates don't have copyrights. * Fix some more ORGANIZATIONNAMEs
262 lines
7.3 KiB
Dart
262 lines
7.3 KiB
Dart
// Copyright 2014 The Flutter 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 'dart:async';
|
|
|
|
import 'package:flutter/cupertino.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:url_launcher/url_launcher.dart';
|
|
|
|
import 'demos.dart';
|
|
import 'example_code_parser.dart';
|
|
import 'syntax_highlighter.dart';
|
|
|
|
class ComponentDemoTabData {
|
|
ComponentDemoTabData({
|
|
this.demoWidget,
|
|
this.exampleCodeTag,
|
|
this.description,
|
|
this.tabName,
|
|
this.documentationUrl,
|
|
});
|
|
|
|
final Widget demoWidget;
|
|
final String exampleCodeTag;
|
|
final String description;
|
|
final String tabName;
|
|
final String documentationUrl;
|
|
|
|
@override
|
|
bool operator==(Object other) {
|
|
if (other.runtimeType != runtimeType)
|
|
return false;
|
|
final ComponentDemoTabData typedOther = other;
|
|
return typedOther.tabName == tabName
|
|
&& typedOther.description == description
|
|
&& typedOther.documentationUrl == documentationUrl;
|
|
}
|
|
|
|
@override
|
|
int get hashCode => hashValues(tabName, description, documentationUrl);
|
|
}
|
|
|
|
class TabbedComponentDemoScaffold extends StatelessWidget {
|
|
const TabbedComponentDemoScaffold({
|
|
this.title,
|
|
this.demos,
|
|
this.actions,
|
|
this.isScrollable = true,
|
|
this.showExampleCodeAction = true,
|
|
});
|
|
|
|
final List<ComponentDemoTabData> demos;
|
|
final String title;
|
|
final List<Widget> actions;
|
|
final bool isScrollable;
|
|
final bool showExampleCodeAction;
|
|
|
|
void _showExampleCode(BuildContext context) {
|
|
final String tag = demos[DefaultTabController.of(context).index].exampleCodeTag;
|
|
if (tag != null) {
|
|
Navigator.push(context, MaterialPageRoute<FullScreenCodeDialog>(
|
|
builder: (BuildContext context) => FullScreenCodeDialog(exampleCodeTag: tag)
|
|
));
|
|
}
|
|
}
|
|
|
|
Future<void> _showApiDocumentation(BuildContext context) async {
|
|
final String url = demos[DefaultTabController.of(context).index].documentationUrl;
|
|
if (url == null)
|
|
return;
|
|
|
|
if (await canLaunch(url)) {
|
|
await launch(url);
|
|
} else {
|
|
showDialog<void>(
|
|
context: context,
|
|
builder: (BuildContext context) {
|
|
return SimpleDialog(
|
|
title: const Text('Couldn\'t display URL:'),
|
|
children: <Widget>[
|
|
Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
|
child: Text(url),
|
|
),
|
|
],
|
|
);
|
|
},
|
|
);
|
|
}
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return DefaultTabController(
|
|
length: demos.length,
|
|
child: Scaffold(
|
|
appBar: AppBar(
|
|
title: Text(title),
|
|
actions: <Widget>[
|
|
...?actions,
|
|
Builder(
|
|
builder: (BuildContext context) {
|
|
return IconButton(
|
|
icon: const Icon(Icons.library_books, semanticLabel: 'Show documentation'),
|
|
onPressed: () => _showApiDocumentation(context),
|
|
);
|
|
},
|
|
),
|
|
if (showExampleCodeAction)
|
|
Builder(
|
|
builder: (BuildContext context) {
|
|
return IconButton(
|
|
icon: const Icon(Icons.code),
|
|
tooltip: 'Show example code',
|
|
onPressed: () => _showExampleCode(context),
|
|
);
|
|
},
|
|
),
|
|
],
|
|
bottom: TabBar(
|
|
isScrollable: isScrollable,
|
|
tabs: demos.map<Widget>((ComponentDemoTabData data) => Tab(text: data.tabName)).toList(),
|
|
),
|
|
),
|
|
body: TabBarView(
|
|
children: demos.map<Widget>((ComponentDemoTabData demo) {
|
|
return SafeArea(
|
|
top: false,
|
|
bottom: false,
|
|
child: Column(
|
|
children: <Widget>[
|
|
Padding(
|
|
padding: const EdgeInsets.all(16.0),
|
|
child: Text(demo.description,
|
|
style: Theme.of(context).textTheme.subhead,
|
|
),
|
|
),
|
|
Expanded(child: demo.demoWidget),
|
|
],
|
|
),
|
|
);
|
|
}).toList(),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class FullScreenCodeDialog extends StatefulWidget {
|
|
const FullScreenCodeDialog({ this.exampleCodeTag });
|
|
|
|
final String exampleCodeTag;
|
|
|
|
@override
|
|
FullScreenCodeDialogState createState() => FullScreenCodeDialogState();
|
|
}
|
|
|
|
class FullScreenCodeDialogState extends State<FullScreenCodeDialog> {
|
|
|
|
String _exampleCode;
|
|
|
|
@override
|
|
void didChangeDependencies() {
|
|
getExampleCode(widget.exampleCodeTag, DefaultAssetBundle.of(context)).then<void>((String code) {
|
|
if (mounted) {
|
|
setState(() {
|
|
_exampleCode = code ?? 'Example code not found';
|
|
});
|
|
}
|
|
});
|
|
super.didChangeDependencies();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final SyntaxHighlighterStyle style = Theme.of(context).brightness == Brightness.dark
|
|
? SyntaxHighlighterStyle.darkThemeStyle()
|
|
: SyntaxHighlighterStyle.lightThemeStyle();
|
|
|
|
Widget body;
|
|
if (_exampleCode == null) {
|
|
body = const Center(
|
|
child: CircularProgressIndicator(),
|
|
);
|
|
} else {
|
|
body = SingleChildScrollView(
|
|
child: Padding(
|
|
padding: const EdgeInsets.all(16.0),
|
|
child: RichText(
|
|
text: TextSpan(
|
|
style: const TextStyle(fontFamily: 'monospace', fontSize: 10.0),
|
|
children: <TextSpan>[
|
|
DartSyntaxHighlighter(style).format(_exampleCode),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
return Scaffold(
|
|
appBar: AppBar(
|
|
leading: IconButton(
|
|
icon: const Icon(
|
|
Icons.clear,
|
|
semanticLabel: 'Close',
|
|
),
|
|
onPressed: () { Navigator.pop(context); },
|
|
),
|
|
title: const Text('Example code'),
|
|
),
|
|
body: body,
|
|
);
|
|
}
|
|
}
|
|
|
|
class MaterialDemoDocumentationButton extends StatelessWidget {
|
|
MaterialDemoDocumentationButton(String routeName, { Key key })
|
|
: documentationUrl = kDemoDocumentationUrl[routeName],
|
|
assert(
|
|
kDemoDocumentationUrl[routeName] != null,
|
|
'A documentation URL was not specified for demo route $routeName in kAllGalleryDemos',
|
|
),
|
|
super(key: key);
|
|
|
|
final String documentationUrl;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return IconButton(
|
|
icon: const Icon(Icons.library_books),
|
|
tooltip: 'API documentation',
|
|
onPressed: () => launch(documentationUrl, forceWebView: true),
|
|
);
|
|
}
|
|
}
|
|
|
|
class CupertinoDemoDocumentationButton extends StatelessWidget {
|
|
CupertinoDemoDocumentationButton(String routeName, { Key key })
|
|
: documentationUrl = kDemoDocumentationUrl[routeName],
|
|
assert(
|
|
kDemoDocumentationUrl[routeName] != null,
|
|
'A documentation URL was not specified for demo route $routeName in kAllGalleryDemos',
|
|
),
|
|
super(key: key);
|
|
|
|
final String documentationUrl;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return CupertinoButton(
|
|
padding: EdgeInsets.zero,
|
|
child: Semantics(
|
|
label: 'API documentation',
|
|
child: const Icon(CupertinoIcons.book),
|
|
),
|
|
onPressed: () => launch(documentationUrl, forceWebView: true),
|
|
);
|
|
}
|
|
}
|