// Copyright 2019 The Flutter team. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:gallery/layout/adaptive.dart'; import 'package:gallery/layout/highlight_focus.dart'; import 'package:gallery/studies/crane/model/data.dart'; import 'package:gallery/studies/crane/model/destination.dart'; class ItemCards extends StatefulWidget { final int index; const ItemCards({Key key, this.index}) : super(key: key); static const totalColumns = 4; @override _ItemCardsState createState() => _ItemCardsState(); } class _ItemCardsState extends State { List flyDestinations; List sleepDestinations; List eatDestinations; List _buildDestinationCards({int listIndex}) { final List destinations = [ if (listIndex == 0) ...flyDestinations, if (listIndex == 1) ...sleepDestinations, if (listIndex == 2) ...eatDestinations, ]; return destinations .map( (d) => HighlightFocus( debugLabel: 'DestinationCard: ${d.destination}', highlightColor: Colors.red.withOpacity(0.5), onPressed: () {}, child: RepaintBoundary( child: _DestinationCard(destination: d), ), ), ) .toList(); } @override void didChangeDependencies() { super.didChangeDependencies(); // We use didChangeDependencies because the initialization involves an // InheritedWidget (for localization). However, we don't need to get // destinations again when, say, resizing the window. if (flyDestinations == null) { flyDestinations = getFlyDestinations(context); sleepDestinations = getSleepDestinations(context); eatDestinations = getEatDestinations(context); } } @override Widget build(BuildContext context) { final isDesktop = isDisplayDesktop(context); final List destinationCards = _buildDestinationCards(listIndex: widget.index); if (isDesktop) { var columns = List>(ItemCards.totalColumns); for (var i = 0; i < destinationCards.length; i++) { final col = i % ItemCards.totalColumns; if (columns[col] == null) { columns[col] = List(); } columns[col].add( // TODO: determine why this is isn't always respected Semantics( sortKey: OrdinalSortKey(i.toDouble(), name: 'destination'), child: destinationCards[i], ), ); } return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ for (var column in columns) Expanded( child: Padding( padding: const EdgeInsetsDirectional.only(end: 16), child: Column( children: column, ), ), ) ], ); } else { return Column(children: destinationCards); } } } class _DestinationCard extends StatelessWidget { _DestinationCard({this.destination}) : assert(destination != null); final Destination destination; @override Widget build(BuildContext context) { final imageWidget = Semantics( child: ExcludeSemantics( child: Image.asset( destination.assetName, fit: BoxFit.cover, ), ), label: destination.assetSemanticLabel, ); final isDesktop = isDisplayDesktop(context); final textTheme = Theme.of(context).textTheme; if (isDesktop) { return Padding( padding: const EdgeInsets.only(bottom: 40), child: Semantics( container: true, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ ClipRRect( borderRadius: const BorderRadius.all(Radius.circular(4)), child: imageWidget, ), Padding( padding: const EdgeInsets.only(top: 20, bottom: 10), child: Text( destination.destination, style: textTheme.subhead, ), ), Text( destination.subtitle(context), semanticsLabel: destination.subtitleSemantics(context), style: textTheme.subtitle, ), ], ), ), ); } else { return Column( mainAxisSize: MainAxisSize.min, children: [ ListTile( contentPadding: EdgeInsetsDirectional.only(end: 8), leading: ClipRRect( borderRadius: const BorderRadius.all(Radius.circular(4)), child: SizedBox( height: 60, width: 60, child: imageWidget, ), ), title: Text(destination.destination, style: textTheme.subhead), subtitle: Text( destination.subtitle(context), semanticsLabel: destination.subtitleSemantics(context), style: textTheme.subtitle, ), ), Divider(), ], ); } } }