blob: e7579e8530103fdfeb05f18d1ab127444021f760 [file] [log] [blame] [edit]
// 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:flutter/services.dart';
import 'package:provider/provider.dart';
import 'package:url_launcher/url_launcher.dart';
import '../dashboard_navigation_drawer.dart';
import '../state/build.dart';
import 'app_bar.dart';
import 'repository_selector.dart';
/// Composable widget built on top of [Scaffold] that provides Cocoon defaults.
///
/// This was originally extracted from `BuildDashboardPage`.
///
/// Requires [BuildState] to be provided at a higher-level widget to be used.
final class CocoonScaffold extends StatelessWidget {
const CocoonScaffold({
required this.body,
required this.onUpdateNavigation,
required this.title,
this.actions,
});
/// The widget that is isnerted into the resulting [CocoonAppBar.title].
final Widget title;
/// The widget that is inserted into the resulting [Scaffold.body].
final Widget body;
/// When navigation should be updated.
final void Function({
required String repo, //
required String branch,
})
onUpdateNavigation;
/// Addtional actions that are inserted into [CocoonAppBar.actions].
final List<Widget>? actions;
static final _flutterIssueUrl = Uri.https(
'github.com',
'/flutter/flutter/issues/new',
{'labels': 'team-infra'},
);
@override
Widget build(BuildContext context) {
final buildState = Provider.of<BuildState>(context);
final mediaQuery = MediaQuery.of(context);
final devicePixelRatio = mediaQuery.devicePixelRatio;
final smallScreen = mediaQuery.size.width * devicePixelRatio < 600;
return CallbackShortcuts(
bindings: {
const SingleActivator(LogicalKeyboardKey.arrowUp): () {
buildState.updateCurrentRepoBranch('flutter', 'master');
},
const SingleActivator(LogicalKeyboardKey.arrowLeft): () {
buildState.updateCurrentRepoBranch('cocoon', 'main');
},
const SingleActivator(LogicalKeyboardKey.arrowRight): () {
buildState.updateCurrentRepoBranch('packages', 'main');
},
},
child: Focus(
autofocus: true,
child: AnimatedBuilder(
animation: buildState,
builder: (context, _) {
return Scaffold(
appBar: CocoonAppBar(
title: title,
actions: [
if (!smallScreen)
RepositorySelector(
repositories: buildState.repos,
branches: buildState.branches,
selectedRepository: buildState.currentRepo,
selectedBranch: buildState.currentBranch,
onRepositoryChange: (newRepo) {
onUpdateNavigation(
repo: newRepo,
branch: buildState.currentBranch,
);
},
onBranchChange: (newBranch) {
onUpdateNavigation(
repo: buildState.currentRepo,
branch: newBranch,
);
},
smallScreen: smallScreen,
),
IconButton(
tooltip: 'Report Issue',
icon: const Icon(Icons.bug_report),
onPressed: () async {
await launchUrl(_flutterIssueUrl);
},
),
...?actions,
],
),
body: body,
drawer: const DashboardNavigationDrawer(),
);
},
),
),
);
}
}