blob: 785a270674d7399a0d590d79fb38e1d620a50c69 [file] [log] [blame]
// Copyright 2017 The Fuchsia 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:async';
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:lib.widgets.dart/model.dart';
import 'enums.dart';
import 'service/build_info.dart';
import 'service/build_service.dart';
final DateTime _kHalloween = new DateTime.utc(
2018,
10,
31,
12,
);
Size _computeBuildStatusSize(int modelRowsCount) =>
ui.window.physicalSize /
ui.window.devicePixelRatio /
(modelRowsCount.toDouble() + 1);
/// Manages a build status and associated metadata.
class BuildStatusModel extends Model {
/// The build type.
final String type;
/// The build name.
final String name;
/// The url of the page used to determine the build status.
final String url;
/// The service used to fetch [BuildInfo].
final BuildService _buildService;
StreamSubscription<BuildInfo> _pendingRequest;
DateTime _lastRefreshed;
DateTime _lastRefreshStarted;
DateTime _lastRefreshEnded;
DateTime _lastFailTime;
DateTime _lastPassTime;
BuildResultEnum _buildResult;
String _errorMessage;
Size buildStatusSize;
/// Constructor.
BuildStatusModel(
{this.type,
this.name,
this.url,
BuildService buildService,
int modelRowsCount})
: _buildService = buildService,
buildStatusSize = _computeBuildStatusSize(modelRowsCount);
/// Returns the time when the status was refreshed.
DateTime get lastRefreshed => _lastRefreshed;
/// Returns the time when the status is starting to refresh.
DateTime get lastRefreshStarted => _lastRefreshStarted;
/// Returns the time when the status is finished refreshing.
DateTime get lastRefreshEnded => _lastRefreshEnded;
/// Returns the current build status.
BuildResultEnum get buildResult => _buildResult;
/// The time the build started failing.
DateTime get lastFailTime => _lastFailTime;
/// The time the build started passing.
DateTime get lastPassTime => _lastPassTime;
/// If the build status isn't [BuildResultEnum.success.value] this will
/// indicate any additional information about why not.
String get errorMessage => _errorMessage;
/// The color to use as the background of a successful build.
/// The default success color was chosen from
/// http://www.visualisingdata.com/2015/11/colour-swatch-alternatives-to-green-and-red/
/// to allow it to be more easily seen by those with color blindness.
Color get successColor {
Duration difference = new DateTime.now().difference(_kHalloween).abs();
if (difference < const Duration(days: 1)) {
return Colors.orange[700];
}
return new Color(0xFF4DAC26);
}
/// The color to use as the background of a failed build.
/// The default success color was chosen from
/// http://www.visualisingdata.com/2015/11/colour-swatch-alternatives-to-green-and-red/
/// to allow it to be more easily seen by those with color blindness.
Color get failColor {
Duration difference = new DateTime.now().difference(_kHalloween).abs();
if (difference < const Duration(days: 1)) {
return Colors.black;
}
return new Color(0xFFD01C8B);
}
/// Starts the model refreshing periodically.
void start() {
new Timer.periodic(
const Duration(seconds: 60),
(_) => refresh(),
);
refresh();
}
/// Initiates a refresh of the build status.
void refresh() {
_fetchConfigStatus();
}
void onWindowMetricsChanged(int modelRowsCount) {
Size previousSize = buildStatusSize;
buildStatusSize = _computeBuildStatusSize(modelRowsCount);
if (buildStatusSize.height != previousSize.height) {
notifyListeners();
}
}
Future<Null> _fetchConfigStatus() async {
await _pendingRequest?.cancel();
_lastRefreshStarted = new DateTime.now();
_lastRefreshEnded = null;
runZoned(() {
_pendingRequest =
_buildService.getBuildByName(url).listen((BuildInfo response) {
_pendingRequest?.cancel();
_pendingRequest = null;
_errorMessage = null;
_buildResult = response.result;
_handleFetchComplete();
});
}, onError: (Object error) {
_pendingRequest?.cancel();
_pendingRequest = null;
_buildResult = null;
_errorMessage = 'Error: $error';
_handleFetchComplete();
if (error is TimeoutException) {
_errorMessage = '$_errorMessage Retrying...';
refresh();
}
});
}
void _handleFetchComplete() {
_lastRefreshEnded = new DateTime.now();
if (_buildResult == BuildResultEnum.success) {
if (_lastPassTime == null) {
_lastPassTime = new DateTime.now();
_lastFailTime = null;
}
} else {
if (_lastFailTime == null) {
_lastFailTime = new DateTime.now();
_lastPassTime = null;
}
}
notifyListeners();
}
}