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

YaruMasterDetailPage: replace "page item" with indexed builders #248

Merged
merged 1 commit into from
Oct 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
14 changes: 11 additions & 3 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ class _HomeState extends State<Home> {
iconBuilder: (context, selected) => const Icon(YaruIcons.settings),
);

final pageItems = _filteredItems.isNotEmpty
? _filteredItems
: [configItem] + examplePageItems;

return MaterialApp(
title: 'Yaru Widgets Factory',
scrollBehavior: TouchMouseStylusScrollBehavior(),
Expand All @@ -60,9 +64,13 @@ class _HomeState extends State<Home> {
: YaruMasterDetailPage(
leftPaneWidth: 280,
previousIconData: YaruIcons.go_previous,
pageItems: _filteredItems.isNotEmpty
? _filteredItems
: [configItem] + examplePageItems,
length: pageItems.length,
iconBuilder: (context, index, selected) =>
pageItems[index].iconBuilder(context, selected),
titleBuilder: (context, index, selected) =>
pageItems[index].titleBuilder(context),
pageBuilder: (context, index) =>
pageItems[index].builder(context),
appBar: AppBar(
title: const Text('Example'),
),
Expand Down
42 changes: 27 additions & 15 deletions lib/src/pages/layouts/yaru_landscape_layout.dart
Original file line number Diff line number Diff line change
@@ -1,26 +1,37 @@
import 'package:flutter/material.dart';
import 'package:yaru/yaru.dart';

import 'yaru_page_item.dart';
import 'yaru_master_detail_page.dart';
import 'yaru_page_item_list_view.dart';

class YaruLandscapeLayout extends StatefulWidget {
/// Creates a landscape layout
const YaruLandscapeLayout({
super.key,
required this.length,
required this.selectedIndex,
required this.pageItems,
required this.iconBuilder,
required this.titleBuilder,
required this.pageBuilder,
required this.onSelected,
required this.leftPaneWidth,
this.appBar,
});

/// The total number of pages.
final int length;

/// Current index of the selected page.
final int selectedIndex;

/// Creates horizontal array of pages.
/// All the `children` will be of type [YaruPageItem]
final List<YaruPageItem> pageItems;
/// A builder that is called for each page to build its icon.
final YaruMasterDetailBuilder iconBuilder;

/// A builder that is called for each page to build its title.
final YaruMasterDetailBuilder titleBuilder;

/// A builder that is called for each page to build its content.
final IndexedWidgetBuilder pageBuilder;

/// Callback that returns an index when the page changes.
final ValueChanged<int> onSelected;
Expand Down Expand Up @@ -68,11 +79,11 @@ class _YaruLandscapeLayoutState extends State<YaruLandscapeLayout> {
if (widget.appBar != null)
Expanded(
child: AppBar(
title: widget.pageItems[
widget.pageItems.length > _selectedIndex
? _selectedIndex
: 0]
.titleBuilder(context),
title: widget.titleBuilder(
context,
widget.length > _selectedIndex ? _selectedIndex : 0,
false,
),
),
)
],
Expand All @@ -95,9 +106,11 @@ class _YaruLandscapeLayoutState extends State<YaruLandscapeLayout> {
),
),
child: YaruPageItemListView(
length: widget.length,
selectedIndex: _selectedIndex,
onTap: _onTap,
pages: widget.pageItems,
iconBuilder: widget.iconBuilder,
titleBuilder: widget.titleBuilder,
),
),
),
Expand All @@ -110,10 +123,9 @@ class _YaruLandscapeLayoutState extends State<YaruLandscapeLayout> {
pages: [
MaterialPage(
key: ValueKey(_selectedIndex),
child: widget.pageItems.length > _selectedIndex
? widget.pageItems[_selectedIndex]
.builder(context)
: widget.pageItems[0].builder(context),
child: widget.length > _selectedIndex
? widget.pageBuilder(context, _selectedIndex)
: widget.pageBuilder(context, 0),
),
],
onPopPage: (route, result) => route.didPop(result),
Expand Down
38 changes: 29 additions & 9 deletions lib/src/pages/layouts/yaru_master_detail_page.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import 'package:flutter/material.dart';
import 'yaru_landscape_layout.dart';
import 'yaru_page_item.dart';
import 'yaru_portrait_layout.dart';

typedef YaruMasterDetailBuilder = Widget Function(
BuildContext context,
int index,
bool selected,
);

class YaruMasterDetailPage extends StatefulWidget {
/// Creates a basic responsive layout with yaru theme,
/// renders layout based on [width] constrain.
Expand All @@ -21,17 +26,26 @@ class YaruMasterDetailPage extends StatefulWidget {
/// ```
const YaruMasterDetailPage({
super.key,
required this.pageItems,
required this.length,
required this.iconBuilder,
required this.titleBuilder,
required this.pageBuilder,
this.previousIconData,
required this.leftPaneWidth,
this.appBar,
});

/// Creates horizontal array of pages.
/// All the `children` will be of type [YaruPageItem].
///
/// These List of items are passed to [YaruLandscapeLayout] and [YaruPortraitLayout].
final List<YaruPageItem> pageItems;
/// The total number of pages.
final int length;

/// A builder that is called for each page to build its icon.
final YaruMasterDetailBuilder iconBuilder;

/// A builder that is called for each page to build its title.
final YaruMasterDetailBuilder titleBuilder;

/// A builder that is called for each page to build its content.
final IndexedWidgetBuilder pageBuilder;

/// Specifies the width of left pane.
final double leftPaneWidth;
Expand Down Expand Up @@ -61,16 +75,22 @@ class _YaruMasterDetailPageState extends State<YaruMasterDetailPage> {
builder: (context, constraints) {
if (constraints.maxWidth < 620) {
return YaruPortraitLayout(
length: widget.length,
selectedIndex: _index,
pageItems: widget.pageItems,
iconBuilder: widget.iconBuilder,
titleBuilder: widget.titleBuilder,
pageBuilder: widget.pageBuilder,
onSelected: _setIndex,
previousIconData: widget.previousIconData,
appBar: widget.appBar,
);
} else {
return YaruLandscapeLayout(
length: widget.length,
selectedIndex: _index == -1 ? _previousIndex : _index,
pageItems: widget.pageItems,
iconBuilder: widget.iconBuilder,
titleBuilder: widget.titleBuilder,
pageBuilder: widget.pageBuilder,
onSelected: _setIndex,
leftPaneWidth: widget.leftPaneWidth,
appBar: widget.appBar,
Expand Down
19 changes: 11 additions & 8 deletions lib/src/pages/layouts/yaru_page_item_list_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,17 @@ const double _kScrollbarMargin = 2.0;
class YaruPageItemListView extends StatelessWidget {
const YaruPageItemListView({
super.key,
required this.pages,
required this.length,
required this.selectedIndex,
required this.iconBuilder,
required this.titleBuilder,
required this.onTap,
this.materialTiles = false,
});

final List<YaruPageItem> pages;
final int length;
final YaruMasterDetailBuilder iconBuilder;
final YaruMasterDetailBuilder titleBuilder;
final int selectedIndex;
final Function(int index) onTap;
final bool materialTiles;
Expand All @@ -33,20 +37,19 @@ class YaruPageItemListView extends StatelessWidget {
)
: null,
controller: ScrollController(),
itemCount: pages.length,
itemCount: length,
itemBuilder: (context, index) => materialTiles
? ListTile(
visualDensity: const VisualDensity(horizontal: -4, vertical: -4),
selected: index == selectedIndex,
title: pages[index].titleBuilder(context),
leading:
pages[index].iconBuilder(context, index == selectedIndex),
title: titleBuilder(context, index, index == selectedIndex),
leading: iconBuilder(context, index, index == selectedIndex),
onTap: () => onTap(index),
)
: _YaruListTile(
selected: index == selectedIndex,
title: pages[index].titleBuilder(context),
icon: pages[index].iconBuilder(context, index == selectedIndex),
title: titleBuilder(context, index, index == selectedIndex),
icon: iconBuilder(context, index, index == selectedIndex),
onTap: () => onTap(index),
),
);
Expand Down
22 changes: 15 additions & 7 deletions lib/src/pages/layouts/yaru_portrait_layout.dart
Original file line number Diff line number Diff line change
@@ -1,21 +1,27 @@
import 'package:flutter/material.dart';
import 'package:yaru/yaru.dart';

import 'yaru_page_item.dart';
import 'yaru_master_detail_page.dart';
import 'yaru_page_item_list_view.dart';

class YaruPortraitLayout extends StatefulWidget {
const YaruPortraitLayout({
super.key,
required this.length,
required this.selectedIndex,
required this.pageItems,
required this.iconBuilder,
required this.titleBuilder,
required this.pageBuilder,
required this.onSelected,
this.previousIconData,
this.appBar,
});

final int length;
final int selectedIndex;
final List<YaruPageItem> pageItems;
final YaruMasterDetailBuilder iconBuilder;
final YaruMasterDetailBuilder titleBuilder;
final IndexedWidgetBuilder pageBuilder;
final ValueChanged<int> onSelected;
final IconData? previousIconData;

Expand Down Expand Up @@ -52,19 +58,19 @@ class _YaruPortraitLayoutState extends State<YaruPortraitLayout> {
final width = MediaQuery.of(context).size.width;
return MaterialPageRoute(
builder: (context) {
final page = widget.pageItems[_selectedIndex];
return Scaffold(
appBar: widget.appBar != null
? AppBar(
title: page.titleBuilder(context),
title: widget.titleBuilder(context, index, false),
leading: InkWell(
child:
Icon(widget.previousIconData ?? Icons.navigate_before),
onTap: _goBack,
),
)
: null,
body: SizedBox(width: width, child: page.builder(context)),
body:
SizedBox(width: width, child: widget.pageBuilder(context, index)),
floatingActionButton: widget.appBar == null
? FloatingActionButton(
child: Icon(widget.previousIconData),
Expand Down Expand Up @@ -96,9 +102,11 @@ class _YaruPortraitLayoutState extends State<YaruPortraitLayout> {
return Scaffold(
appBar: widget.appBar,
body: YaruPageItemListView(
length: widget.length,
selectedIndex: _selectedIndex,
onTap: _onTap,
pages: widget.pageItems,
iconBuilder: widget.iconBuilder,
titleBuilder: widget.titleBuilder,
),
);
},
Expand Down