| // Copyright 2019 The Flutter Authors. 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:url_launcher/url_launcher.dart'; | |
| import '../logic/qualified_task.dart'; | |
| import 'task_box.dart'; | |
| /// Header icon for all [Task]s that map to the same [Task.stageName] | |
| /// and [Task.name]. | |
| /// | |
| /// Intended to be used in the first row of [TaskGrid]. Shows an | |
| /// icon based on [qualifiedTask.stage], defaulting to [Icons.help] if | |
| /// it can't be mapped. On tap, shows the task. | |
| class TaskIcon extends StatelessWidget { | |
| const TaskIcon({super.key, required this.qualifiedTask, this.onTap}); | |
| /// [Task] to get information from. | |
| final QualifiedTask qualifiedTask; | |
| /// Callback when the icon is tapped. | |
| final void Function(BuildContext)? onTap; | |
| /// A lookup table for matching [stageName] to [Image]. | |
| /// | |
| /// [stageName] is based on the backend. | |
| Widget stageIconForBrightness(Brightness brightness) { | |
| // Pass this as the `color` for Image's that are black and white icons. | |
| // This only works in the CanvasKit implementation currently, not in DOM. If | |
| // this needs to run in the DOM implementation, it will need to include | |
| // different assets. | |
| final blendFilter = brightness == Brightness.dark ? Colors.white : null; | |
| if (!(qualifiedTask.isLuci || qualifiedTask.isDartInternal)) { | |
| return Icon(Icons.help, color: blendFilter); | |
| } | |
| final matchedName = qualifiedTask.task.toLowerCase(); | |
| final isWebTest = | |
| matchedName.contains('_web') || matchedName.contains('web_'); | |
| final isToolTest = | |
| matchedName.contains('_tool') || matchedName.contains('tool_'); | |
| final isAndroidTest = | |
| matchedName.contains('_android') || | |
| matchedName.contains('_mokey') || | |
| matchedName.contains('_pixel_7pro'); | |
| if (matchedName.contains('_fuchsia')) { | |
| return Padding( | |
| padding: const EdgeInsets.all(2.0), | |
| child: Image.asset('assets/fuchsia.png', color: blendFilter), | |
| ); | |
| } else if (isWebTest && !isToolTest) { | |
| return Padding( | |
| padding: const EdgeInsets.all(2.0), | |
| child: Image.asset('assets/chromium.png', color: blendFilter), | |
| ); | |
| } else if (isAndroidTest) { | |
| return Icon(Icons.android, color: blendFilter); | |
| } else if (matchedName.startsWith('linux')) { | |
| return Padding( | |
| padding: const EdgeInsets.all(2.0), | |
| child: Image.asset('assets/linux.png', color: blendFilter), | |
| ); | |
| } else if (matchedName.startsWith('mac')) { | |
| if (matchedName.contains('_ios')) { | |
| return Icon(Icons.phone_iphone, color: blendFilter); | |
| } else { | |
| return Padding( | |
| padding: const EdgeInsets.all(2.0), | |
| child: Image.asset('assets/apple.png', color: blendFilter), | |
| ); | |
| } | |
| } else if (matchedName.startsWith('win')) { | |
| return Image.asset('assets/windows.png', color: blendFilter); | |
| } | |
| return Icon(Icons.help, color: blendFilter); | |
| } | |
| @override | |
| Widget build(BuildContext context) { | |
| final brightness = Theme.of(context).brightness; | |
| final icon = stageIconForBrightness(brightness); | |
| return IconTheme.merge( | |
| data: IconThemeData(size: TaskBox.of(context) - 5), | |
| child: InkWell( | |
| onTap: () async { | |
| if (onTap != null) { | |
| onTap!(context); | |
| } else { | |
| await launchUrl(qualifiedTask.sourceConfigurationUrl); | |
| } | |
| }, | |
| child: Tooltip( | |
| message: qualifiedTask.task, | |
| child: Align(alignment: Alignment.bottomCenter, child: icon), | |
| ), | |
| ), | |
| ); | |
| } | |
| } |