| // Copyright 2016 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/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, |
| }); |
| |
| final List<ComponentDemoTabData> demos; |
| final String title; |
| final List<Widget> actions; |
| |
| 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) |
| )); |
| } |
| } |
| |
| void _showApiDocumentation(BuildContext context) { |
| final String url = demos[DefaultTabController.of(context).index].documentationUrl; |
| if (url != null) { |
| launch(url, forceWebView: true); |
| } |
| } |
| |
| @override |
| Widget build(BuildContext context) { |
| return DefaultTabController( |
| length: demos.length, |
| child: Scaffold( |
| appBar: AppBar( |
| title: Text(title), |
| actions: (actions ?? <Widget>[])..addAll( |
| <Widget>[ |
| Builder( |
| builder: (BuildContext context) { |
| return IconButton( |
| icon: const Icon(Icons.library_books, semanticLabel: 'Show documentation'), |
| onPressed: () => _showApiDocumentation(context), |
| ); |
| }, |
| ), |
| Builder( |
| builder: (BuildContext context) { |
| return IconButton( |
| icon: const Icon(Icons.code), |
| tooltip: 'Show example code', |
| onPressed: () => _showExampleCode(context), |
| ); |
| }, |
| ), |
| ], |
| ), |
| bottom: TabBar( |
| isScrollable: true, |
| 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), |
| ); |
| } |
| } |