LCOV - code coverage report
Current view: top level - list - mongol_list_tile.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 371 440 84.3 %
Date: 2021-08-02 17:55:49 Functions: 0 0 -

          Line data    Source code
       1             : // Copyright 2014 The Flutter Authors.
       2             : // Copyright 2021 Suragch.
       3             : // All rights reserved.
       4             : // Use of this source code is governed by a BSD-style license that can be
       5             : // found in the LICENSE file.
       6             : 
       7             : import 'dart:math' as math;
       8             : import 'dart:ui';
       9             : 
      10             : import 'package:flutter/material.dart'
      11             :     show
      12             :         Colors,
      13             :         Divider,
      14             :         Ink,
      15             :         InkWell,
      16             :         ListTileStyle,
      17             :         MaterialState,
      18             :         MaterialStateMouseCursor,
      19             :         MaterialStateProperty,
      20             :         Theme,
      21             :         ThemeData,
      22             :         VisualDensity,
      23             :         debugCheckHasMaterial,
      24             :         kThemeChangeDuration;
      25             : import 'package:flutter/widgets.dart';
      26             : import 'package:flutter/rendering.dart';
      27             : 
      28             : /// An inherited widget that defines color and style parameters for [MongolListTile]s
      29             : /// in this widget's subtree.
      30             : ///
      31             : /// Values specified here are used for [MongolListTile] properties that are not given
      32             : /// an explicit non-null value.
      33             : ///
      34             : /// The [MongolDrawer] widget specifies a tile theme for its children which sets
      35             : /// [style] to [ListTileStyle.drawer].
      36             : class MongolListTileTheme extends InheritedTheme {
      37             :   /// Creates a list tile theme that controls the color and style parameters for
      38             :   /// [MongolListTile]s.
      39          11 :   const MongolListTileTheme({
      40             :     Key? key,
      41             :     this.dense = false,
      42             :     this.shape,
      43             :     this.style = ListTileStyle.list,
      44             :     this.selectedColor,
      45             :     this.iconColor,
      46             :     this.textColor,
      47             :     this.contentPadding,
      48             :     this.tileColor,
      49             :     this.selectedTileColor,
      50             :     this.enableFeedback,
      51             :     this.verticalTitleGap,
      52             :     this.minHorizontalPadding,
      53             :     this.minLeadingHeight,
      54             :     required Widget child,
      55           1 :   }) : super(key: key, child: child);
      56             : 
      57             :   /// Creates a list tile theme that controls the color and style parameters for
      58             :   /// [MongolListTile]s, and merges in the current list tile theme, if any.
      59             :   ///
      60             :   /// The [child] argument must not be null.
      61           0 :   static Widget merge({
      62             :     Key? key,
      63             :     bool? dense,
      64             :     ShapeBorder? shape,
      65             :     ListTileStyle? style,
      66             :     Color? selectedColor,
      67             :     Color? iconColor,
      68             :     Color? textColor,
      69             :     EdgeInsetsGeometry? contentPadding,
      70             :     Color? tileColor,
      71             :     Color? selectedTileColor,
      72             :     bool? enableFeedback,
      73             :     double? verticalTitleGap,
      74             :     double? minHorizontalPadding,
      75             :     double? minLeadingHeight,
      76             :     required Widget child,
      77             :   }) {
      78           0 :     return Builder(
      79           0 :       builder: (BuildContext context) {
      80           0 :         final MongolListTileTheme parent = MongolListTileTheme.of(context);
      81           0 :         return MongolListTileTheme(
      82             :           key: key,
      83           0 :           dense: dense ?? parent.dense,
      84           0 :           shape: shape ?? parent.shape,
      85           0 :           style: style ?? parent.style,
      86           0 :           selectedColor: selectedColor ?? parent.selectedColor,
      87           0 :           iconColor: iconColor ?? parent.iconColor,
      88           0 :           textColor: textColor ?? parent.textColor,
      89           0 :           contentPadding: contentPadding ?? parent.contentPadding,
      90           0 :           tileColor: tileColor ?? parent.tileColor,
      91           0 :           selectedTileColor: selectedTileColor ?? parent.selectedTileColor,
      92           0 :           enableFeedback: enableFeedback ?? parent.enableFeedback,
      93           0 :           verticalTitleGap: verticalTitleGap ?? parent.verticalTitleGap,
      94             :           minHorizontalPadding:
      95           0 :               minHorizontalPadding ?? parent.minHorizontalPadding,
      96           0 :           minLeadingHeight: minLeadingHeight ?? parent.minLeadingHeight,
      97             :           child: child,
      98             :         );
      99             :       },
     100             :     );
     101             :   }
     102             : 
     103             :   /// If true then [ListTile]s will have the vertically dense layout.
     104             :   final bool dense;
     105             : 
     106             :   /// If specified, [shape] defines the [MongolListTile]'s shape.
     107             :   final ShapeBorder? shape;
     108             : 
     109             :   /// If specified, [style] defines the font used for [MongolListTile] titles.
     110             :   final ListTileStyle style;
     111             : 
     112             :   /// If specified, the color used for icons and text when a [MongolListTile] is selected.
     113             :   final Color? selectedColor;
     114             : 
     115             :   /// If specified, the icon color used for enabled [MongolListTile]s that are not selected.
     116             :   final Color? iconColor;
     117             : 
     118             :   /// If specified, the text color used for enabled [MongolListTile]s that are not selected.
     119             :   final Color? textColor;
     120             : 
     121             :   /// The tile's internal padding.
     122             :   ///
     123             :   /// Insets a [MongolListTile]'s contents: its [MongolListTile.leading], [MongolListTile.title],
     124             :   /// [MongolListTile.subtitle], and [MongolListTile.trailing] widgets.
     125             :   final EdgeInsetsGeometry? contentPadding;
     126             : 
     127             :   /// If specified, defines the background color for `MongolListTile` when
     128             :   /// [MongolListTile.selected] is false.
     129             :   ///
     130             :   /// If [MongolListTile.tileColor] is provided, [tileColor] is ignored.
     131             :   final Color? tileColor;
     132             : 
     133             :   /// If specified, defines the background color for `MongolListTile` when
     134             :   /// [MongolListTile.selected] is true.
     135             :   ///
     136             :   /// If [MongolListTile.selectedTileColor] is provided, [selectedTileColor] is ignored.
     137             :   final Color? selectedTileColor;
     138             : 
     139             :   /// The vertical gap between the titles and the leading/trailing widgets.
     140             :   ///
     141             :   /// If specified, overrides the default value of [MongolListTile.verticalTitleGap].
     142             :   final double? verticalTitleGap;
     143             : 
     144             :   /// The minimum padding on the left and right of the title and subtitle widgets.
     145             :   ///
     146             :   /// If specified, overrides the default value of [MongolListTile.minHorizontalPadding].
     147             :   final double? minHorizontalPadding;
     148             : 
     149             :   /// The minimum height allocated for the [MongolListTile.leading] widget.
     150             :   ///
     151             :   /// If specified, overrides the default value of [MongolListTile.minLeadingHeight].
     152             :   final double? minLeadingHeight;
     153             : 
     154             :   /// If specified, defines the feedback property for `MongolListTile`.
     155             :   ///
     156             :   /// If [MongolListTile.enableFeedback] is provided, [enableFeedback] is ignored.
     157             :   final bool? enableFeedback;
     158             : 
     159             :   /// The closest instance of this class that encloses the given context.
     160             :   ///
     161             :   /// Typical usage is as follows:
     162             :   ///
     163             :   /// ```dart
     164             :   /// MongolListTileTheme theme = MongolListTileTheme.of(context);
     165             :   /// ```
     166           1 :   static MongolListTileTheme of(BuildContext context) {
     167             :     final MongolListTileTheme? result =
     168           1 :         context.dependOnInheritedWidgetOfExactType<MongolListTileTheme>();
     169             :     return result ?? const MongolListTileTheme(child: SizedBox());
     170             :   }
     171             : 
     172           0 :   @override
     173             :   Widget wrap(BuildContext context, Widget child) {
     174           0 :     return MongolListTileTheme(
     175           0 :       dense: dense,
     176           0 :       shape: shape,
     177           0 :       style: style,
     178           0 :       selectedColor: selectedColor,
     179           0 :       iconColor: iconColor,
     180           0 :       textColor: textColor,
     181           0 :       contentPadding: contentPadding,
     182           0 :       tileColor: tileColor,
     183           0 :       selectedTileColor: selectedTileColor,
     184           0 :       enableFeedback: enableFeedback,
     185           0 :       verticalTitleGap: verticalTitleGap,
     186           0 :       minHorizontalPadding: minHorizontalPadding,
     187           0 :       minLeadingHeight: minLeadingHeight,
     188             :       child: child,
     189             :     );
     190             :   }
     191             : 
     192           1 :   @override
     193             :   bool updateShouldNotify(MongolListTileTheme oldWidget) {
     194           3 :     return dense != oldWidget.dense ||
     195           3 :         shape != oldWidget.shape ||
     196           3 :         style != oldWidget.style ||
     197           3 :         selectedColor != oldWidget.selectedColor ||
     198           3 :         iconColor != oldWidget.iconColor ||
     199           3 :         textColor != oldWidget.textColor ||
     200           3 :         contentPadding != oldWidget.contentPadding ||
     201           3 :         tileColor != oldWidget.tileColor ||
     202           3 :         selectedTileColor != oldWidget.selectedTileColor ||
     203           3 :         enableFeedback != oldWidget.enableFeedback ||
     204           3 :         verticalTitleGap != oldWidget.verticalTitleGap ||
     205           3 :         minHorizontalPadding != oldWidget.minHorizontalPadding ||
     206           3 :         minLeadingHeight != oldWidget.minLeadingHeight;
     207             :   }
     208             : }
     209             : 
     210             : /// A single fixed-width column that typically contains some text as well as
     211             : /// a leading or trailing icon.
     212             : ///
     213             : /// This widget is the vertical text version of [ListTile].
     214             : ///
     215             : /// {@youtube 560 315 https://www.youtube.com/watch?v=l8dj0yPBvgQ}
     216             : ///
     217             : /// A list tile contains one to three lines of text optionally flanked by icons or
     218             : /// other widgets, such as check boxes. The icons (or other widgets) for the
     219             : /// tile are defined with the [leading] and [trailing] parameters. The first
     220             : /// line of text is not optional and is specified with [title]. The value of
     221             : /// [subtitle], which _is_ optional, will occupy the space allocated for an
     222             : /// additional line of text, or two lines if [isThreeLine] is true. If [dense]
     223             : /// is true then the overall width of this tile and the size of the
     224             : /// [DefaultTextStyle]s that wrap the [title] and [subtitle] widget are reduced.
     225             : ///
     226             : /// It is the responsibility of the caller to ensure that [title] does not wrap,
     227             : /// and to ensure that [subtitle] doesn't wrap (if [isThreeLine] is false) or
     228             : /// wraps to two lines (if it is true).
     229             : ///
     230             : /// The widths of the [leading] and [trailing] widgets are constrained
     231             : /// according to the
     232             : /// [Material spec](https://material.io/design/components/lists.html).
     233             : /// An exception is made for one-line MongolListTiles for accessibility. Please
     234             : /// see the example below to see how to adhere to both Material spec and
     235             : /// accessibility requirements.
     236             : ///
     237             : /// Note that [leading] and [trailing] widgets can expand as far as they wish
     238             : /// vertically, so ensure that they are properly constrained.
     239             : ///
     240             : /// List tiles are typically used in horizontal [ListView]s, or arranged in [Rows]s in
     241             : /// [MongolDrawer]s and [Card]s.
     242             : ///
     243             : /// Requires one of its ancestors to be a [Material] widget.
     244             : ///
     245             : /// {@tool snippet}
     246             : ///
     247             : /// This example uses a [ListView] to demonstrate different configurations of
     248             : /// [MongolListTile]s in [Card]s.
     249             : ///
     250             : /// ![Different variations of ListTile](https://flutter.github.io/assets-for-api-docs/assets/material/list_tile.png)
     251             : ///
     252             : /// ```dart
     253             : /// ListView(
     254             : ///   scrollDirection: Axis.horizontal,
     255             : ///   children: const <Widget>[
     256             : ///     Card(child: MongolListTile(title: Text('One-line MongolListTile'))),
     257             : ///     Card(
     258             : ///       child: MongolListTile(
     259             : ///         leading: FlutterLogo(),
     260             : ///         title: MongolText('One-line with leading widget'),
     261             : ///       ),
     262             : ///     ),
     263             : ///     Card(
     264             : ///       child: MongolListTile(
     265             : ///         title: MongolText('One-line with trailing widget'),
     266             : ///         trailing: Icon(Icons.more_vert),
     267             : ///       ),
     268             : ///     ),
     269             : ///     Card(
     270             : ///       child: MongolListTile(
     271             : ///         leading: FlutterLogo(),
     272             : ///         title: MongolText('One-line with both widgets'),
     273             : ///         trailing: Icon(Icons.more_vert),
     274             : ///       ),
     275             : ///     ),
     276             : ///     Card(
     277             : ///       child: MongolListTile(
     278             : ///         title: MongolText('One-line dense MongolListTile'),
     279             : ///         dense: true,
     280             : ///       ),
     281             : ///     ),
     282             : ///     Card(
     283             : ///       child: MongolListTile(
     284             : ///         leading: FlutterLogo(size: 56.0),
     285             : ///         title: MongolText('Two-line MongolListTile'),
     286             : ///         subtitle: MongolText('Here is a second line'),
     287             : ///         trailing: Icon(Icons.more_vert),
     288             : ///       ),
     289             : ///     ),
     290             : ///     Card(
     291             : ///       child: MongolListTile(
     292             : ///         leading: FlutterLogo(size: 72.0),
     293             : ///         title: MongolText('Three-line MongolListTile'),
     294             : ///         subtitle: MongolText(
     295             : ///           'A sufficiently long subtitle warrants three lines.'
     296             : ///         ),
     297             : ///         trailing: Icon(Icons.more_vert),
     298             : ///         isThreeLine: true,
     299             : ///       ),
     300             : ///     ),
     301             : ///   ],
     302             : /// )
     303             : /// ```
     304             : /// {@end-tool}
     305             : /// {@tool snippet}
     306             : ///
     307             : /// To use a [MongolListTile] within a [Column], it needs to be wrapped in an
     308             : /// [Expanded] widget. [MongolListTile] requires fixed height constraints,
     309             : /// whereas a [Column] does not constrain its children.
     310             : ///
     311             : /// ```dart
     312             : /// Column(
     313             : ///   children: const <Widget>[
     314             : ///     Expanded(
     315             : ///       child: MongolListTile(
     316             : ///         leading: FlutterLogo(),
     317             : ///         title: MongolText('These MongolListTiles are expanded '),
     318             : ///       ),
     319             : ///     ),
     320             : ///     Expanded(
     321             : ///       child: MongolListTile(
     322             : ///         trailing: FlutterLogo(),
     323             : ///         title: MongolText('to fill the available space.'),
     324             : ///       ),
     325             : ///     ),
     326             : ///   ],
     327             : /// )
     328             : /// ```
     329             : /// {@end-tool}
     330             : /// {@tool snippet}
     331             : ///
     332             : /// Tiles can be much more elaborate. Here is a tile which can be tapped, but
     333             : /// which is disabled when the `_act` variable is not 2. When the tile is
     334             : /// tapped, the whole column has an ink splash effect (see [InkWell]).
     335             : ///
     336             : /// ```dart
     337             : /// int _act = 1;
     338             : /// // ...
     339             : /// MongolListTile(
     340             : ///   leading: const Icon(Icons.flight_land),
     341             : ///   title: const MongolText("Trix's airplane"),
     342             : ///   subtitle: _act != 2 ? const MongolText('The airplane is only in Act II.') : null,
     343             : ///   enabled: _act == 2,
     344             : ///   onTap: () { /* react to the tile being tapped */ }
     345             : /// )
     346             : /// ```
     347             : /// {@end-tool}
     348             : ///
     349             : /// To be accessible, tappable [leading] and [trailing] widgets have to
     350             : /// be at least 48x48 in size. However, to adhere to the Material spec,
     351             : /// [trailing] and [leading] widgets in one-line MongolListTiles should visually be
     352             : /// at most 32 ([dense]: true) or 40 ([dense]: false) in width, which may
     353             : /// conflict with the accessibility requirement.
     354             : ///
     355             : /// For this reason, a one-line MongolListTile allows the width of [leading]
     356             : /// and [trailing] widgets to be constrained by the width of the MongolListTile.
     357             : /// This allows for the creation of tappable [leading] and [trailing] widgets
     358             : /// that are large enough, but it is up to the developer to ensure that
     359             : /// their widgets follow the Material spec.
     360             : ///
     361             : /// {@tool snippet}
     362             : ///
     363             : /// Here is an example of a one-line, non-[dense] MongolListTile with a
     364             : /// tappable leading widget that adheres to accessibility requirements and
     365             : /// the Material spec. To adjust the use case below for a one-line, [dense]
     366             : /// MongolListTile, adjust the horizontal padding to 8.0.
     367             : ///
     368             : /// ```dart
     369             : /// MongolListTile(
     370             : ///   leading: GestureDetector(
     371             : ///     behavior: HitTestBehavior.translucent,
     372             : ///     onTap: () {},
     373             : ///     child: Container(
     374             : ///       width: 48,
     375             : ///       height: 48,
     376             : ///       padding: const EdgeInsets.symmetric(horizontal: 4.0),
     377             : ///       alignment: Alignment.center,
     378             : ///       child: const CircleAvatar(),
     379             : ///     ),
     380             : ///   ),
     381             : ///   title: const MongolText('title'),
     382             : ///   dense: false,
     383             : /// ),
     384             : /// ```
     385             : /// {@end-tool}
     386             : ///
     387             : /// See also:
     388             : ///
     389             : ///  * [MongolListTileTheme], which defines visual properties for [MongolListTile]s.
     390             : ///  * [ListView], which can display an arbitrary number of [MongolListTile]s
     391             : ///    in a scrolling list.
     392             : ///  * [CircleAvatar], which shows an icon representing a person and is often
     393             : ///    used as the [leading] element of a MongolListTile.
     394             : ///  * [Card], which can be used with [Row] to show a few [MongolListTile]s.
     395             : ///  * [VerticalDivider], which can be used to separate [MongolListTile]s.
     396             : ///  * [MongolListTile.divideTiles], a utility for inserting [VerticalDivider]s
     397             : ///    in between [MongolListTile]s.
     398             : ///  * <https://material.io/design/components/lists.html>
     399             : ///  * Cookbook: [Use lists](https://flutter.dev/docs/cookbook/lists/basic-list)
     400             : ///  * Cookbook: [Implement swipe to dismiss](https://flutter.dev/docs/cookbook/gestures/dismissible)
     401             : class MongolListTile extends StatelessWidget {
     402             :   /// Creates a vertical list tile.
     403             :   ///
     404             :   /// If [isThreeLine] is true, then [subtitle] must not be null.
     405             :   ///
     406             :   /// Requires one of its ancestors to be a [Material] widget.
     407           2 :   const MongolListTile({
     408             :     Key? key,
     409             :     this.leading,
     410             :     this.title,
     411             :     this.subtitle,
     412             :     this.trailing,
     413             :     this.isThreeLine = false,
     414             :     this.dense,
     415             :     this.visualDensity,
     416             :     this.shape,
     417             :     this.contentPadding,
     418             :     this.enabled = true,
     419             :     this.onTap,
     420             :     this.onLongPress,
     421             :     this.mouseCursor,
     422             :     this.selected = false,
     423             :     this.focusColor,
     424             :     this.hoverColor,
     425             :     this.focusNode,
     426             :     this.autofocus = false,
     427             :     this.tileColor,
     428             :     this.selectedTileColor,
     429             :     this.enableFeedback,
     430             :     this.verticalTitleGap,
     431             :     this.minHorizontalPadding,
     432             :     this.minLeadingHeight,
     433           0 :   })  : assert(!isThreeLine || subtitle != null),
     434           1 :         super(key: key);
     435             : 
     436             :   /// A widget to display above the title.
     437             :   ///
     438             :   /// Typically an [Icon] or a [CircleAvatar] widget.
     439             :   final Widget? leading;
     440             : 
     441             :   /// The primary content of the list tile.
     442             :   ///
     443             :   /// Typically a [MongolText] widget.
     444             :   ///
     445             :   /// This should not wrap. To enforce the single line limit, use
     446             :   /// [MongolText.maxLines].
     447             :   final Widget? title;
     448             : 
     449             :   /// Additional content displayed below the title.
     450             :   ///
     451             :   /// Typically a [MongolText] widget.
     452             :   ///
     453             :   /// If [isThreeLine] is false, this should not wrap.
     454             :   ///
     455             :   /// If [isThreeLine] is true, this should be configured to take a maximum of
     456             :   /// two lines. For example, you can use [MongolText.maxLines] to enforce the number
     457             :   /// of lines.
     458             :   ///
     459             :   /// The subtitle's default [TextStyle] depends on [TextTheme.bodyText2] except
     460             :   /// [TextStyle.color]. The [TextStyle.color] depends on the value of [enabled]
     461             :   /// and [selected].
     462             :   ///
     463             :   /// When [enabled] is false, the text color is set to [ThemeData.disabledColor].
     464             :   ///
     465             :   /// When [selected] is false, the text color is set to [MongolListTileTheme.textColor]
     466             :   /// if it's not null and to [TextTheme.caption]'s color if [MongolListTileTheme.textColor]
     467             :   /// is null.
     468             :   final Widget? subtitle;
     469             : 
     470             :   /// A widget to display under the title.
     471             :   ///
     472             :   /// Typically an [Icon] widget.
     473             :   final Widget? trailing;
     474             : 
     475             :   /// Whether this list tile is intended to display three lines of text.
     476             :   ///
     477             :   /// If true, then [subtitle] must be non-null (since it is expected to give
     478             :   /// the second and third lines of text).
     479             :   ///
     480             :   /// If false, the list tile is treated as having one line if the subtitle is
     481             :   /// null and treated as having two lines if the subtitle is non-null.
     482             :   ///
     483             :   /// When using a [MongolText] widget for [title] and [subtitle], you can enforce
     484             :   /// line limits using [MongolText.maxLines].
     485             :   final bool isThreeLine;
     486             : 
     487             :   /// Whether this list tile is part of a horizontally dense list.
     488             :   ///
     489             :   /// If this property is null then its value is based on [MongolListTileTheme.dense].
     490             :   ///
     491             :   /// Dense list tiles default to a smaller width.
     492             :   final bool? dense;
     493             : 
     494             :   /// Defines how compact the list tile's layout will be.
     495             :   ///
     496             :   /// See also:
     497             :   ///
     498             :   ///  * [ThemeData.visualDensity], which specifies the [visualDensity] for all
     499             :   ///    widgets within a [Theme].
     500             :   final VisualDensity? visualDensity;
     501             : 
     502             :   /// The tile's shape.
     503             :   ///
     504             :   /// Defines the tile's [InkWell.customBorder] and [Ink.decoration] shape.
     505             :   ///
     506             :   /// If this property is null then [MongolListTileTheme.shape] is used.
     507             :   /// If that's null then a rectangular [Border] will be used.
     508             :   final ShapeBorder? shape;
     509             : 
     510             :   /// The tile's internal padding.
     511             :   ///
     512             :   /// Insets a [MongolListTile]'s contents: its [leading], [title], [subtitle],
     513             :   /// and [trailing] widgets.
     514             :   ///
     515             :   /// If null, `EdgeInsets.symmetric(vertical: 16.0)` is used.
     516             :   final EdgeInsetsGeometry? contentPadding;
     517             : 
     518             :   /// Whether this list tile is interactive.
     519             :   ///
     520             :   /// If false, this list tile is styled with the disabled color from the
     521             :   /// current [Theme] and the [onTap] and [onLongPress] callbacks are
     522             :   /// inoperative.
     523             :   final bool enabled;
     524             : 
     525             :   /// Called when the user taps this list tile.
     526             :   ///
     527             :   /// Inoperative if [enabled] is false.
     528             :   final GestureTapCallback? onTap;
     529             : 
     530             :   /// Called when the user long-presses on this list tile.
     531             :   ///
     532             :   /// Inoperative if [enabled] is false.
     533             :   final GestureLongPressCallback? onLongPress;
     534             : 
     535             :   /// The cursor for a mouse pointer when it enters or is hovering over the
     536             :   /// widget.
     537             :   ///
     538             :   /// If [mouseCursor] is a [MaterialStateProperty<MouseCursor>],
     539             :   /// [MaterialStateProperty.resolve] is used for the following [MaterialState]s:
     540             :   ///
     541             :   ///  * [MaterialState.selected].
     542             :   ///  * [MaterialState.disabled].
     543             :   ///
     544             :   /// If this property is null, [MaterialStateMouseCursor.clickable] will be used.
     545             :   final MouseCursor? mouseCursor;
     546             : 
     547             :   /// If this tile is also [enabled] then icons and text are rendered with the same color.
     548             :   ///
     549             :   /// By default the selected color is the theme's primary color. The selected color
     550             :   /// can be overridden with a [MongolListTileTheme].
     551             :   final bool selected;
     552             : 
     553             :   /// The color for the tile's [Material] when it has the input focus.
     554             :   final Color? focusColor;
     555             : 
     556             :   /// The color for the tile's [Material] when a pointer is hovering over it.
     557             :   final Color? hoverColor;
     558             : 
     559             :   /// {@macro flutter.widgets.Focus.focusNode}
     560             :   final FocusNode? focusNode;
     561             : 
     562             :   /// {@macro flutter.widgets.Focus.autofocus}
     563             :   final bool autofocus;
     564             : 
     565             :   /// Defines the background color of `MongolListTile` when [selected] is false.
     566             :   ///
     567             :   /// When the value is null, the `tileColor` is set to [MongolListTileTheme.tileColor]
     568             :   /// if it's not null and to [Colors.transparent] if it's null.
     569             :   final Color? tileColor;
     570             : 
     571             :   /// Defines the background color of ` MongolListTile` when [selected] is true.
     572             :   ///
     573             :   /// When the value if null, the `selectedTileColor` is set to
     574             :   /// [MongolListTileTheme.selectedTileColor] if it's not null and to
     575             :   /// [Colors.transparent] if it's null.
     576             :   final Color? selectedTileColor;
     577             : 
     578             :   /// Whether detected gestures should provide acoustic and/or haptic feedback.
     579             :   ///
     580             :   /// For example, on Android a tap will produce a clicking sound and a
     581             :   /// long-press will produce a short vibration, when feedback is enabled.
     582             :   ///
     583             :   /// See also:
     584             :   ///
     585             :   ///  * [Feedback] for providing platform-specific feedback to certain actions.
     586             :   final bool? enableFeedback;
     587             : 
     588             :   /// The vertical gap between the titles and the leading/trailing widgets.
     589             :   ///
     590             :   /// If null, then the value of [MongolListTileTheme.verticalTitleGap] is used. If
     591             :   /// that is also null, then a default value of 16 is used.
     592             :   final double? verticalTitleGap;
     593             : 
     594             :   /// The minimum padding on the left and right of the title and subtitle widgets.
     595             :   ///
     596             :   /// If null, then the value of [MongolListTileTheme.minHorizontalPadding] is used. If
     597             :   /// that is also null, then a default value of 4 is used.
     598             :   final double? minHorizontalPadding;
     599             : 
     600             :   /// The minimum height allocated for the [MongolListTile.leading] widget.
     601             :   ///
     602             :   /// If null, then the value of [MongolListTileTheme.minLeadingHeight] is used. If
     603             :   /// that is also null, then a default value of 40 is used.
     604             :   final double? minLeadingHeight;
     605             : 
     606             :   /// Add a one pixel border in between each tile. If color isn't specified the
     607             :   /// [ThemeData.dividerColor] of the context's [Theme] is used.
     608             :   ///
     609             :   /// See also:
     610             :   ///
     611             :   ///  * [VerticalDivider], which you can use to obtain this effect manually.
     612             :   static Iterable<Widget> divideTiles(
     613             :       {BuildContext? context,
     614             :       required Iterable<Widget> tiles,
     615             :       Color? color}) sync* {
     616             :     assert(color != null || context != null);
     617             : 
     618             :     final Iterator<Widget> iterator = tiles.iterator;
     619             :     final bool hasNext = iterator.moveNext();
     620             :     if (!hasNext) return;
     621             : 
     622             :     final Decoration decoration = BoxDecoration(
     623             :       border: Border(
     624             :         right: Divider.createBorderSide(context, color: color),
     625             :       ),
     626             :     );
     627             : 
     628             :     Widget tile = iterator.current;
     629             :     while (iterator.moveNext()) {
     630             :       yield DecoratedBox(
     631             :         position: DecorationPosition.foreground,
     632             :         decoration: decoration,
     633             :         child: tile,
     634             :       );
     635             :       tile = iterator.current;
     636             :     }
     637             :     if (hasNext) yield tile;
     638             :   }
     639             : 
     640           1 :   Color? _iconColor(ThemeData theme, MongolListTileTheme? tileTheme) {
     641           2 :     if (!enabled) return theme.disabledColor;
     642             : 
     643           2 :     if (selected && tileTheme?.selectedColor != null) {
     644           1 :       return tileTheme!.selectedColor;
     645             :     }
     646             : 
     647           3 :     if (!selected && tileTheme?.iconColor != null) return tileTheme!.iconColor;
     648             : 
     649           1 :     switch (theme.brightness) {
     650           1 :       case Brightness.light:
     651             :         // For the sake of backwards compatibility, the default for unselected
     652             :         // tiles is Colors.black45 rather than colorScheme.onSurface.withAlpha(0x73).
     653           3 :         return selected ? theme.colorScheme.primary : Colors.black45;
     654           1 :       case Brightness.dark:
     655           1 :         return selected
     656           2 :             ? theme.colorScheme.primary
     657             :             : null; // null - use current icon theme color
     658             :     }
     659             :   }
     660             : 
     661           1 :   Color? _textColor(
     662             :       ThemeData theme, MongolListTileTheme? tileTheme, Color? defaultColor) {
     663           2 :     if (!enabled) return theme.disabledColor;
     664             : 
     665           2 :     if (selected && tileTheme?.selectedColor != null) {
     666           1 :       return tileTheme!.selectedColor;
     667             :     }
     668             : 
     669           3 :     if (!selected && tileTheme?.textColor != null) return tileTheme!.textColor;
     670             : 
     671           3 :     if (selected) return theme.colorScheme.primary;
     672             : 
     673             :     return defaultColor;
     674             :   }
     675             : 
     676           1 :   bool _isDenseLayout(MongolListTileTheme? tileTheme) {
     677           2 :     return dense ?? tileTheme?.dense ?? false;
     678             :   }
     679             : 
     680           1 :   TextStyle _titleTextStyle(ThemeData theme, MongolListTileTheme? tileTheme) {
     681             :     final TextStyle style;
     682             :     if (tileTheme != null) {
     683           1 :       switch (tileTheme.style) {
     684           1 :         case ListTileStyle.drawer:
     685           0 :           style = theme.textTheme.bodyText1!;
     686             :           break;
     687           1 :         case ListTileStyle.list:
     688           2 :           style = theme.textTheme.subtitle1!;
     689             :           break;
     690             :       }
     691             :     } else {
     692           0 :       style = theme.textTheme.subtitle1!;
     693             :     }
     694           2 :     final Color? color = _textColor(theme, tileTheme, style.color);
     695           1 :     return _isDenseLayout(tileTheme)
     696           1 :         ? style.copyWith(fontSize: 13.0, color: color)
     697           1 :         : style.copyWith(color: color);
     698             :   }
     699             : 
     700           1 :   TextStyle _subtitleTextStyle(
     701             :       ThemeData theme, MongolListTileTheme? tileTheme) {
     702           2 :     final TextStyle style = theme.textTheme.bodyText2!;
     703             :     final Color? color =
     704           4 :         _textColor(theme, tileTheme, theme.textTheme.caption!.color);
     705           1 :     return _isDenseLayout(tileTheme)
     706           1 :         ? style.copyWith(color: color, fontSize: 12.0)
     707           1 :         : style.copyWith(color: color);
     708             :   }
     709             : 
     710           1 :   TextStyle _trailingAndLeadingTextStyle(
     711             :       ThemeData theme, MongolListTileTheme? tileTheme) {
     712           2 :     final TextStyle style = theme.textTheme.bodyText2!;
     713           2 :     final Color? color = _textColor(theme, tileTheme, style.color);
     714           1 :     return style.copyWith(color: color);
     715             :   }
     716             : 
     717           1 :   Color _tileBackgroundColor(MongolListTileTheme? tileTheme) {
     718           1 :     if (!selected) {
     719           2 :       if (tileColor != null) return tileColor!;
     720           2 :       if (tileTheme?.tileColor != null) return tileTheme!.tileColor!;
     721             :     }
     722             : 
     723           1 :     if (selected) {
     724           2 :       if (selectedTileColor != null) return selectedTileColor!;
     725           1 :       if (tileTheme?.selectedTileColor != null) {
     726           1 :         return tileTheme!.selectedTileColor!;
     727             :       }
     728             :     }
     729             : 
     730             :     return Colors.transparent;
     731             :   }
     732             : 
     733           1 :   @override
     734             :   Widget build(BuildContext context) {
     735           1 :     assert(debugCheckHasMaterial(context));
     736           1 :     final ThemeData theme = Theme.of(context);
     737           1 :     final MongolListTileTheme tileTheme = MongolListTileTheme.of(context);
     738             : 
     739             :     IconThemeData? iconThemeData;
     740             :     TextStyle? leadingAndTrailingTextStyle;
     741           2 :     if (leading != null || trailing != null) {
     742           2 :       iconThemeData = IconThemeData(color: _iconColor(theme, tileTheme));
     743             :       leadingAndTrailingTextStyle =
     744           1 :           _trailingAndLeadingTextStyle(theme, tileTheme);
     745             :     }
     746             : 
     747             :     Widget? leadingIcon;
     748           1 :     if (leading != null) {
     749           1 :       leadingIcon = AnimatedDefaultTextStyle(
     750             :         style: leadingAndTrailingTextStyle!,
     751             :         duration: kThemeChangeDuration,
     752           1 :         child: IconTheme.merge(
     753             :           data: iconThemeData!,
     754           1 :           child: leading!,
     755             :         ),
     756             :       );
     757             :     }
     758             : 
     759           1 :     final TextStyle titleStyle = _titleTextStyle(theme, tileTheme);
     760           1 :     final Widget titleText = AnimatedDefaultTextStyle(
     761             :       style: titleStyle,
     762             :       duration: kThemeChangeDuration,
     763           1 :       child: title ?? const SizedBox(),
     764             :     );
     765             : 
     766             :     Widget? subtitleText;
     767             :     TextStyle? subtitleStyle;
     768           1 :     if (subtitle != null) {
     769           1 :       subtitleStyle = _subtitleTextStyle(theme, tileTheme);
     770           1 :       subtitleText = AnimatedDefaultTextStyle(
     771             :         style: subtitleStyle,
     772             :         duration: kThemeChangeDuration,
     773           1 :         child: subtitle!,
     774             :       );
     775             :     }
     776             : 
     777             :     Widget? trailingIcon;
     778           1 :     if (trailing != null) {
     779           1 :       trailingIcon = AnimatedDefaultTextStyle(
     780             :         style: leadingAndTrailingTextStyle!,
     781             :         duration: kThemeChangeDuration,
     782           1 :         child: IconTheme.merge(
     783             :           data: iconThemeData!,
     784           1 :           child: trailing!,
     785             :         ),
     786             :       );
     787             :     }
     788             : 
     789             :     const EdgeInsets _defaultContentPadding =
     790             :         EdgeInsets.symmetric(vertical: 16.0);
     791             :     const TextDirection textDirection = TextDirection.ltr;
     792             :     final EdgeInsets resolvedContentPadding =
     793           2 :         contentPadding?.resolve(textDirection) ??
     794           1 :             tileTheme.contentPadding?.resolve(textDirection) ??
     795             :             _defaultContentPadding;
     796             : 
     797             :     final MouseCursor resolvedMouseCursor =
     798           1 :         MaterialStateProperty.resolveAs<MouseCursor>(
     799           1 :       mouseCursor ?? MaterialStateMouseCursor.clickable,
     800             :       <MaterialState>{
     801           3 :         if (!enabled || (onTap == null && onLongPress == null))
     802           1 :           MaterialState.disabled,
     803           2 :         if (selected) MaterialState.selected,
     804             :       },
     805             :     );
     806             : 
     807           1 :     return InkWell(
     808           2 :       customBorder: shape ?? tileTheme.shape,
     809           2 :       onTap: enabled ? onTap : null,
     810           2 :       onLongPress: enabled ? onLongPress : null,
     811             :       mouseCursor: resolvedMouseCursor,
     812           1 :       canRequestFocus: enabled,
     813           1 :       focusNode: focusNode,
     814           1 :       focusColor: focusColor,
     815           1 :       hoverColor: hoverColor,
     816           1 :       autofocus: autofocus,
     817           2 :       enableFeedback: enableFeedback ?? tileTheme.enableFeedback ?? true,
     818           1 :       child: Semantics(
     819           1 :         selected: selected,
     820           1 :         enabled: enabled,
     821           1 :         child: Ink(
     822           1 :           decoration: ShapeDecoration(
     823           2 :             shape: shape ?? tileTheme.shape ?? const Border(),
     824           1 :             color: _tileBackgroundColor(tileTheme),
     825             :           ),
     826           1 :           child: SafeArea(
     827             :             left: false,
     828             :             right: false,
     829             :             minimum: resolvedContentPadding,
     830           1 :             child: _MongolListTile(
     831             :               leading: leadingIcon,
     832             :               title: titleText,
     833             :               subtitle: subtitleText,
     834             :               trailing: trailingIcon,
     835           1 :               isDense: _isDenseLayout(tileTheme),
     836           2 :               visualDensity: visualDensity ?? theme.visualDensity,
     837           1 :               isThreeLine: isThreeLine,
     838           1 :               titleBaselineType: titleStyle.textBaseline!,
     839           1 :               subtitleBaselineType: subtitleStyle?.textBaseline,
     840             :               verticalTitleGap:
     841           2 :                   verticalTitleGap ?? tileTheme.verticalTitleGap ?? 16,
     842             :               minHorizontalPadding:
     843           2 :                   minHorizontalPadding ?? tileTheme.minHorizontalPadding ?? 4,
     844             :               minLeadingHeight:
     845           2 :                   minLeadingHeight ?? tileTheme.minLeadingHeight ?? 40,
     846             :             ),
     847             :           ),
     848             :         ),
     849             :       ),
     850             :     );
     851             :   }
     852             : }
     853             : 
     854             : // Identifies the children of a _MongolListTileElement.
     855          10 : enum _ListTileSlot {
     856             :   leading,
     857             :   title,
     858             :   subtitle,
     859             :   trailing,
     860             : }
     861             : 
     862             : class _MongolListTile extends RenderObjectWidget {
     863           1 :   const _MongolListTile({
     864             :     Key? key,
     865             :     this.leading,
     866             :     required this.title,
     867             :     this.subtitle,
     868             :     this.trailing,
     869             :     required this.isThreeLine,
     870             :     required this.isDense,
     871             :     required this.visualDensity,
     872             :     required this.titleBaselineType,
     873             :     required this.verticalTitleGap,
     874             :     required this.minHorizontalPadding,
     875             :     required this.minLeadingHeight,
     876             :     this.subtitleBaselineType,
     877           1 :   }) : super(key: key);
     878             : 
     879             :   final Widget? leading;
     880             :   final Widget title;
     881             :   final Widget? subtitle;
     882             :   final Widget? trailing;
     883             :   final bool isThreeLine;
     884             :   final bool isDense;
     885             :   final VisualDensity visualDensity;
     886             :   final TextBaseline titleBaselineType;
     887             :   final TextBaseline? subtitleBaselineType;
     888             :   final double verticalTitleGap;
     889             :   final double minHorizontalPadding;
     890             :   final double minLeadingHeight;
     891             : 
     892           1 :   @override
     893           1 :   _MongolListTileElement createElement() => _MongolListTileElement(this);
     894             : 
     895           1 :   @override
     896             :   _MongolRenderListTile createRenderObject(BuildContext context) {
     897           1 :     return _MongolRenderListTile(
     898           1 :       isThreeLine: isThreeLine,
     899           1 :       isDense: isDense,
     900           1 :       visualDensity: visualDensity,
     901           1 :       titleBaselineType: titleBaselineType,
     902           1 :       subtitleBaselineType: subtitleBaselineType,
     903           1 :       verticalTitleGap: verticalTitleGap,
     904           1 :       minHorizontalPadding: minHorizontalPadding,
     905           1 :       minLeadingHeight: minLeadingHeight,
     906             :     );
     907             :   }
     908             : 
     909           1 :   @override
     910             :   void updateRenderObject(
     911             :       BuildContext context, _MongolRenderListTile renderObject) {
     912             :     renderObject
     913           2 :       ..isThreeLine = isThreeLine
     914           2 :       ..isDense = isDense
     915           2 :       ..visualDensity = visualDensity
     916           2 :       ..titleBaselineType = titleBaselineType
     917           2 :       ..subtitleBaselineType = subtitleBaselineType
     918           2 :       ..verticalTitleGap = verticalTitleGap
     919           2 :       ..minHorizontalPadding = minHorizontalPadding
     920           2 :       ..minLeadingHeight = minLeadingHeight;
     921             :   }
     922             : }
     923             : 
     924             : class _MongolListTileElement extends RenderObjectElement {
     925           2 :   _MongolListTileElement(_MongolListTile widget) : super(widget);
     926             : 
     927             :   final Map<_ListTileSlot, Element> slotToChild = <_ListTileSlot, Element>{};
     928             : 
     929           1 :   @override
     930           1 :   _MongolListTile get widget => super.widget as _MongolListTile;
     931             : 
     932           1 :   @override
     933             :   _MongolRenderListTile get renderObject =>
     934           1 :       super.renderObject as _MongolRenderListTile;
     935             : 
     936           1 :   @override
     937             :   void visitChildren(ElementVisitor visitor) {
     938           3 :     slotToChild.values.forEach(visitor);
     939             :   }
     940             : 
     941           0 :   @override
     942             :   void forgetChild(Element child) {
     943           0 :     assert(slotToChild.containsValue(child));
     944           0 :     assert(child.slot is _ListTileSlot);
     945           0 :     assert(slotToChild.containsKey(child.slot));
     946           0 :     slotToChild.remove(child.slot);
     947           0 :     super.forgetChild(child);
     948             :   }
     949             : 
     950           1 :   void _mountChild(Widget? widget, _ListTileSlot slot) {
     951           2 :     final Element? oldChild = slotToChild[slot];
     952           1 :     final Element? newChild = updateChild(oldChild, widget, slot);
     953             :     if (oldChild != null) {
     954           0 :       slotToChild.remove(slot);
     955             :     }
     956             :     if (newChild != null) {
     957           2 :       slotToChild[slot] = newChild;
     958             :     }
     959             :   }
     960             : 
     961           1 :   @override
     962             :   void mount(Element? parent, Object? newSlot) {
     963           1 :     super.mount(parent, newSlot);
     964           3 :     _mountChild(widget.leading, _ListTileSlot.leading);
     965           3 :     _mountChild(widget.title, _ListTileSlot.title);
     966           3 :     _mountChild(widget.subtitle, _ListTileSlot.subtitle);
     967           3 :     _mountChild(widget.trailing, _ListTileSlot.trailing);
     968             :   }
     969             : 
     970           1 :   void _updateChild(Widget? widget, _ListTileSlot slot) {
     971           2 :     final Element? oldChild = slotToChild[slot];
     972           1 :     final Element? newChild = updateChild(oldChild, widget, slot);
     973             :     if (oldChild != null) {
     974           2 :       slotToChild.remove(slot);
     975             :     }
     976             :     if (newChild != null) {
     977           2 :       slotToChild[slot] = newChild;
     978             :     }
     979             :   }
     980             : 
     981           1 :   @override
     982             :   void update(_MongolListTile newWidget) {
     983           1 :     super.update(newWidget);
     984           2 :     assert(widget == newWidget);
     985           3 :     _updateChild(widget.leading, _ListTileSlot.leading);
     986           3 :     _updateChild(widget.title, _ListTileSlot.title);
     987           3 :     _updateChild(widget.subtitle, _ListTileSlot.subtitle);
     988           3 :     _updateChild(widget.trailing, _ListTileSlot.trailing);
     989             :   }
     990             : 
     991           1 :   void _updateRenderObject(RenderBox? child, _ListTileSlot slot) {
     992             :     switch (slot) {
     993           1 :       case _ListTileSlot.leading:
     994           2 :         renderObject.leading = child;
     995             :         break;
     996           1 :       case _ListTileSlot.title:
     997           2 :         renderObject.title = child;
     998             :         break;
     999           1 :       case _ListTileSlot.subtitle:
    1000           2 :         renderObject.subtitle = child;
    1001             :         break;
    1002           1 :       case _ListTileSlot.trailing:
    1003           2 :         renderObject.trailing = child;
    1004             :         break;
    1005             :     }
    1006             :   }
    1007             : 
    1008           1 :   @override
    1009             :   void insertRenderObjectChild(RenderObject child, _ListTileSlot slot) {
    1010           1 :     assert(child is RenderBox);
    1011           1 :     _updateRenderObject(child as RenderBox, slot);
    1012           4 :     assert(renderObject.children.keys.contains(slot));
    1013             :   }
    1014             : 
    1015           1 :   @override
    1016             :   void removeRenderObjectChild(RenderObject child, _ListTileSlot slot) {
    1017           1 :     assert(child is RenderBox);
    1018           4 :     assert(renderObject.children[slot] == child);
    1019           1 :     _updateRenderObject(null, slot);
    1020           4 :     assert(!renderObject.children.keys.contains(slot));
    1021             :   }
    1022             : 
    1023           0 :   @override
    1024             :   void moveRenderObjectChild(
    1025             :       RenderObject child, Object? oldSlot, Object? newSlot) {
    1026           0 :     assert(false, 'not reachable');
    1027             :   }
    1028             : }
    1029             : 
    1030             : class _MongolRenderListTile extends RenderBox {
    1031           1 :   _MongolRenderListTile({
    1032             :     required bool isDense,
    1033             :     required VisualDensity visualDensity,
    1034             :     required bool isThreeLine,
    1035             :     required TextBaseline titleBaselineType,
    1036             :     TextBaseline? subtitleBaselineType,
    1037             :     required double verticalTitleGap,
    1038             :     required double minHorizontalPadding,
    1039             :     required double minLeadingHeight,
    1040             :   })  : _isDense = isDense,
    1041             :         _visualDensity = visualDensity,
    1042             :         _isThreeLine = isThreeLine,
    1043             :         _titleBaselineType = titleBaselineType,
    1044             :         _subtitleBaselineType = subtitleBaselineType,
    1045             :         _verticalTitleGap = verticalTitleGap,
    1046             :         _minHorizontalPadding = minHorizontalPadding,
    1047             :         _minLeadingHeight = minLeadingHeight;
    1048             : 
    1049             :   final Map<_ListTileSlot, RenderBox> children = <_ListTileSlot, RenderBox>{};
    1050             : 
    1051           1 :   RenderBox? _updateChild(
    1052             :       RenderBox? oldChild, RenderBox? newChild, _ListTileSlot slot) {
    1053             :     if (oldChild != null) {
    1054           1 :       dropChild(oldChild);
    1055           2 :       children.remove(slot);
    1056             :     }
    1057             :     if (newChild != null) {
    1058           2 :       children[slot] = newChild;
    1059           1 :       adoptChild(newChild);
    1060             :     }
    1061             :     return newChild;
    1062             :   }
    1063             : 
    1064             :   RenderBox? _leading;
    1065           2 :   RenderBox? get leading => _leading;
    1066           1 :   set leading(RenderBox? value) {
    1067           3 :     _leading = _updateChild(_leading, value, _ListTileSlot.leading);
    1068             :   }
    1069             : 
    1070             :   RenderBox? _title;
    1071           2 :   RenderBox? get title => _title;
    1072           1 :   set title(RenderBox? value) {
    1073           3 :     _title = _updateChild(_title, value, _ListTileSlot.title);
    1074             :   }
    1075             : 
    1076             :   RenderBox? _subtitle;
    1077           2 :   RenderBox? get subtitle => _subtitle;
    1078           1 :   set subtitle(RenderBox? value) {
    1079           3 :     _subtitle = _updateChild(_subtitle, value, _ListTileSlot.subtitle);
    1080             :   }
    1081             : 
    1082             :   RenderBox? _trailing;
    1083           2 :   RenderBox? get trailing => _trailing;
    1084           1 :   set trailing(RenderBox? value) {
    1085           3 :     _trailing = _updateChild(_trailing, value, _ListTileSlot.trailing);
    1086             :   }
    1087             : 
    1088             :   // The returned list is ordered for hit testing.
    1089             :   Iterable<RenderBox> get _children sync* {
    1090             :     if (leading != null) yield leading!;
    1091             :     if (title != null) yield title!;
    1092             :     if (subtitle != null) yield subtitle!;
    1093             :     if (trailing != null) yield trailing!;
    1094             :   }
    1095             : 
    1096           2 :   bool get isDense => _isDense;
    1097             :   bool _isDense;
    1098           1 :   set isDense(bool value) {
    1099           2 :     if (_isDense == value) return;
    1100           1 :     _isDense = value;
    1101           1 :     markNeedsLayout();
    1102             :   }
    1103             : 
    1104           2 :   VisualDensity get visualDensity => _visualDensity;
    1105             :   VisualDensity _visualDensity;
    1106           1 :   set visualDensity(VisualDensity value) {
    1107           2 :     if (_visualDensity == value) return;
    1108           1 :     _visualDensity = value;
    1109           1 :     markNeedsLayout();
    1110             :   }
    1111             : 
    1112           2 :   bool get isThreeLine => _isThreeLine;
    1113             :   bool _isThreeLine;
    1114           1 :   set isThreeLine(bool value) {
    1115           2 :     if (_isThreeLine == value) return;
    1116           1 :     _isThreeLine = value;
    1117           1 :     markNeedsLayout();
    1118             :   }
    1119             : 
    1120           2 :   TextBaseline get titleBaselineType => _titleBaselineType;
    1121             :   TextBaseline _titleBaselineType;
    1122           1 :   set titleBaselineType(TextBaseline value) {
    1123           2 :     if (_titleBaselineType == value) return;
    1124           0 :     _titleBaselineType = value;
    1125           0 :     markNeedsLayout();
    1126             :   }
    1127             : 
    1128           2 :   TextBaseline? get subtitleBaselineType => _subtitleBaselineType;
    1129             :   TextBaseline? _subtitleBaselineType;
    1130           1 :   set subtitleBaselineType(TextBaseline? value) {
    1131           2 :     if (_subtitleBaselineType == value) return;
    1132           1 :     _subtitleBaselineType = value;
    1133           1 :     markNeedsLayout();
    1134             :   }
    1135             : 
    1136           0 :   double get verticalTitleGap => _verticalTitleGap;
    1137             :   double _verticalTitleGap;
    1138           1 :   double get _effectiveVerticalTitleGap =>
    1139           5 :       _verticalTitleGap + visualDensity.vertical * 2.0;
    1140             : 
    1141           1 :   set verticalTitleGap(double value) {
    1142           2 :     if (_verticalTitleGap == value) return;
    1143           0 :     _verticalTitleGap = value;
    1144           0 :     markNeedsLayout();
    1145             :   }
    1146             : 
    1147           0 :   double get minHorizontalPadding => _minHorizontalPadding;
    1148             :   double _minHorizontalPadding;
    1149             : 
    1150           1 :   set minHorizontalPadding(double value) {
    1151           2 :     if (_minHorizontalPadding == value) return;
    1152           0 :     _minHorizontalPadding = value;
    1153           0 :     markNeedsLayout();
    1154             :   }
    1155             : 
    1156           0 :   double get minLeadingHeight => _minLeadingHeight;
    1157             :   double _minLeadingHeight;
    1158             : 
    1159           1 :   set minLeadingHeight(double value) {
    1160           2 :     if (_minLeadingHeight == value) return;
    1161           0 :     _minLeadingHeight = value;
    1162           0 :     markNeedsLayout();
    1163             :   }
    1164             : 
    1165           1 :   @override
    1166             :   void attach(PipelineOwner owner) {
    1167           1 :     super.attach(owner);
    1168           1 :     for (final RenderBox child in _children) {
    1169           0 :       child.attach(owner);
    1170             :     }
    1171             :   }
    1172             : 
    1173           1 :   @override
    1174             :   void detach() {
    1175           1 :     super.detach();
    1176           2 :     for (final RenderBox child in _children) {
    1177           1 :       child.detach();
    1178             :     }
    1179             :   }
    1180             : 
    1181           1 :   @override
    1182             :   void redepthChildren() {
    1183           3 :     _children.forEach(redepthChild);
    1184             :   }
    1185             : 
    1186           1 :   @override
    1187             :   void visitChildren(RenderObjectVisitor visitor) {
    1188           2 :     _children.forEach(visitor);
    1189             :   }
    1190             : 
    1191           0 :   @override
    1192             :   List<DiagnosticsNode> debugDescribeChildren() {
    1193           0 :     final List<DiagnosticsNode> value = <DiagnosticsNode>[];
    1194           0 :     void add(RenderBox? child, String name) {
    1195           0 :       if (child != null) value.add(child.toDiagnosticsNode(name: name));
    1196             :     }
    1197             : 
    1198           0 :     add(leading, 'leading');
    1199           0 :     add(title, 'title');
    1200           0 :     add(subtitle, 'subtitle');
    1201           0 :     add(trailing, 'trailing');
    1202             :     return value;
    1203             :   }
    1204             : 
    1205           1 :   @override
    1206             :   bool get sizedByParent => false;
    1207             : 
    1208           1 :   static double _minHeight(RenderBox? box, double width) {
    1209           1 :     return box == null ? 0.0 : box.getMinIntrinsicHeight(width);
    1210             :   }
    1211             : 
    1212           1 :   static double _maxHeight(RenderBox? box, double width) {
    1213           1 :     return box == null ? 0.0 : box.getMaxIntrinsicHeight(width);
    1214             :   }
    1215             : 
    1216           1 :   @override
    1217             :   double computeMinIntrinsicHeight(double width) {
    1218           1 :     final double leadingHeight = leading != null
    1219           5 :         ? math.max(leading!.getMinIntrinsicHeight(width), _minLeadingHeight) +
    1220           1 :             _effectiveVerticalTitleGap
    1221             :         : 0.0;
    1222           1 :     return leadingHeight +
    1223           6 :         math.max(_minHeight(title, width), _minHeight(subtitle, width)) +
    1224           2 :         _maxHeight(trailing, width);
    1225             :   }
    1226             : 
    1227           1 :   @override
    1228             :   double computeMaxIntrinsicHeight(double width) {
    1229           1 :     final double leadingHeight = leading != null
    1230           5 :         ? math.max(leading!.getMaxIntrinsicHeight(width), _minLeadingHeight) +
    1231           1 :             _effectiveVerticalTitleGap
    1232             :         : 0.0;
    1233           1 :     return leadingHeight +
    1234           6 :         math.max(_maxHeight(title, width), _maxHeight(subtitle, width)) +
    1235           2 :         _maxHeight(trailing, width);
    1236             :   }
    1237             : 
    1238           1 :   double get _defaultTileWidth {
    1239           1 :     final bool hasSubtitle = subtitle != null;
    1240           1 :     final bool isTwoLine = !isThreeLine && hasSubtitle;
    1241           1 :     final bool isOneLine = !isThreeLine && !hasSubtitle;
    1242             : 
    1243           2 :     final Offset baseDensity = visualDensity.baseSizeAdjustment;
    1244           3 :     if (isOneLine) return (isDense ? 48.0 : 56.0) + baseDensity.dx;
    1245           3 :     if (isTwoLine) return (isDense ? 64.0 : 72.0) + baseDensity.dx;
    1246           3 :     return (isDense ? 76.0 : 88.0) + baseDensity.dx;
    1247             :   }
    1248             : 
    1249           1 :   @override
    1250             :   double computeMinIntrinsicWidth(double height) {
    1251           1 :     return math.max(
    1252           1 :       _defaultTileWidth,
    1253           3 :       title!.getMinIntrinsicWidth(height) +
    1254           2 :           (subtitle?.getMinIntrinsicWidth(height) ?? 0.0),
    1255             :     );
    1256             :   }
    1257             : 
    1258           1 :   @override
    1259             :   double computeMaxIntrinsicWidth(double height) {
    1260           1 :     return computeMinIntrinsicWidth(height);
    1261             :   }
    1262             : 
    1263           0 :   @override
    1264             :   double computeDistanceToActualBaseline(TextBaseline baseline) {
    1265             :     return 0.0;
    1266             :   }
    1267             : 
    1268           1 :   static double? _boxBaseline(RenderBox box, TextBaseline baseline) {
    1269           1 :     return box.getDistanceToBaseline(baseline);
    1270             :   }
    1271             : 
    1272           1 :   static Size _layoutBox(RenderBox? box, BoxConstraints constraints) {
    1273             :     if (box == null) return Size.zero;
    1274           1 :     box.layout(constraints, parentUsesSize: true);
    1275           1 :     return box.size;
    1276             :   }
    1277             : 
    1278           1 :   static void _positionBox(RenderBox box, Offset offset) {
    1279           1 :     final BoxParentData parentData = box.parentData! as BoxParentData;
    1280           1 :     parentData.offset = offset;
    1281             :   }
    1282             : 
    1283           1 :   @override
    1284             :   Size computeDryLayout(BoxConstraints constraints) {
    1285           1 :     assert(debugCannotComputeDryLayout(
    1286             :       reason:
    1287             :           'Layout requires baseline metrics, which are only available after a full layout.',
    1288             :     ));
    1289             :     return Size.zero;
    1290             :   }
    1291             : 
    1292             :   // All of the dimensions below were taken from the Material Design spec:
    1293             :   // https://material.io/design/components/lists.html#specs
    1294           1 :   @override
    1295             :   void performLayout() {
    1296           1 :     final BoxConstraints constraints = this.constraints;
    1297           1 :     final bool hasLeading = leading != null;
    1298           1 :     final bool hasSubtitle = subtitle != null;
    1299           1 :     final bool hasTrailing = trailing != null;
    1300           1 :     final bool isTwoLine = !isThreeLine && hasSubtitle;
    1301           1 :     final bool isOneLine = !isThreeLine && !hasSubtitle;
    1302           2 :     final Offset densityAdjustment = visualDensity.baseSizeAdjustment;
    1303             : 
    1304           1 :     final BoxConstraints maxIconWidthConstraint = BoxConstraints(
    1305             :       // One-line trailing and leading widget widths do not follow
    1306             :       // Material specifications, but this sizing is required to adhere
    1307             :       // to accessibility requirements for smallest tappable widget.
    1308             :       // Two- and three-line trailing widget widths are constrained
    1309             :       // properly according to the Material spec.
    1310           3 :       maxWidth: (isDense ? 48.0 : 56.0) + densityAdjustment.dx,
    1311             :     );
    1312           1 :     final BoxConstraints looseConstraints = constraints.loosen();
    1313             :     final BoxConstraints iconConstraints =
    1314           1 :         looseConstraints.enforce(maxIconWidthConstraint);
    1315             : 
    1316           1 :     final double tileHeight = looseConstraints.maxHeight;
    1317           2 :     final Size leadingSize = _layoutBox(leading, iconConstraints);
    1318           2 :     final Size trailingSize = _layoutBox(trailing, iconConstraints);
    1319             :     assert(
    1320           3 :       tileHeight != leadingSize.height || tileHeight == 0.0,
    1321             :       'Leading widget consumes entire tile height. Please use a sized widget, '
    1322             :       'or consider replacing MongolListTile with a custom widget '
    1323             :       '(see https://api.flutter.dev/flutter/material/ListTile-class.html#material.ListTile.4)',
    1324             :     );
    1325             :     assert(
    1326           3 :       tileHeight != trailingSize.height || tileHeight == 0.0,
    1327             :       'Trailing widget consumes entire tile height. Please use a sized widget, '
    1328             :       'or consider replacing MongolListTile with a custom widget '
    1329             :       '(see https://api.flutter.dev/flutter/material/ListTile-class.html#material.ListTile.4)',
    1330             :     );
    1331             : 
    1332             :     final double titleStart = hasLeading
    1333           4 :         ? math.max(_minLeadingHeight, leadingSize.height) +
    1334           1 :             _effectiveVerticalTitleGap
    1335             :         : 0.0;
    1336             :     final double adjustedLeadingHeight = hasLeading
    1337           4 :         ? math.max(leadingSize.height + _effectiveVerticalTitleGap, 32.0)
    1338             :         : 0.0;
    1339             :     final double adjustedTrailingHeight =
    1340           2 :         hasTrailing ? math.max(trailingSize.height, 32.0) : 0.0;
    1341           1 :     final BoxConstraints textConstraints = looseConstraints.tighten(
    1342           2 :       height: tileHeight - titleStart - adjustedTrailingHeight,
    1343             :     );
    1344           2 :     final Size titleSize = _layoutBox(title, textConstraints);
    1345           2 :     final Size subtitleSize = _layoutBox(subtitle, textConstraints);
    1346             : 
    1347             :     double? titleBaseline;
    1348             :     double? subtitleBaseline;
    1349             :     if (isTwoLine) {
    1350           1 :       titleBaseline = isDense ? 28.0 : 32.0;
    1351           1 :       subtitleBaseline = isDense ? 48.0 : 52.0;
    1352           1 :     } else if (isThreeLine) {
    1353           1 :       titleBaseline = isDense ? 22.0 : 28.0;
    1354           1 :       subtitleBaseline = isDense ? 42.0 : 48.0;
    1355             :     } else {
    1356           0 :       assert(isOneLine);
    1357             :     }
    1358             : 
    1359           1 :     final double defaultTileWidth = _defaultTileWidth;
    1360             : 
    1361             :     double tileWidth;
    1362             :     double titleX;
    1363             :     double? subtitleX;
    1364             :     if (!hasSubtitle) {
    1365           1 :       tileWidth = math.max(
    1366           4 :           defaultTileWidth, titleSize.width + 2.0 * _minHorizontalPadding);
    1367           3 :       titleX = (tileWidth - titleSize.width) / 2.0;
    1368             :     } else {
    1369           1 :       assert(subtitleBaselineType != null);
    1370           4 :       titleX = titleBaseline! - _boxBaseline(title!, titleBaselineType)!;
    1371           1 :       subtitleX = subtitleBaseline! -
    1372           4 :           _boxBaseline(subtitle!, subtitleBaselineType!)! +
    1373           3 :           visualDensity.horizontal * 2.0;
    1374             :       tileWidth = defaultTileWidth;
    1375             : 
    1376             :       // If the title and subtitle overlap, move the title left by half
    1377             :       // the overlap and the subtitle right by the same amount, and adjust
    1378             :       // tileWidth so that both titles fit.
    1379           3 :       final double titleOverlap = titleX + titleSize.width - subtitleX;
    1380           1 :       if (titleOverlap > 0.0) {
    1381           0 :         titleX -= titleOverlap / 2.0;
    1382           0 :         subtitleX += titleOverlap / 2.0;
    1383             :       }
    1384             : 
    1385             :       // If the title or subtitle overflow tileWidth then punt: title
    1386             :       // and subtitle are arranged in a column, tileWidth = row width plus
    1387             :       // _minHorizontalPadding on the left and right.
    1388           2 :       if (titleX < _minHorizontalPadding ||
    1389           5 :           (subtitleX + subtitleSize.width + _minHorizontalPadding) >
    1390             :               tileWidth) {
    1391             :         tileWidth =
    1392           6 :             titleSize.width + subtitleSize.width + 2.0 * _minHorizontalPadding;
    1393           1 :         titleX = _minHorizontalPadding;
    1394           3 :         subtitleX = titleSize.width + _minHorizontalPadding;
    1395             :       }
    1396             :     }
    1397             : 
    1398             :     // This attempts to implement the redlines for the horizontal position of the
    1399             :     // leading and trailing icons on the spec page:
    1400             :     //   https://material.io/design/components/lists.html#specs
    1401             :     // The interpretation for these redlines is as follows:
    1402             :     //  - For large tiles (> 72dp), both leading and trailing controls should be
    1403             :     //    a fixed distance from the left. As per guidelines this is set to 16dp.
    1404             :     //  - For smaller tiles, trailing should always be centered. Leading can be
    1405             :     //    centered or closer to the left. It should never be further than 16dp
    1406             :     //    to the left.
    1407             :     final double leadingX;
    1408             :     final double trailingX;
    1409           1 :     if (tileWidth > 72.0) {
    1410             :       leadingX = 16.0;
    1411             :       trailingX = 16.0;
    1412             :     } else {
    1413           4 :       leadingX = math.min((tileWidth - leadingSize.width) / 2.0, 16.0);
    1414           3 :       trailingX = (tileWidth - trailingSize.width) / 2.0;
    1415             :     }
    1416             : 
    1417             :     if (hasLeading) {
    1418           3 :       _positionBox(leading!, Offset(leadingX, 0.0));
    1419             :     }
    1420           3 :     _positionBox(title!, Offset(titleX, adjustedLeadingHeight));
    1421             :     if (hasSubtitle) {
    1422           3 :       _positionBox(subtitle!, Offset(subtitleX!, adjustedLeadingHeight));
    1423             :     }
    1424             :     if (hasTrailing) {
    1425           1 :       _positionBox(
    1426           4 :           trailing!, Offset(trailingX, tileHeight - trailingSize.height));
    1427             :     }
    1428             : 
    1429           3 :     size = constraints.constrain(Size(tileWidth, tileHeight));
    1430           4 :     assert(size.width == constraints.constrainWidth(tileWidth));
    1431           4 :     assert(size.height == constraints.constrainHeight(tileHeight));
    1432             :   }
    1433             : 
    1434           1 :   @override
    1435             :   void paint(PaintingContext context, Offset offset) {
    1436           1 :     void doPaint(RenderBox? child) {
    1437             :       if (child != null) {
    1438           1 :         final BoxParentData parentData = child.parentData! as BoxParentData;
    1439           3 :         context.paintChild(child, parentData.offset + offset);
    1440             :       }
    1441             :     }
    1442             : 
    1443           2 :     doPaint(leading);
    1444           2 :     doPaint(title);
    1445           2 :     doPaint(subtitle);
    1446           2 :     doPaint(trailing);
    1447             :   }
    1448             : 
    1449           1 :   @override
    1450             :   bool hitTestSelf(Offset position) => true;
    1451             : 
    1452           1 :   @override
    1453             :   bool hitTestChildren(BoxHitTestResult result, {required Offset position}) {
    1454           2 :     for (final RenderBox child in _children) {
    1455           1 :       final BoxParentData parentData = child.parentData! as BoxParentData;
    1456           1 :       final bool isHit = result.addWithPaintOffset(
    1457           1 :         offset: parentData.offset,
    1458             :         position: position,
    1459           1 :         hitTest: (BoxHitTestResult result, Offset transformed) {
    1460           3 :           assert(transformed == position - parentData.offset);
    1461           1 :           return child.hitTest(result, position: transformed);
    1462             :         },
    1463             :       );
    1464             :       if (isHit) return true;
    1465             :     }
    1466             :     return false;
    1467             :   }
    1468             : }

Generated by: LCOV version 1.15