Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace NavigationRail with YaruNavigationRail #201

Merged
merged 14 commits into from Oct 6, 2022
9 changes: 5 additions & 4 deletions example/lib/main.dart
Expand Up @@ -82,11 +82,12 @@ class _CompactPage extends StatelessWidget {
final width = MediaQuery.of(context).size.width;

return YaruCompactLayout(
extendNavigationRail: width > 1000,
style: width > 1000
? YaruNavigationRailStyle.labelledExtended
: width > 500
? YaruNavigationRailStyle.labelled
: YaruNavigationRailStyle.compact,
pageItems: [configItem] + examplePageItems,
backgroundColor: Theme.of(context).brightness == Brightness.light
? Colors.white
: Theme.of(context).colorScheme.onSurface.withOpacity(0.03),
);
}
}
Expand Down
169 changes: 58 additions & 111 deletions lib/src/pages/layouts/yaru_compact_layout.dart
Expand Up @@ -2,41 +2,24 @@ import 'package:flutter/material.dart';
import 'package:yaru/yaru.dart';
import '../../../yaru_widgets.dart';

/// A responsive layout switching between [YaruWideLayout]
/// and [YaruNarrowLayout] depening on the screen width.
/// A page layout which use a [YaruNavigationRail] on left for page navigation
class YaruCompactLayout extends StatefulWidget {
const YaruCompactLayout({
super.key,
required this.pageItems,
this.showSelectedLabels = true,
this.showUnselectedLabels = true,
this.labelType = NavigationRailLabelType.none,
this.extendNavigationRail = false,
this.style = YaruNavigationRailStyle.compact,
this.initialIndex = 0,
this.backgroundColor,
});

/// The list of [YaruPageItem] has to be provided.
/// A list of page destinations
final List<YaruPageItem> pageItems;

/// Optional bool to hide selected labels in the [BottomNavigationBar]
final bool showSelectedLabels;

/// Optional bool to hide unselected labels in the [BottomNavigationBar]
final bool showUnselectedLabels;

/// Optionally control the labels of the [NavigationRail]
final NavigationRailLabelType labelType;

/// Defines if the labels are shown right to the icon
/// of the [NavigationRail] in the wide layout
final bool extendNavigationRail;
/// Define the navigation rail style, see [YaruNavigationRailStyle]
final YaruNavigationRailStyle style;

/// The index of the [YaruPageItem] that is selected from [pageItems]
final int initialIndex;

final Color? backgroundColor;

@override
State<YaruCompactLayout> createState() => _YaruCompactLayoutState();
}
Expand All @@ -61,9 +44,6 @@ class _YaruCompactLayoutState extends State<YaruCompactLayout> {

@override
Widget build(BuildContext context) {
final unselectedTextColor =
Theme.of(context).colorScheme.onSurface.withOpacity(0.8);
final selectedTextColor = Theme.of(context).colorScheme.onSurface;
return LayoutBuilder(
builder: (context, constraint) {
return SafeArea(
Expand All @@ -72,97 +52,64 @@ class _YaruCompactLayoutState extends State<YaruCompactLayout> {
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
SizedBox(
height: MediaQuery.of(context).size.height,
child: SingleChildScrollView(
controller: _controller,
child: ConstrainedBox(
constraints:
BoxConstraints(minHeight: constraint.maxHeight),
child: IntrinsicHeight(
child: NavigationRail(
extended:
widget.labelType == NavigationRailLabelType.none
? widget.extendNavigationRail
: false,
unselectedIconTheme: IconThemeData(
color: unselectedTextColor,
),
indicatorColor: Theme.of(context)
.colorScheme
.onSurface
.withOpacity(0.1),
selectedIconTheme: IconThemeData(
color: selectedTextColor,
),
selectedLabelTextStyle: TextStyle(
overflow: TextOverflow.ellipsis,
color: selectedTextColor,
fontSize: 13,
fontWeight: FontWeight.w500,
),
unselectedLabelTextStyle: TextStyle(
color: unselectedTextColor,
overflow: TextOverflow.ellipsis,
fontSize: 13,
fontWeight: FontWeight.w500,
),
backgroundColor: widget.backgroundColor ??
Theme.of(context).colorScheme.background,
selectedIndex: _index,
onDestinationSelected: (index) {
if (widget.pageItems[index].onTap != null) {
widget.pageItems[index].onTap?.call(context);
}
setState(() {
_index = index;
});
},
labelType: widget.labelType,
destinations: [
for (int i = 0; i < widget.pageItems.length; i++)
NavigationRailDestination(
icon: widget.pageItems[i].iconBuilder(
context,
i == _index,
),
selectedIcon: widget.pageItems[i].iconBuilder(
context,
i == _index,
),
label:
widget.pageItems[i].titleBuilder(context),
)
],
),
),
),
),
),
const VerticalDivider(thickness: 1, width: 1),
Expanded(
child: Theme(
data: Theme.of(context).copyWith(
pageTransitionsTheme: YaruPageTransitionsTheme.vertical,
),
child: Navigator(
pages: [
MaterialPage(
key: ValueKey(_index),
child: widget.pageItems.length > _index
? widget.pageItems[_index].builder(context)
: widget.pageItems[0].builder(context),
),
],
onPopPage: (route, result) => route.didPop(result),
),
),
)
_buildNavigationRail(context, constraint),
_buildVerticalSeparator(),
_buildPageView(context),
],
),
),
);
},
);
}

Widget _buildNavigationRail(BuildContext context, BoxConstraints constraint) {
return SizedBox(
height: MediaQuery.of(context).size.height,
child: SingleChildScrollView(
controller: _controller,
child: ConstrainedBox(
constraints: BoxConstraints(minHeight: constraint.maxHeight),
child: YaruNavigationRail(
style: widget.style,
selectedIndex: _index,
onDestinationSelected: (index) {
if (widget.pageItems[index].onTap != null) {
widget.pageItems[index].onTap!.call(context);
}
setState(() {
_index = index;
});
},
destinations: widget.pageItems,
),
),
),
);
}

Widget _buildVerticalSeparator() {
return const VerticalDivider(thickness: 1, width: 1);
}

Widget _buildPageView(BuildContext context) {
return Expanded(
child: Theme(
data: Theme.of(context).copyWith(
pageTransitionsTheme: YaruPageTransitionsTheme.vertical,
),
child: Navigator(
pages: [
MaterialPage(
key: ValueKey(_index),
child: widget.pageItems.length > _index
? widget.pageItems[_index].builder(context)
: widget.pageItems[0].builder(context),
),
],
onPopPage: (route, result) => route.didPop(result),
),
),
);
}
}