| // 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/foundation.dart'; |
| import 'package:flutter/material.dart'; |
| import 'package:gallery/data/gallery_options.dart'; |
| |
| import 'package:gallery/studies/crane/model/formatters.dart'; |
| |
| import '../../../l10n/gallery_localizations.dart'; |
| |
| abstract class Destination { |
| const Destination({ |
| @required this.id, |
| @required this.destination, |
| @required this.assetSemanticLabel, |
| }) : assert(id != null), |
| assert(destination != null); |
| |
| final int id; |
| final String destination; |
| final String assetSemanticLabel; |
| |
| String get assetName; |
| |
| String subtitle(BuildContext context); |
| String subtitleSemantics(BuildContext context) => subtitle(context); |
| |
| @override |
| String toString() => '$destination (id=$id)'; |
| } |
| |
| class FlyDestination extends Destination { |
| const FlyDestination({ |
| @required int id, |
| @required String destination, |
| @required String assetSemanticLabel, |
| @required this.stops, |
| this.duration, |
| }) : assert(stops != null), |
| assert(destination != null), |
| super( |
| id: id, |
| destination: destination, |
| assetSemanticLabel: assetSemanticLabel, |
| ); |
| |
| final int stops; |
| final Duration duration; |
| |
| String get assetName => 'assets/crane/destinations/fly_$id.jpg'; |
| |
| String subtitle(BuildContext context) { |
| final stopsText = GalleryLocalizations.of(context).craneFlyStops(stops); |
| |
| if (duration == null) { |
| return stopsText; |
| } else { |
| final textDirection = GalleryOptions.of(context).textDirection(); |
| final durationText = |
| formattedDuration(context, duration, abbreviated: true); |
| return textDirection == TextDirection.ltr |
| ? '$stopsText · $durationText' |
| : '$durationText · $stopsText'; |
| } |
| } |
| |
| @override |
| String subtitleSemantics(BuildContext context) { |
| final stopsText = GalleryLocalizations.of(context).craneFlyStops(stops); |
| |
| if (duration == null) { |
| return stopsText; |
| } else { |
| final durationText = |
| formattedDuration(context, duration, abbreviated: false); |
| return '$stopsText, $durationText'; |
| } |
| } |
| } |
| |
| class SleepDestination extends Destination { |
| const SleepDestination({ |
| @required int id, |
| @required String destination, |
| @required String assetSemanticLabel, |
| @required this.total, |
| }) : assert(total != null), |
| assert(destination != null), |
| super( |
| id: id, |
| destination: destination, |
| assetSemanticLabel: assetSemanticLabel, |
| ); |
| |
| final int total; |
| |
| String get assetName => 'assets/crane/destinations/sleep_$id.jpg'; |
| |
| String subtitle(BuildContext context) { |
| return GalleryLocalizations.of(context).craneSleepProperties(total); |
| } |
| } |
| |
| class EatDestination extends Destination { |
| const EatDestination({ |
| @required int id, |
| @required String destination, |
| @required String assetSemanticLabel, |
| @required this.total, |
| }) : assert(total != null), |
| assert(destination != null), |
| super( |
| id: id, |
| destination: destination, |
| assetSemanticLabel: assetSemanticLabel, |
| ); |
| |
| final int total; |
| |
| String get assetName => 'assets/crane/destinations/eat_$id.jpg'; |
| |
| String subtitle(BuildContext context) { |
| return GalleryLocalizations.of(context).craneEatRestaurants(total); |
| } |
| } |