| // Copyright 2013 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. |
| |
| // There's a lot of <Object>[] lists in this file so to avoid making this |
| // file even less readable we relax our usual stance on verbose typing. |
| // ignore_for_file: always_specify_types |
| |
| // This file is hand-formatted. |
| |
| import 'package:flutter/gestures.dart'; |
| import 'package:flutter/material.dart'; |
| |
| import 'argument_decoders.dart'; |
| import 'runtime.dart'; |
| |
| /// A widget library for Remote Flutter Widgets that defines widgets that are |
| /// implemented on the client in terms of Flutter widgets from the `material` |
| /// Dart library. |
| /// |
| /// The following widgets are implemented: |
| /// |
| /// * [AboutListTile] |
| /// * [AppBar] |
| /// * [ButtonBar] |
| /// * [Card] |
| /// * [CircularProgressIndicator] |
| /// * [Divider] |
| /// * [DrawerHeader] |
| /// * [ElevatedButton] |
| /// * [FloatingActionButton] |
| /// * [InkWell] |
| /// * [LinearProgressIndicator] |
| /// * [ListTile] |
| /// * [OutlinedButton] |
| /// * [Scaffold] |
| /// * [TextButton] |
| /// * [VerticalDivider] |
| /// |
| /// For each, every parameter is implemented using the same name. Parameters |
| /// that take structured types are represented using maps, with each named |
| /// parameter of that type's default constructor represented by a key. The |
| /// conventions edscribed for [createCoreWidgets] are reused here. |
| /// |
| /// In addition, the following conventions are introduced: |
| /// |
| /// * Hero tags are always strings. |
| /// |
| /// * [VisualDensity] is represented in the manner described in the documentation |
| /// of the [ArgumentDecoders.visualDensity] method. |
| /// |
| /// Some features are not supported: |
| /// |
| /// * [AppBar]s do not support [AppBar.bottom], [AppBar.flexibleSpace], and |
| /// related properties. Also, [AppBar.systemOverlayStyle] is not suported. |
| /// |
| /// * Theming in general is not currently supported. |
| /// |
| /// * Properties whose values are [Animation]s or based on |
| /// [MaterialStateProperty] are not supported. |
| /// |
| /// * Features related to focus or configuring mouse support are not |
| /// implemented. |
| /// |
| /// * Callbacks such as [Scafford.onDrawerChanged] are not exposed. |
| /// |
| /// * The [Scaffold]'s floating action button position and animation features |
| /// are not supported. |
| /// |
| /// In general, the trend will all of these unsupported features is that this |
| /// library doesn't support features that can't be trivially expressed using the |
| /// JSON-like structures of RFW. For example, [MaterialStateProperty] is |
| /// designed to be used with code to select the values, which doesn't work well |
| /// in the RFW structure. |
| LocalWidgetLibrary createMaterialWidgets() => LocalWidgetLibrary(_materialWidgetsDefinitions); |
| |
| Map<String, LocalWidgetBuilder> get _materialWidgetsDefinitions => <String, LocalWidgetBuilder>{ |
| |
| // Keep these in alphabetical order. |
| |
| 'AboutListTile': (BuildContext context, DataSource source) { |
| return AboutListTile( |
| icon: source.optionalChild(['icon']), |
| applicationName: source.v<String>(['applicationName']), |
| applicationVersion: source.v<String>(['applicationVersion']), |
| applicationIcon: source.optionalChild(['applicationIcon']), |
| applicationLegalese: source.v<String>(['applicationLegalese']), |
| aboutBoxChildren: source.childList(['aboutBoxChildren']), |
| dense: source.v<bool>(['dense']), |
| child: source.optionalChild(['child']), |
| ); |
| }, |
| |
| 'AppBar': (BuildContext context, DataSource source) { |
| // not implemented: bottom (and bottomOpacity), flexibleSpace; systemOverlayStyle |
| return AppBar( |
| leading: source.optionalChild(['leading']), |
| automaticallyImplyLeading: source.v<bool>(['automaticallyImplyLeading']) ?? true, |
| title: source.optionalChild(['title']), |
| actions: source.childList(['actions']), |
| elevation: source.v<double>(['elevation']), |
| shadowColor: ArgumentDecoders.color(source, ['shadowColor']), |
| shape: ArgumentDecoders.shapeBorder(source, ['shape']), |
| backgroundColor: ArgumentDecoders.color(source, ['backgroundColor']), |
| foregroundColor: ArgumentDecoders.color(source, ['foregroundColor']), |
| iconTheme: ArgumentDecoders.iconThemeData(source, ['iconTheme']), |
| actionsIconTheme: ArgumentDecoders.iconThemeData(source, ['actionsIconTheme']), |
| primary: source.v<bool>(['primary']) ?? true, |
| centerTitle: source.v<bool>(['centerTitle']), |
| excludeHeaderSemantics: source.v<bool>(['excludeHeaderSemantics']) ?? false, |
| titleSpacing: source.v<double>(['titleSpacing']), |
| toolbarOpacity: source.v<double>(['toolbarOpacity']) ?? 1.0, |
| toolbarHeight: source.v<double>(['toolbarHeight']), |
| leadingWidth: source.v<double>(['leadingWidth']), |
| toolbarTextStyle: ArgumentDecoders.textStyle(source, ['toolbarTextStyle']), |
| titleTextStyle: ArgumentDecoders.textStyle(source, ['titleTextStyle']), |
| ); |
| }, |
| |
| 'ButtonBar': (BuildContext context, DataSource source) { |
| // not implemented: buttonTextTheme |
| return ButtonBar( |
| alignment: ArgumentDecoders.enumValue<MainAxisAlignment>(MainAxisAlignment.values, source, ['alignment']) ?? MainAxisAlignment.start, |
| mainAxisSize: ArgumentDecoders.enumValue<MainAxisSize>(MainAxisSize.values, source, ['mainAxisSize']) ?? MainAxisSize.max, |
| buttonMinWidth: source.v<double>(['buttonMinWidth']), |
| buttonHeight: source.v<double>(['buttonHeight']), |
| buttonPadding: ArgumentDecoders.edgeInsets(source, ['buttonPadding']), |
| buttonAlignedDropdown: source.v<bool>(['buttonAlignedDropdown']) ?? false, |
| layoutBehavior: ArgumentDecoders.enumValue<ButtonBarLayoutBehavior>(ButtonBarLayoutBehavior.values, source, ['layoutBehavior']), |
| overflowDirection: ArgumentDecoders.enumValue<VerticalDirection>(VerticalDirection.values, source, ['overflowDirection']), |
| overflowButtonSpacing: source.v<double>(['overflowButtonSpacing']), |
| children: source.childList(['children']), |
| ); |
| }, |
| |
| 'Card': (BuildContext context, DataSource source) { |
| return Card( |
| color: ArgumentDecoders.color(source, ['color']), |
| shadowColor: ArgumentDecoders.color(source, ['shadowColor']), |
| elevation: source.v<double>(['elevation']), |
| shape: ArgumentDecoders.shapeBorder(source, ['shape']), |
| borderOnForeground: source.v<bool>(['borderOnForeground']) ?? true, |
| margin: ArgumentDecoders.edgeInsets(source, ['margin']), |
| clipBehavior: ArgumentDecoders.enumValue<Clip>(Clip.values, source, ['clipBehavior']) ?? Clip.none, |
| semanticContainer: source.v<bool>(['semanticContainer']) ?? true, |
| child: source.optionalChild(['child']), |
| ); |
| }, |
| |
| 'CircularProgressIndicator': (BuildContext context, DataSource source) { |
| // not implemented: valueColor |
| return CircularProgressIndicator( |
| value: source.v<double>(['value']), |
| color: ArgumentDecoders.color(source, ['color']), |
| backgroundColor: ArgumentDecoders.color(source, ['backgroundColor']), |
| strokeWidth: source.v<double>(['strokeWidth']) ?? 4.0, |
| semanticsLabel: source.v<String>(['semanticsLabel']), |
| semanticsValue: source.v<String>(['semanticsValue']), |
| ); |
| }, |
| |
| 'Divider': (BuildContext context, DataSource source) { |
| return Divider( |
| height: source.v<double>(['height']), |
| thickness: source.v<double>(['thickness']), |
| indent: source.v<double>(['indent']), |
| endIndent: source.v<double>(['endIndent']), |
| color: ArgumentDecoders.color(source, ['color']), |
| ); |
| }, |
| |
| 'Drawer': (BuildContext context, DataSource source) { |
| return Drawer( |
| elevation: source.v<double>(['elevation']) ?? 16.0, |
| semanticLabel: source.v<String>(['semanticLabel']), |
| child: source.optionalChild(['child']), |
| ); |
| }, |
| |
| 'DrawerHeader': (BuildContext context, DataSource source) { |
| return DrawerHeader( |
| duration: ArgumentDecoders.duration(source, ['duration'], context), |
| curve: ArgumentDecoders.curve(source, ['curve'], context), |
| decoration: ArgumentDecoders.decoration(source, ['decoration']), |
| margin: ArgumentDecoders.edgeInsets(source, ['margin']) ?? const EdgeInsets.only(bottom: 8.0), |
| padding: ArgumentDecoders.edgeInsets(source, ['padding']) ?? const EdgeInsets.fromLTRB(16.0, 16.0, 16.0, 8.0), |
| child: source.optionalChild(['child']), |
| ); |
| }, |
| |
| 'ElevatedButton': (BuildContext context, DataSource source) { |
| // not implemented: buttonStyle, focusNode |
| return ElevatedButton( |
| onPressed: source.voidHandler(['onPressed']), |
| onLongPress: source.voidHandler(['onLongPress']), |
| autofocus: source.v<bool>(['autofocus']) ?? false, |
| clipBehavior: ArgumentDecoders.enumValue<Clip>(Clip.values, source, ['clipBehavior']) ?? Clip.none, |
| child: source.child(['child']), |
| ); |
| }, |
| |
| 'FloatingActionButton': (BuildContext context, DataSource source) { |
| // not implemented: mouseCursor, focusNode |
| return FloatingActionButton( |
| tooltip: source.v<String>(['tooltip']), |
| foregroundColor: ArgumentDecoders.color(source, ['foregroundColor']), |
| backgroundColor: ArgumentDecoders.color(source, ['backgroundColor']), |
| focusColor: ArgumentDecoders.color(source, ['focusColor']), |
| hoverColor: ArgumentDecoders.color(source, ['hoverColor']), |
| splashColor: ArgumentDecoders.color(source, ['splashColor']), |
| heroTag: source.v<String>(['heroTag']), |
| elevation: source.v<double>(['elevation']), |
| focusElevation: source.v<double>(['focusElevation']), |
| hoverElevation: source.v<double>(['hoverElevation']), |
| highlightElevation: source.v<double>(['highlightElevation']), |
| disabledElevation: source.v<double>(['disabledElevation']), |
| onPressed: source.voidHandler(['onPressed']), |
| mini: source.v<bool>(['mini']) ?? false, |
| shape: ArgumentDecoders.shapeBorder(source, ['shape']), |
| clipBehavior: ArgumentDecoders.enumValue<Clip>(Clip.values, source, ['clipBehavior']) ?? Clip.none, |
| autofocus: source.v<bool>(['autofocus']) ?? false, |
| materialTapTargetSize: ArgumentDecoders.enumValue<MaterialTapTargetSize>(MaterialTapTargetSize.values, source, ['materialTapTargetSize']), |
| isExtended: source.v<bool>(['isExtended']) ?? false, |
| enableFeedback: source.v<bool>(['enableFeedback']), |
| child: source.child(['child']), |
| ); |
| }, |
| |
| 'InkWell': (BuildContext context, DataSource source) { |
| // not implemented: onHighlightChanged, onHover; mouseCursor; focusColor, hoverColor, highlightColor, overlayColor, splashColor; splashFactory; focusNode, onFocusChange |
| return InkWell( |
| onTap: source.voidHandler(['onTap']), |
| onDoubleTap: source.voidHandler(['onDoubleTap']), |
| onLongPress: source.voidHandler(['onLongPress']), |
| onTapDown: source.handler(['onTapDown'], (VoidCallback trigger) => (TapDownDetails details) => trigger()), |
| onTapCancel: source.voidHandler(['onTapCancel']), |
| radius: source.v<double>(['radius']), |
| borderRadius: ArgumentDecoders.borderRadius(source, ['borderRadius'])?.resolve(Directionality.of(context)), |
| customBorder: ArgumentDecoders.shapeBorder(source, ['customBorder']), |
| enableFeedback: source.v<bool>(['enableFeedback']) ?? true, |
| excludeFromSemantics: source.v<bool>(['excludeFromSemantics']) ?? false, |
| autofocus: source.v<bool>(['autofocus']) ?? false, |
| child: source.optionalChild(['child']), |
| ); |
| }, |
| |
| 'LinearProgressIndicator': (BuildContext context, DataSource source) { |
| // not implemented: valueColor |
| return LinearProgressIndicator( |
| value: source.v<double>(['value']), |
| color: ArgumentDecoders.color(source, ['color']), |
| backgroundColor: ArgumentDecoders.color(source, ['backgroundColor']), |
| minHeight: source.v<double>(['minHeight']), |
| semanticsLabel: source.v<String>(['semanticsLabel']), |
| semanticsValue: source.v<String>(['semanticsValue']), |
| ); |
| }, |
| |
| 'ListTile': (BuildContext context, DataSource source) { |
| // not implemented: mouseCursor, focusNode |
| return ListTile( |
| leading: source.optionalChild(['leading']), |
| title: source.optionalChild(['title']), |
| subtitle: source.optionalChild(['subtitle']), |
| trailing: source.optionalChild(['trailing']), |
| isThreeLine: source.v<bool>(['isThreeLine']) ?? false, |
| dense: source.v<bool>(['dense']), |
| visualDensity: ArgumentDecoders.visualDensity(source, ['visualDensity']), |
| shape: ArgumentDecoders.shapeBorder(source, ['shape']), |
| contentPadding: ArgumentDecoders.edgeInsets(source, ['contentPadding']), |
| enabled: source.v<bool>(['enabled']) ?? true, |
| onTap: source.voidHandler(['onTap']), |
| onLongPress: source.voidHandler(['onLongPress']), |
| selected: source.v<bool>(['selected']) ?? false, |
| focusColor: ArgumentDecoders.color(source, ['focusColor']), |
| hoverColor: ArgumentDecoders.color(source, ['hoverColor']), |
| autofocus: source.v<bool>(['autofocus']) ?? false, |
| tileColor: ArgumentDecoders.color(source, ['tileColor']), |
| selectedTileColor: ArgumentDecoders.color(source, ['selectedTileColor']), |
| enableFeedback: source.v<bool>(['enableFeedback']), |
| horizontalTitleGap: source.v<double>(['horizontalTitleGap']), |
| minVerticalPadding: source.v<double>(['minVerticalPadding']), |
| minLeadingWidth: source.v<double>(['minLeadingWidth']), |
| ); |
| }, |
| |
| 'OutlinedButton': (BuildContext context, DataSource source) { |
| // not implemented: buttonStyle, focusNode |
| return OutlinedButton( |
| onPressed: source.voidHandler(['onPressed']), |
| onLongPress: source.voidHandler(['onLongPress']), |
| autofocus: source.v<bool>(['autofocus']) ?? false, |
| clipBehavior: ArgumentDecoders.enumValue<Clip>(Clip.values, source, ['clipBehavior']) ?? Clip.none, |
| child: source.child(['child']), |
| ); |
| }, |
| |
| 'Scaffold': (BuildContext context, DataSource source) { |
| // not implemented: floatingActionButtonLocation, floatingActionButtonAnimator; onDrawerChanged, onEndDrawerChanged |
| final Widget? appBarWidget = source.optionalChild(['appBar']); |
| final List<Widget> persistentFooterButtons = source.childList(['persistentFooterButtons']); |
| return Scaffold( |
| appBar: appBarWidget == null ? null : PreferredSize( |
| preferredSize: Size.fromHeight(source.v<double>(['bottomHeight']) ?? 56.0), |
| child: appBarWidget, |
| ), |
| body: source.optionalChild(['body']), |
| floatingActionButton: source.optionalChild(['floatingActionButton']), |
| persistentFooterButtons: persistentFooterButtons.isEmpty ? null : persistentFooterButtons, |
| drawer: source.optionalChild(['drawer']), |
| endDrawer: source.optionalChild(['endDrawer']), |
| bottomNavigationBar: source.optionalChild(['bottomNavigationBar']), |
| bottomSheet: source.optionalChild(['bottomSheet']), |
| backgroundColor: ArgumentDecoders.color(source, ['backgroundColor']), |
| resizeToAvoidBottomInset: source.v<bool>(['resizeToAvoidBottomInset']), |
| primary: source.v<bool>(['primary']) ?? true, |
| drawerDragStartBehavior: ArgumentDecoders.enumValue<DragStartBehavior>(DragStartBehavior.values, source, ['drawerDragStartBehavior']) ?? DragStartBehavior.start, |
| extendBody: source.v<bool>(['extendBody']) ?? false, |
| extendBodyBehindAppBar: source.v<bool>(['extendBodyBehindAppBar']) ?? false, |
| drawerScrimColor: ArgumentDecoders.color(source, ['drawerScrimColor']), |
| drawerEdgeDragWidth: source.v<double>(['drawerEdgeDragWidth']), |
| drawerEnableOpenDragGesture: source.v<bool>(['drawerEnableOpenDragGesture']) ?? true, |
| endDrawerEnableOpenDragGesture: source.v<bool>(['endDrawerEnableOpenDragGesture']) ?? true, |
| restorationId: source.v<String>(['restorationId']), |
| ); |
| }, |
| |
| 'TextButton': (BuildContext context, DataSource source) { |
| // not implemented: buttonStyle, focusNode |
| return TextButton( |
| onPressed: source.voidHandler(['onPressed']), |
| onLongPress: source.voidHandler(['onLongPress']), |
| autofocus: source.v<bool>(['autofocus']) ?? false, |
| clipBehavior: ArgumentDecoders.enumValue<Clip>(Clip.values, source, ['clipBehavior']) ?? Clip.none, |
| child: source.child(['child']), |
| ); |
| }, |
| |
| 'VerticalDivider': (BuildContext context, DataSource source) { |
| return VerticalDivider( |
| width: source.v<double>(['width']), |
| thickness: source.v<double>(['thickness']), |
| indent: source.v<double>(['indent']), |
| endIndent: source.v<double>(['endIndent']), |
| color: ArgumentDecoders.color(source, ['color']), |
| ); |
| }, |
| |
| }; |