in release_dashboard/lib/widgets/progression.dart [142:226]
Widget build(BuildContext context) {
Map<ConductorStatusEntry, Object>? releaseStatus = context.watch<StatusState>().releaseStatus;
// If there is no test state, start from the first step: creating a release.
final int currentStep =
releaseStatus == null ? 0 : MainProgression.stepPosition[releaseStatus[ConductorStatusEntry.currentPhase]]!;
// The values of the map are widgets that each [Step] renders as its content.
const Map<Object, Widget> stepWidgetMapping = <Object, Widget>{
ReleaseSteps.initializeRelease: CreateReleaseSubsteps(),
pb.ReleasePhase.APPLY_ENGINE_CHERRYPICKS: CherrypicksSubsteps(repository: Repositories.engine),
pb.ReleasePhase.CODESIGN_ENGINE_BINARIES: MergePrSubsteps(repository: Repositories.engine),
pb.ReleasePhase.APPLY_FRAMEWORK_CHERRYPICKS: CherrypicksSubsteps(repository: Repositories.framework),
pb.ReleasePhase.PUBLISH_VERSION: MergePrSubsteps(repository: Repositories.framework),
pb.ReleasePhase.PUBLISH_CHANNEL: PublishReleaseSubsteps(),
pb.ReleasePhase.VERIFY_RELEASE: VerifyReleaseSubsteps(),
pb.ReleasePhase.RELEASE_COMPLETED: ReleaseCompleted(),
};
if (_dialogueContent != null) {
// Whenever [StartContext] or [NextContext]'s prompt returns a message, it would update
// [_dialogueContent] which triggers the [dialogPrompt] below with the
// message displayed as the content. The prompt will also initialize a completer.
// If [dialogPrompt]'s 'Yes' is pressed, complete the completer
// with 'true' (equivalent of replying 'y' to the prompt in the command line when using
// the CLI version). Otherwise, complete with 'false' (equivalent of replying 'n' to
// the prompt in the command line when using the CLI version).
Future.delayed(Duration.zero, () {
dialogPrompt(
context: context,
title: const Text(
'Please read the instructions below carefully. Some processes are disruptive and irreversible.'),
content: SelectableText(_dialogueContent!),
leftButtonTitle: 'No',
rightButtonTitle: 'Yes',
leftButtonCallback: () async {
if (_dialogueCallback != null) {
_dialogueCallback!.complete(false);
}
// Have to set the message to null, otherwise the [dialogPrompt] gets displayed again.
dialogPromptChanger(null, null);
},
rightButtonCallback: () async {
if (_dialogueCallback != null) {
_dialogueCallback!.complete(true);
}
// Have to set the message to null, otherwise the [dialogPrompt] gets displayed again.
dialogPromptChanger(null, null);
},
);
});
}
return Expanded(
child: Scrollbar(
isAlwaysShown: true,
controller: _scrollController,
child: ListView(
controller: _scrollController,
padding: const EdgeInsets.symmetric(vertical: 12.0),
physics: const ClampingScrollPhysics(),
children: <Widget>[
const ConductorStatus(),
const SizedBox(height: 20.0),
Stepper(
controlsBuilder: (BuildContext context, ControlsDetails details) => Row(),
physics: const ScrollPhysics(),
currentStep: currentStep,
steps: <Step>[
for (MapEntry step in MainProgression.stepPosition.entries)
Step(
title: Text(MainProgression.stepTitles[step.key]!),
// Only renders the current step's content.
content: currentStep == step.value ? stepWidgetMapping[step.key]! : Container(),
// All previously completed steps and the current steps are active.
isActive: currentStep >= step.value,
state: handleStepState(currentStep, step.value),
),
],
),
],
),
),
);
}