blob: 5983c3dc42ab645a3c5e1704b8acbde860baa188 [file] [log] [blame]
// 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 'dart:html';
import 'package:intl/intl.dart';
import 'package:flutter_web/material.dart';
import '../models/providers.dart';
import '../models/roll_history.dart';
import '../models/roll_sheriff.dart';
import '../models/skia_autoroll.dart';
enum RollUnits { hour, day }
class RollDetails extends StatelessWidget {
const RollDetails();
@override
Widget build(BuildContext context) {
final ThemeData theme = Theme.of(context);
final TextStyle headerStyle = theme.textTheme.headline
.copyWith(color: Theme.of(context).primaryColor)
.apply(fontSizeFactor: 1.3);
return Theme(
data: Theme.of(context).copyWith(
textTheme: Theme.of(context).textTheme.apply(fontSizeFactor: 1.3),
),
child:
Row(mainAxisAlignment: MainAxisAlignment.start, children: <Widget>[
ModelBinding<RollHistory>(
initialModel: RollHistory(),
child: RefreshRollHistory(
child: Expanded(
child: Column(children: <Widget>[
ListTile(
title: Text('Roll Commits', style: headerStyle),
),
ListTile(
title: const Text('Skia → Engine'),
subtitle: _DetailItem(
value: (RollHistory history) =>
history.lastSkiaAutoRoll,
unit: RollUnits.hour),
onTap: () => window.open(
'https://autoroll.skia.org/r/skia-flutter-autoroll',
'_blank')),
ListTile(
title: const Text('Engine → Framework'),
subtitle: _DetailItem(
value: (RollHistory history) =>
history.lastEngineRoll,
unit: RollUnits.hour),
onTap: () => window.open(
'https://autoroll.skia.org/r/flutter-engine-flutter-autoroll',
'_blank')),
ListTile(
title: const Text('master → dev channel'),
subtitle: _DetailItem(
value: (RollHistory history) =>
history.lastDevBranchRoll),
onTap: () => window.open(
'https://github.com/flutter/flutter/commits/dev',
'_blank')),
ListTile(
title: const Text('dev → beta channel'),
subtitle: _DetailItem(
value: (RollHistory history) =>
history.lastBetaBranchRoll),
onTap: () => window.open(
'https://github.com/flutter/flutter/commits/beta',
'_blank')),
ListTile(
title: const Text('beta → stable channel'),
subtitle: _DetailItem(
value: (RollHistory history) =>
history.lastStableBranchRoll),
onTap: () => window.open(
'https://github.com/flutter/flutter/commits/stable',
'_blank')),
ListTile(
title: const Text('flutter_web'),
subtitle: _DetailItem(
value: (RollHistory history) =>
history.lastFlutterWebCommit),
onTap: () => window.open(
'https://github.com/flutter/flutter_web/commits/master',
'_blank')),
]),
),
),
),
Expanded(
child: Column(children: <Widget>[
ListTile(
title: Text('Auto Rollers', style: headerStyle),
),
const ModelBinding<RollSheriff>(
initialModel: RollSheriff(),
child: RefreshSheriffRotation(child: RollSheriffWidget())),
const ModelBinding<SkiaAutoRoll>(
initialModel: SkiaAutoRoll(),
child: RefreshEngineFrameworkRoll(
child: AutoRollWidget(
name: 'Engine → Framework',
url:
'https://autoroll.skia.org/r/flutter-engine-flutter-autoroll',
))),
const ModelBinding<SkiaAutoRoll>(
initialModel: SkiaAutoRoll(),
child: RefreshSkiaFlutterRoll(
child: AutoRollWidget(
name: 'Skia → Engine',
url: 'https://autoroll.skia.org/r/skia-flutter-autoroll',
)))
]),
)
]));
}
}
class RollSheriffWidget extends StatelessWidget {
const RollSheriffWidget();
@override
Widget build(BuildContext context) {
final RollSheriff sheriff = ModelBinding.of<RollSheriff>(context);
if (sheriff?.currentSheriff != null) {
return ListTile(
leading: const CircleAvatar(
child: Icon(Icons.security),
),
title: Text('${sheriff.currentSheriff} 🤠'),
onTap: () => window.open(
'http://chromium-build.appspot.com/static/rotations.html',
'_blank'));
}
return const SizedBox();
}
}
class AutoRollWidget extends StatelessWidget {
const AutoRollWidget({@required this.name, @required this.url});
final String name;
final String url;
@override
Widget build(BuildContext context) {
final SkiaAutoRoll autoRoll = ModelBinding.of<SkiaAutoRoll>(context);
IconData icon;
Color backgroundColor;
if (autoRoll.mode == 'running') {
if (autoRoll.lastRollResult == 'succeeded') {
icon = Icons.check;
backgroundColor = Colors.green;
} else if (autoRoll.lastRollResult == 'failed') {
icon = Icons.error;
backgroundColor = Colors.redAccent;
}
} else if (autoRoll.mode == 'stopped') {
icon = Icons.pause_circle_filled;
backgroundColor = Colors.amberAccent;
}
if (icon == null || backgroundColor == null) {
icon = Icons.report_problem;
backgroundColor = Colors.grey;
}
return ListTile(
title: Text(name),
leading: CircleAvatar(
child: Icon(icon),
backgroundColor: backgroundColor,
),
subtitle: Text(
'${autoRoll.mode ?? 'Unknown'}\nLast roll: ${autoRoll.lastRollResult}'),
isThreeLine: true,
onTap: () => window.open(url, '_blank'));
}
}
class _DetailItem extends StatelessWidget {
const _DetailItem({@required this.value, this.unit = RollUnits.day});
final DateTime Function(RollHistory history) value;
final RollUnits unit;
@override
Widget build(BuildContext context) {
DateFormat dateFormat;
String parenthesis;
DateTime valueDate;
final RollHistory history = ModelBinding.of<RollHistory>(context);
if (value != null) {
valueDate = value(history);
if (valueDate != null) {
if (unit == RollUnits.hour) {
final int hours = DateTime.now().difference(valueDate).inHours;
// Ignoring Russian, etc pluralization problems.
parenthesis = Intl.plural(hours,
zero: '<1 hour ago',
one: '1 hour ago',
other: '$hours hours ago');
dateFormat = DateFormat.jm();
} else {
// RollUnits.day
final int days = DateTime.now().difference(valueDate).inDays;
parenthesis = Intl.plural(days,
zero: 'today', one: '1 day ago', other: '$days days ago');
dateFormat = DateFormat.MMMMd();
}
}
}
return Text(
(valueDate != null)
? '${dateFormat.format(valueDate.toLocal())} ($parenthesis)'
: 'Unknown',
style: Theme.of(context).textTheme.body1);
}
}