blob: 8299599b755e3ad69d2071e79def8fa5f139e1bf [file] [log] [blame]
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
// for details. 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:angular/angular.dart';
import 'package:angular_components/angular_components.dart';
import 'package:angular_components/content/deferred_content.dart';
import 'package:angular_forms/angular_forms.dart' show formDirectives;
import 'package:angular_components/laminate/enums/alignment.dart';
import 'package:angular_components/material_checkbox/material_checkbox.dart';
import 'package:angular_components/material_chips/material_chips.dart';
import 'package:angular_components/material_chips/material_chip.dart';
import 'package:angular_components/material_radio/material_radio.dart';
import 'package:angular_components/material_tooltip/material_tooltip.dart';
import 'package:angular_components/material_tooltip/module.dart' as tooltip;
import 'log_component.dart';
import 'commit.dart';
@Component(
selector: 'results-selector-panel',
directives: [
coreDirectives,
formDirectives,
DeferredContentDirective,
LogComponent,
MaterialButtonComponent,
MaterialCheckboxComponent,
MaterialChipComponent,
MaterialChipsComponent,
MaterialPaperTooltipComponent,
MaterialRadioComponent,
MaterialRadioGroupComponent,
MaterialTooltipDirective,
MaterialTooltipTargetDirective,
RelativePosition
],
providers: [popupBindings, tooltip.materialTooltipBindings],
templateUrl: 'results_selector_panel.html',
styleUrls: ([
'commit_component.css',
'package:angular_components/css/mdc_web/card/mdc-card.scss.css'
]))
class ResultsSelectorPanel {
ResultsSelectorPanel();
@Input()
set changes(Changes changes) {
_changes = changes;
selectableChanges = [
for (ConfigGroup c in changes) SelectableConfigurationGroup(c, this)
];
initializeSelected();
}
@Input()
ChangeGroup commit;
@Input()
set selected(Set<Change> selected) {
_selected = selected;
initializeSelected();
}
Changes _changes;
Set<Change> _selected;
List<SelectableConfigurationGroup> selectableChanges;
int resultLimit = 10;
Changes get changes => _changes;
final preferredTooltipPositions = [
RelativePosition.OffsetBottomLeft,
RelativePosition.OffsetTopLeft
];
void initializeSelected() {
if (_selected != null && _changes != null) {
_selected.addAll([
for (final c in selectableChanges)
for (SelectableResultGroup r in c.resultGroups)
for (SelectableChange h in r.changes) h.change
]);
}
}
}
class SelectableChange {
final Change change;
bool selected = true;
final SelectableResultGroup resultGroup;
final SelectableConfigurationGroup configurationGroup;
final ResultsSelectorPanel panel;
SelectableChange(
this.change, this.resultGroup, this.configurationGroup, this.panel);
void onChange(bool event) {
if (selected == event) return;
selected = event;
if (event) {
panel._selected.add(this.change);
} else {
panel._selected.remove(this.change);
}
resultGroup.checkbox.setMixed();
configurationGroup.checkbox.setMixed();
}
}
class SelectableResultGroup {
List<SelectableChange> changes;
SelectableConfigurationGroup configurationGroup;
FixedMixedCheckbox checkbox = FixedMixedCheckbox();
SelectableResultGroup(
ResultGroup group, this.configurationGroup, ResultsSelectorPanel panel) {
changes = [
for (final change in group)
SelectableChange(change, this, configurationGroup, panel)
];
}
void onChange(String event) {
if (checkbox.eventMatchesState(event)) return;
assert(event != 'mixed');
bool newChecked = event == 'true';
checkbox.setState(newChecked, false);
for (final change in changes) {
change.selected = newChecked;
}
configurationGroup.checkbox.setMixed();
}
}
class SelectableConfigurationGroup {
List<SelectableResultGroup> resultGroups;
FixedMixedCheckbox checkbox = FixedMixedCheckbox();
SelectableConfigurationGroup(
ConfigGroup configGroup, ResultsSelectorPanel panel) {
resultGroups = [
for (final resultGroup in configGroup)
SelectableResultGroup(resultGroup, this, panel)
];
}
get summaries =>
resultGroups.first.changes.first.change.configurations.summaries;
void onChange(String event) {
if (checkbox.eventMatchesState(event)) return;
assert(event != 'mixed');
bool newChecked = event == 'true';
checkbox.setState(newChecked, false);
for (final group in resultGroups) {
group.checkbox.setState(newChecked, false);
for (final change in group.changes) {
change.selected = newChecked;
}
}
}
}
class FixedMixedCheckbox {
bool checked = true;
bool indeterminate = false;
// Model change indeterminate <-> checked generates a bad 'unchecked' event.
// Workaround for issue https://github.com/dart-lang/angular_components/issues/434
bool expectBadEvent = false;
bool eventMatchesState(String event) {
if (event == 'mixed' && indeterminate ||
event == 'true' && checked ||
event == 'false' && !indeterminate && !checked ||
event == 'false' && expectBadEvent) {
expectBadEvent = false;
return true;
}
return false;
}
void setState(bool newChecked, bool newIndeterminate) {
assert(!newChecked || !newIndeterminate);
if (newChecked && indeterminate || checked && newIndeterminate) {
expectBadEvent = true;
}
checked = newChecked;
indeterminate = newIndeterminate;
}
void setMixed() => setState(false, true);
}