blob: b0abfea204914c563c9a73e74b6423655dbb3a51 [file] [log] [blame]
// 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/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<ItemCards> {
List<Destination> flyDestinations;
List<Destination> sleepDestinations;
List<Destination> eatDestinations;
List<Widget> _buildDestinationCards({int listIndex}) {
final List<Destination> destinations = [
if (listIndex == 0) ...flyDestinations,
if (listIndex == 1) ...sleepDestinations,
if (listIndex == 2) ...eatDestinations,
];
return destinations
.map(
(d) => 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<Widget> destinationCards =
_buildDestinationCards(listIndex: widget.index);
if (isDesktop) {
var columns = List<List<Widget>>(ItemCards.totalColumns);
for (var i = 0; i < destinationCards.length; i++) {
final col = i % ItemCards.totalColumns;
if (columns[col] == null) {
columns[col] = List<Widget>();
}
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(),
],
);
}
}
}