blob: af2ef9e68d557fbe9afbc35f05d4b9f5fea009ba [file] [log] [blame]
// Copyright 2019 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 'package:flutter/material.dart';
import '../blocs/webpage_bloc.dart';
import 'history_buttons.dart';
import 'navigation_field.dart';
// TODO(fxb/45264): Make the common factors as part of Ermine central styles.
const _kNavbarHeight = 24.0;
const _kIconSize = 14.0;
enum _LayoutId { historyButtons, url, addTabButton }
class BrowserNavigationBar extends StatelessWidget {
final WebPageBloc? bloc;
final VoidCallback newTab;
final FocusNode _fieldFocus;
const BrowserNavigationBar({
required this.bloc,
required this.newTab,
required FocusNode fieldFocus,
}) : _fieldFocus = fieldFocus;
@override
Widget build(BuildContext context) => Material(
child: SizedBox(
height: _kNavbarHeight,
child: Stack(
children: <Widget>[
Positioned.fill(child: _buildWidgets(context)),
if (bloc != null)
Align(
alignment: Alignment.bottomCenter,
child: _buildLoadingIndicator(),
),
],
),
),
);
Widget _buildLoadingIndicator() {
return AnimatedBuilder(
animation: bloc!.isLoadedStateNotifier,
builder: (context, snapshot) => bloc!.isLoadedState
? Offstage()
: SizedBox(
width: double.infinity,
height: 4.0,
child: LinearProgressIndicator(
color: Theme.of(context).colorScheme.secondary,
backgroundColor: Colors.transparent,
),
),
);
}
Widget _buildWidgets(BuildContext context) {
return CustomMultiChildLayout(
delegate: _LayoutDelegate(),
children: [
LayoutId(
id: _LayoutId.historyButtons,
child: bloc != null ? HistoryButtons(bloc: bloc!) : Container(),
),
LayoutId(
id: _LayoutId.url,
child: bloc != null
? NavigationField(bloc: bloc!, focus: _fieldFocus)
: Container(),
),
LayoutId(
id: _LayoutId.addTabButton,
child: _buildNewTabButton(context),
),
],
);
}
Widget _buildNewTabButton(BuildContext context) {
return GestureDetector(
onTap: newTab,
child: Align(
alignment: Alignment.centerRight,
child: AspectRatio(
aspectRatio: 1.0,
child: Padding(
padding: const EdgeInsets.all(1.0),
child: Container(
color: Theme.of(context).colorScheme.secondary,
alignment: Alignment.center,
child: Icon(
Icons.add,
key: Key('new_tab'),
color: Theme.of(context).colorScheme.primary,
size: _kIconSize,
),
),
),
),
),
);
}
}
class _LayoutDelegate extends MultiChildLayoutDelegate {
@override
void performLayout(Size size) {
final historyButtonsSize = layoutChild(
_LayoutId.historyButtons,
BoxConstraints.tightFor(height: size.height),
);
positionChild(_LayoutId.historyButtons, Offset.zero);
final newTabButtonSize = layoutChild(
_LayoutId.addTabButton,
BoxConstraints(
minHeight: size.height,
maxHeight: size.height,
minWidth: historyButtonsSize.width,
),
);
positionChild(
_LayoutId.addTabButton,
size.topRight(-newTabButtonSize.topRight(Offset.zero)),
);
final urlSize = layoutChild(
_LayoutId.url,
BoxConstraints.tightFor(
width: (size.width - historyButtonsSize.width - newTabButtonSize.width)
.clamp(0.0, size.width),
),
);
positionChild(
_LayoutId.url,
Offset(
historyButtonsSize.width,
(size.height - urlSize.height) * 0.5,
),
);
}
@override
bool shouldRelayout(MultiChildLayoutDelegate oldDelegate) => false;
}