LCOV - code coverage report
Current view: top level - lib/widgets/form_widget - cross_reference_form_widget.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 129 129 100.0 %
Date: 2021-10-28 12:33:10 Functions: 0 0 -

          Line data    Source code
       1             : part of apptive_grid_form_widgets;
       2             : 
       3             : /// FormComponent Widget to display a [CrossReferenceFormComponent]
       4             : class CrossReferenceFormWidget extends StatefulWidget {
       5             :   /// Creates a [Checkbox] to display a boolean value contained in [component]
       6           2 :   const CrossReferenceFormWidget({
       7             :     Key? key,
       8             :     required this.component,
       9           2 :   }) : super(key: key);
      10             : 
      11             :   /// Component this Widget should reflect
      12             :   final CrossReferenceFormComponent component;
      13             : 
      14           1 :   @override
      15             :   _CrossReferenceFormWidgetState createState() =>
      16           1 :       _CrossReferenceFormWidgetState();
      17             : }
      18             : 
      19             : class _CrossReferenceFormWidgetState extends State<CrossReferenceFormWidget> {
      20             :   Grid? _grid;
      21             :   dynamic _error;
      22             : 
      23             :   final LinkedScrollControllerGroup _scrollControllerGroup =
      24             :       LinkedScrollControllerGroup();
      25             :   final _controllers = <String, ScrollController>{};
      26             :   ScrollController? _headerController;
      27             :   final _keys = <String, GlobalKey<_RowMenuItemState>>{};
      28             : 
      29           1 :   @override
      30             :   void didChangeDependencies() {
      31           1 :     super.didChangeDependencies();
      32           2 :     if (_grid == null && _error == null) {
      33           1 :       _loadGrid();
      34             :     }
      35             :   }
      36             : 
      37           1 :   @override
      38             :   void dispose() {
      39           3 :     for (final controller in _controllers.values) {
      40           1 :       controller.dispose();
      41             :     }
      42           2 :     _headerController?.dispose();
      43           1 :     _headerController = null;
      44           1 :     super.dispose();
      45             :   }
      46             : 
      47           1 :   void _loadGrid() {
      48           2 :     setState(() {
      49           1 :       _error = null;
      50           1 :       _grid = null;
      51             :     });
      52           2 :     ApptiveGrid.getClient(context, listen: false)
      53           5 :         .loadGrid(gridUri: widget.component.data.gridUri)
      54           2 :         .then((value) {
      55           2 :       for (final row in value.rows) {
      56           3 :         _controllers[row.id]?.dispose();
      57           5 :         _controllers[row.id] = _scrollControllerGroup.addAndGet();
      58             : 
      59           4 :         _keys[row.id] ??= GlobalKey();
      60             :       }
      61           1 :       _headerController?.dispose();
      62           3 :       _headerController = _scrollControllerGroup.addAndGet();
      63           2 :       setState(() {
      64           1 :         _error = null;
      65           1 :         _grid = value;
      66             :       });
      67           2 :     }).catchError((error) {
      68           2 :       setState(() {
      69           1 :         _error = error;
      70           1 :         _grid = null;
      71             :       });
      72             :     });
      73             :   }
      74             : 
      75           1 :   @override
      76             :   Widget build(BuildContext context) {
      77           1 :     return GridRowDropdownButtonFormField<GridRowDropdownDataItem?>(
      78             :       isExpanded: true,
      79           1 :       items: _items(),
      80           1 :       onChanged: (newValue) {
      81           1 :         if (newValue?.entityUri != null) {
      82           2 :           setState(() {
      83           5 :             widget.component.data.value = newValue?.displayValue;
      84           5 :             widget.component.data.entityUri = newValue?.entityUri;
      85             :           });
      86             :         }
      87             :       },
      88           1 :       validator: (value) {
      89           3 :         if (widget.component.required &&
      90           2 :             (value?.entityUri == null || value?.displayValue == null)) {
      91           1 :           return ApptiveGridLocalization.of(context)!
      92           4 :               .fieldIsRequired(widget.component.property);
      93             :         } else {
      94             :           return null;
      95             :         }
      96             :       },
      97           1 :       selectedItemBuilder: _selectedItems,
      98             :       autovalidateMode: AutovalidateMode.onUserInteraction,
      99           4 :       value: widget.component.data.entityUri != null &&
     100           4 :               widget.component.data.value != null
     101           1 :           ? GridRowDropdownDataItem(
     102           4 :               entityUri: widget.component.data.entityUri,
     103           4 :               displayValue: widget.component.data.value,
     104             :             )
     105             :           : null,
     106           1 :       decoration: InputDecoration(
     107           4 :         helperText: widget.component.options.description,
     108             :         helperMaxLines: 100,
     109           7 :         labelText: widget.component.options.label ?? widget.component.property,
     110           2 :         errorText: _error?.toString(),
     111             :       ),
     112             :     );
     113             :   }
     114             : 
     115           1 :   List<GridRowDropdownMenuItem<GridRowDropdownDataItem?>>? _items() {
     116           2 :     if (_error != null || _grid == null) {
     117             :       return null;
     118             :     } else {
     119           1 :       final searchBox = GridRowDropdownMenuItem(
     120             :         enabled: false,
     121             :         value: null,
     122           1 :         child: Padding(
     123             :           padding: const EdgeInsets.symmetric(horizontal: 16.0),
     124           1 :           child: TextField(
     125             :             decoration: const InputDecoration(
     126             :               icon: Icon(Icons.search),
     127             :               hintText: 'Search',
     128             :               border: InputBorder.none,
     129             :             ),
     130           1 :             onChanged: (input) {
     131           3 :               for (final key in _keys.values) {
     132           2 :                 key.currentState?.updateFilter(input);
     133             :               }
     134             :             },
     135             :           ),
     136             :         ),
     137             :       );
     138             : 
     139           1 :       final headerRow = GridRowDropdownMenuItem(
     140             :         enabled: false,
     141             :         value: null,
     142           1 :         child: HeaderRowWidget(
     143           2 :           fields: _grid!.fields,
     144           1 :           controller: _headerController,
     145             :         ),
     146             :       );
     147             : 
     148           4 :       final items = _grid!.rows.map((row) {
     149           4 :         final gridUri = widget.component.data.gridUri;
     150           1 :         final entityUri = EntityUri(
     151           1 :           user: gridUri.user,
     152           1 :           space: gridUri.space,
     153           1 :           grid: gridUri.grid,
     154           1 :           entity: row.id,
     155             :         );
     156           1 :         return GridRowDropdownMenuItem(
     157           1 :           value: GridRowDropdownDataItem(
     158             :             entityUri: entityUri,
     159           5 :             displayValue: row.entries.first.data.value.toString(),
     160             :           ),
     161           1 :           child: _RowMenuItem(
     162           3 :             key: _keys[row.id],
     163           1 :             grid: _grid!,
     164             :             row: row,
     165           3 :             controller: _controllers[row.id],
     166             :           ),
     167             :         );
     168           1 :       }).toList();
     169           2 :       return [searchBox, headerRow, ...items];
     170             :     }
     171             :   }
     172             : 
     173           1 :   List<Widget> _selectedItems(BuildContext context) {
     174           1 :     final localization = ApptiveGridLocalization.of(context)!;
     175           1 :     if (_error != null) {
     176           1 :       return [
     177             :         const Center(
     178             :           child: Text('ERROR'),
     179             :         )
     180             :       ];
     181           1 :     } else if (_grid == null) {
     182           1 :       return [
     183           1 :         Center(
     184           2 :           child: Text(localization.loadingGrid),
     185             :         )
     186             :       ];
     187             :     } else {
     188           2 :       final pleaseSelect = Text(localization.selectEntry);
     189           1 :       return [
     190           1 :         ...[pleaseSelect, pleaseSelect],
     191           2 :         ..._grid!.rows
     192           1 :             .map(
     193           2 :               (row) => Text(
     194           5 :                 row.entries.first.data.value?.toString() ?? '',
     195             :                 maxLines: 1,
     196             :                 overflow: TextOverflow.ellipsis,
     197             :               ),
     198             :             )
     199           1 :             .toList()
     200             :       ];
     201             :     }
     202             :   }
     203             : }
     204             : 
     205             : class _RowMenuItem extends StatefulWidget {
     206           1 :   const _RowMenuItem({
     207             :     Key? key,
     208             :     required this.grid,
     209             :     required this.row,
     210             :     this.controller,
     211           1 :   }) : super(key: key);
     212             : 
     213             :   final Grid grid;
     214             :   final GridRow row;
     215             :   final ScrollController? controller;
     216             : 
     217           1 :   @override
     218           1 :   _RowMenuItemState createState() => _RowMenuItemState();
     219             : }
     220             : 
     221             : class _RowMenuItemState extends State<_RowMenuItem> {
     222             :   String? _filter;
     223             : 
     224           1 :   void updateFilter(String filter) {
     225           2 :     setState(() {
     226           1 :       _filter = filter;
     227             :     });
     228             :   }
     229             : 
     230           1 :   @override
     231             :   Widget build(BuildContext context) {
     232           4 :     if (!widget.row.matchesFilter(_filter)) {
     233             :       return const SizedBox();
     234             :     } else {
     235           3 :       final index = widget.grid.rows
     236           4 :           .where((row) => row.matchesFilter(_filter))
     237           1 :           .toList()
     238           3 :           .indexOf(widget.row);
     239           1 :       return GridRowWidget(
     240           2 :         row: widget.row,
     241           2 :         controller: widget.controller,
     242           2 :         color: index % 2 != 0
     243           3 :             ? Theme.of(context).hintColor.withOpacity(0.1)
     244             :             : null,
     245             :       );
     246             :     }
     247             :   }
     248             : }
     249             : 
     250             : extension _GridRowX on GridRow {
     251           1 :   bool matchesFilter(String? filter) {
     252           1 :     if (filter == null || filter.isEmpty) return true;
     253             : 
     254           1 :     return entries
     255           1 :         .where(
     256           1 :           (entry) =>
     257           2 :               entry.data.schemaValue
     258           1 :                   ?.toString()
     259           1 :                   .toLowerCase()
     260           2 :                   .contains(filter.toLowerCase()) ??
     261             :               false,
     262             :         )
     263           1 :         .isNotEmpty;
     264             :   }
     265             : }

Generated by: LCOV version 1.15