adding packages

This commit is contained in:
2026-01-15 14:38:46 -08:00
parent ef86e3ab6a
commit 6869cf47e5
5253 changed files with 726695 additions and 34 deletions
@@ -0,0 +1,11 @@
import 'package:flutter/material.dart';
class DetailsScreen {
const DetailsScreen({
this.appBar,
@required this.body,
});
final Widget body;
final PreferredSizeWidget appBar;
}
@@ -0,0 +1,4 @@
export 'package:responsive_scaffold/data/classes/details.dart';
export 'package:responsive_scaffold/templates/list/responsive_list.dart';
export 'package:responsive_scaffold/templates/layout/scaffold.dart';
export 'package:responsive_scaffold/templates/3-column/three_column_navigation.dart';
@@ -0,0 +1,112 @@
# Screenshots
![image](https://github.com/fluttercommunity/responsive_scaffold/blob/master/screenshots/multi-column/1.png)
![image](https://github.com/fluttercommunity/responsive_scaffold/blob/master/screenshots/multi-column/2.png)
![image](https://github.com/fluttercommunity/responsive_scaffold/blob/master/screenshots/multi-column/3.png)
![image](https://github.com/fluttercommunity/responsive_scaffold/blob/master/screenshots/multi-column/4.png)
![image](https://github.com/fluttercommunity/responsive_scaffold/blob/master/screenshots/multi-column/5.png)
![image](https://github.com/fluttercommunity/plugins/blob/master/packages/responsive_scaffold/screenshots/multi-column/5.png)
![image](https://github.com/fluttercommunity/responsive_scaffold/blob/master/screenshots/multi-column/6.png)
![image](https://github.com/fluttercommunity/responsive_scaffold/blob/master/screenshots/multi-column/7.png)
# Example
``` dart
import 'package:flutter/material.dart';
import 'package:responsive_scaffold/responsive_scaffold.dart';
class MultiColumnNavigationExample extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ThreeColumnNavigation(
title: Text('Mailboxes'),
showDetailsArrows: true,
backgroundColor: Colors.grey[100],
bottomAppBar: BottomAppBar(
elevation: 1,
child: Row(
children: <Widget>[
IconButton(
icon: Icon(
Icons.filter_list,
color: Colors.transparent,
),
onPressed: () {},
),
],
),
),
sections: [
MainSection(
label: Text('All Inboxes'),
icon: Icon(Icons.mail),
itemCount: 100,
itemBuilder: (context, index, selected) {
return ListTile(
leading: CircleAvatar(
child: Text(index.toString()),
),
selected: selected,
title: Text('Primary Information'),
subtitle: Text('Here are some details about the item'),
);
},
bottomAppBar: BottomAppBar(
elevation: 1,
child: Row(
children: <Widget>[
IconButton(
icon: Icon(Icons.filter_list),
onPressed: () {},
),
],
),
),
getDetails: (context, index) {
return DetailsWidget(
title: Text('Details'),
child: Center(
child: Text(
index.toString(),
),
),
);
},
),
MainSection(
label: Text('Sent Mail'),
icon: Icon(Icons.send),
itemCount: 100,
itemBuilder: (context, index, selected) {
return ListTile(
leading: CircleAvatar(
child: Text(index.toString()),
),
selected: selected,
title: Text('Secondary Information'),
subtitle: Text('Here are some details about the item'),
);
},
getDetails: (context, index) {
return DetailsWidget(
title: Text('Details'),
actions: [
IconButton(
icon: Icon(Icons.share),
onPressed: () {},
),
],
child: Center(
child: Text(
index.toString(),
),
),
);
},
),
],
);
}
}
```
@@ -0,0 +1,66 @@
import 'package:flutter/material.dart';
import '../three_column_navigation.dart';
class DetailsView extends StatelessWidget {
const DetailsView({
Key key,
@required int listIndex,
@required DetailsWidget details,
this.previous,
this.next,
this.isLast = false,
this.isFirst = false,
this.automaticallyImplyLeading = true,
this.showDetailsArrows = false,
this.scaffoldKey,
}) : _listIndex = listIndex,
_details = details,
super(key: key);
final int _listIndex;
final DetailsWidget _details;
final VoidCallback previous, next;
final bool showDetailsArrows;
final bool isLast, isFirst;
final bool automaticallyImplyLeading;
final GlobalKey<ScaffoldState> scaffoldKey;
@override
Widget build(BuildContext context) {
return Scaffold(
key: scaffoldKey,
appBar: AppBar(
automaticallyImplyLeading: automaticallyImplyLeading,
title: !showDetailsArrows
? _details.title
: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
IconButton(
icon: Icon(Icons.arrow_upward),
onPressed: isFirst ? null : previous,
),
IconButton(
icon: Icon(Icons.arrow_downward),
onPressed: isLast ? null : next,
),
],
),
if (_details?.title != null)
Expanded(
child: Center(child: _details.title),
),
],
),
actions: _details?.actions,
),
body: _details.child,
bottomNavigationBar: _details?.bottomAppBar,
);
}
}
@@ -0,0 +1,3 @@
export 'details.dart';
export 'section_list.dart';
export 'sections.dart';
@@ -0,0 +1,41 @@
import 'package:flutter/material.dart';
import 'package:scroll_to_index/scroll_to_index.dart';
import '../three_column_navigation.dart';
class SectionList extends StatelessWidget {
const SectionList({
Key key,
@required this.controller,
@required MainSection section,
@required int listIndex,
@required this.listTap,
}) : _section = section,
_listIndex = listIndex,
super(key: key);
final AutoScrollController controller;
final MainSection _section;
final int _listIndex;
final ValueChanged<int> listTap;
@override
Widget build(BuildContext context) {
return ListView.builder(
controller: controller,
itemBuilder: (context, index) {
final _item = _section.itemBuilder(context, index, _listIndex == index);
return AutoScrollTag(
controller: controller,
key: ValueKey(index),
index: index,
child: GestureDetector(
child: _item,
onTap: () => listTap(index),
),
);
},
itemCount: _section.itemCount,
);
}
}
@@ -0,0 +1,33 @@
import 'package:flutter/material.dart';
import '../three_column_navigation.dart';
class SectionsList extends StatelessWidget {
const SectionsList({
Key key,
@required this.sectionTap,
@required int sectionIndex,
@required this.sections,
}) : _sectionIndex = sectionIndex,
super(key: key);
final int _sectionIndex;
final ValueChanged<int> sectionTap;
final List<MainSection> sections;
@override
Widget build(BuildContext context) {
return ListView.builder(
itemBuilder: (context, index) {
final _item = sections[index];
return ListTile(
leading: _item.icon,
title: _item.label,
selected: index == _sectionIndex,
onTap: () => sectionTap(index),
);
},
itemCount: sections.length,
);
}
}
@@ -0,0 +1,341 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:scroll_to_index/scroll_to_index.dart';
import 'common/index.dart';
class ThreeColumnNavigation extends StatefulWidget {
ThreeColumnNavigation({
@required this.sections,
this.showDetailsArrows = true,
this.expandedIconData = Icons.fullscreen_exit,
this.collapsedIconData = Icons.fullscreen,
this.initiallyExpanded = true,
this.bottomAppBar,
this.backgroundColor,
this.title,
});
final Color backgroundColor;
final Widget bottomAppBar;
final IconData expandedIconData, collapsedIconData;
final bool initiallyExpanded;
List<MainSection> sections;
final bool showDetailsArrows;
final Text title;
@override
_ThreeColumnNavigationState createState() => _ThreeColumnNavigationState();
}
class _ThreeColumnNavigationState extends State<ThreeColumnNavigation> {
AutoScrollController controller;
bool _expanded = true;
int _listIndex = 0;
final _scaffoldKey = GlobalKey<ScaffoldState>();
int _sectionIndex = 0;
@override
void initState() {
if (!widget.initiallyExpanded) if (mounted)
setState(() {
_expanded = false;
});
_setUpController(true);
super.initState();
}
void _setUpController(bool init) {
controller = AutoScrollController(
viewportBoundaryGetter: () =>
Rect.fromLTRB(0, 0, 0, MediaQuery.of(context).padding.bottom),
axis: Axis.vertical,
);
}
Future _scrollToIndex(int value,
{AutoScrollPosition position = AutoScrollPosition.middle}) async {
try {
controller.scrollToIndex(
value,
preferPosition: position,
);
// controller.highlight(value);
} on Exception catch (e) {
print('Could not scroll to index: $value => $e');
}
}
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth > 720) {
final _showMenu = constraints.maxWidth < 1100;
if (_showMenu) {
_expanded = false;
}
return Material(
child: Row(
children: <Widget>[
if (_expanded)
Container(
width: 300,
child: Scaffold(
backgroundColor: widget?.backgroundColor,
appBar: AppBar(
title: widget?.title,
leading: IconButton(
icon: Icon(widget.expandedIconData),
onPressed: () {
if (mounted)
setState(() {
_expanded = false;
});
},
),
),
body: SectionsList(
sections: widget.sections,
sectionIndex: _sectionIndex,
sectionTap: (index) {
if (_sectionIndex != index) {
if (mounted)
setState(() {
_sectionIndex = index;
});
_setUpController(false);
}
},
),
bottomNavigationBar: widget?.bottomAppBar,
),
),
Container(
width: 400,
child: Scaffold(
drawerScrimColor: Colors.transparent,
drawer: _showMenu
? SectionsDrawer(
sections: widget.sections,
sectionIndex: _sectionIndex,
sectionChanged: (context, index) {
if (_sectionIndex != index) {
if (mounted)
setState(() {
_sectionIndex = index;
});
_setUpController(false);
Navigator.pop(context);
}
},
)
: null,
appBar: AppBar(
leading: _showMenu
? MenuButton(scaffoldKey: _scaffoldKey)
: !_expanded
? IconButton(
icon: Icon(widget.collapsedIconData),
onPressed: () {
if (mounted)
setState(() {
_expanded = true;
});
},
)
: null,
title: widget.sections[_sectionIndex].label,
),
body: SectionList(
controller: controller,
section: widget.sections[_sectionIndex],
listIndex: _listIndex,
listTap: (index) {
if (_listIndex != index) {
if (mounted)
setState(() {
_listIndex = index;
});
}
},
),
bottomNavigationBar:
widget.sections[_sectionIndex]?.bottomAppBar,
),
),
Expanded(
child: Container(
child: Stack(
children: <Widget>[
DetailsView(
scaffoldKey: _scaffoldKey,
automaticallyImplyLeading: false,
isFirst: _listIndex == 0,
isLast: widget.sections[_sectionIndex].itemCount ==
_listIndex + 1,
listIndex: _listIndex,
details: widget.sections[_sectionIndex]
.getDetails(context, _listIndex),
showDetailsArrows: widget.showDetailsArrows,
previous: () {
if (mounted)
setState(() {
_listIndex--;
});
_scrollToIndex(_listIndex);
},
next: () {
if (mounted)
setState(() {
_listIndex++;
});
_scrollToIndex(_listIndex);
},
),
],
),
),
),
],
),
);
}
return Scaffold(
drawer: SectionsDrawer(
sections: widget.sections,
sectionIndex: _sectionIndex,
sectionChanged: (context, index) {
if (_sectionIndex != index) {
if (mounted)
setState(() {
_sectionIndex = index;
});
_setUpController(false);
Navigator.pop(context);
}
},
),
appBar: AppBar(
title: widget.sections[_sectionIndex]?.label,
),
body: SectionList(
controller: controller,
section: widget.sections[_sectionIndex],
listIndex: _listIndex,
listTap: (index) {
if (_listIndex != index) {
if (mounted)
setState(() {
_listIndex = index;
});
Navigator.of(context).push(MaterialPageRoute(
builder: (_) {
final _details = widget.sections[_sectionIndex]
.getDetails(context, _listIndex);
return DetailsView(
isFirst: _listIndex == 0,
isLast: widget.sections.isNotEmpty &&
_listIndex == widget.sections.length - 1,
listIndex: _listIndex,
details: _details,
showDetailsArrows: false,
);
},
));
}
},
),
bottomNavigationBar: widget.sections[_sectionIndex]?.bottomAppBar,
);
},
);
}
}
class MenuButton extends StatelessWidget {
const MenuButton({
Key key,
@required GlobalKey<ScaffoldState> scaffoldKey,
}) : _scaffoldKey = scaffoldKey,
super(key: key);
final GlobalKey<ScaffoldState> _scaffoldKey;
@override
Widget build(BuildContext context) {
return IconButton(
icon: Icon(Icons.menu),
onPressed: () {
Scaffold.of(context).openDrawer();
// _scaffoldKey.currentState.showBodyScrim(true, 0.5);
},
);
}
}
class SectionsDrawer extends StatelessWidget {
const SectionsDrawer({
Key key,
@required int sectionIndex,
@required this.sectionChanged,
@required this.sections,
}) : _sectionIndex = sectionIndex,
super(key: key);
final List<MainSection> sections;
final int _sectionIndex;
final Function(BuildContext, int) sectionChanged;
@override
Widget build(BuildContext context) {
return Drawer(
child: SectionsList(
sections: sections,
sectionIndex: _sectionIndex,
sectionTap: (index) => sectionChanged(context, index),
),
);
}
}
class MainSection {
const MainSection({
@required this.itemBuilder,
@required this.itemCount,
@required this.getDetails,
@required this.icon,
@required this.label,
this.bottomAppBar,
});
final Widget bottomAppBar;
final Icon icon;
final int itemCount;
final Text label;
final Widget Function(BuildContext context, int index, bool selected)
itemBuilder;
final DetailsWidget Function(BuildContext context, int index) getDetails;
}
class DetailsWidget {
const DetailsWidget({
@required this.child,
this.actions,
this.title,
this.bottomAppBar,
});
final List<Widget> actions;
final Widget bottomAppBar;
final Widget child;
final Text title;
}
@@ -0,0 +1,236 @@
import 'package:flutter/material.dart';
class ResponsiveScaffold extends StatelessWidget {
const ResponsiveScaffold({
this.scaffoldKey,
this.drawer,
this.endDrawer,
this.title,
this.body,
this.trailing,
this.floatingActionButton,
this.menuIcon,
this.endIcon,
this.kTabletBreakpoint = 720.0,
this.kDesktopBreakpoint = 1440.0,
this.appBarElevation,
});
final Widget drawer, endDrawer;
final Widget title;
final Widget body;
final Widget trailing;
final Widget floatingActionButton;
final kTabletBreakpoint;
final kDesktopBreakpoint;
final _drawerWidth = 304.0;
final IconData menuIcon, endIcon;
final double appBarElevation;
final Key scaffoldKey;
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (_, constraints) {
if (constraints.maxWidth >= kDesktopBreakpoint) {
return Material(
child: Stack(
children: <Widget>[
Row(
children: <Widget>[
if (drawer != null) ...[
SizedBox(
width: _drawerWidth,
child: Drawer(
child: SafeArea(
child: drawer,
),
),
),
],
Expanded(
child: Scaffold(
key: scaffoldKey,
appBar: AppBar(
elevation: appBarElevation,
automaticallyImplyLeading: false,
title: title,
actions: <Widget>[
if (trailing != null) ...[
trailing,
],
],
),
body: Row(
children: <Widget>[
Expanded(
child: body ?? Container(),
),
if (endDrawer != null) ...[
Container(
width: _drawerWidth,
child: Drawer(
elevation: 3.0,
child: SafeArea(
child: endDrawer,
),
),
),
],
],
),
),
),
],
),
if (floatingActionButton != null) ...[
Positioned(
top: 100.0,
left: _drawerWidth - 30,
child: floatingActionButton,
)
],
],
),
);
}
if (constraints.maxWidth >= kTabletBreakpoint) {
return Scaffold(
key: scaffoldKey,
drawer: drawer == null
? null
: Drawer(
child: SafeArea(
child: drawer,
),
),
appBar: AppBar(
elevation: appBarElevation,
automaticallyImplyLeading: false,
title: title,
leading: _MenuButton(iconData: menuIcon),
actions: <Widget>[
if (trailing != null) ...[
trailing,
],
],
),
body: SafeArea(
right: false,
bottom: false,
child: Stack(
children: <Widget>[
Row(
children: <Widget>[
Expanded(
child: body ?? Container(),
),
if (endDrawer != null) ...[
Container(
width: _drawerWidth,
child: Drawer(
elevation: 3.0,
child: SafeArea(
child: endDrawer,
),
),
),
],
],
),
if (floatingActionButton != null) ...[
Positioned(
top: 10.0,
left: 10.0,
child: floatingActionButton,
)
],
],
),
),
);
}
return Scaffold(
key: scaffoldKey,
drawer: drawer == null
? null
: Drawer(
child: SafeArea(
child: drawer,
),
),
endDrawer: endDrawer == null
? null
: Drawer(
child: SafeArea(
child: endDrawer,
),
),
appBar: AppBar(
elevation: appBarElevation,
automaticallyImplyLeading: false,
leading: _MenuButton(iconData: menuIcon),
title: title,
actions: <Widget>[
if (trailing != null) ...[
trailing,
],
if (endDrawer != null) ...[
_OptionsButton(iconData: endIcon),
]
],
),
body: body,
floatingActionButton: floatingActionButton,
floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
);
},
);
}
}
class _OptionsButton extends StatelessWidget {
const _OptionsButton({
Key key,
@required this.iconData,
}) : super(key: key);
final IconData iconData;
@override
Widget build(BuildContext context) {
return IconButton(
icon: Icon(iconData ?? Icons.more_vert),
onPressed: () {
Scaffold.of(context).openEndDrawer();
},
);
}
}
class _MenuButton extends StatelessWidget {
const _MenuButton({
Key key,
@required this.iconData,
}) : super(key: key);
final IconData iconData;
@override
Widget build(BuildContext context) {
return IconButton(
icon: Icon(iconData ?? Icons.menu),
onPressed: () {
Scaffold.of(context).openDrawer();
},
);
}
}
@@ -0,0 +1,241 @@
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'responsive_list.dart';
import 'views/index.dart';
export 'package:responsive_scaffold/data/classes/details.dart';
class ResponsiveListScaffold extends StatelessWidget {
ResponsiveListScaffold({
this.tabletBreakpoint = 720.0,
@required this.detailBuilder,
this.appBar,
this.drawer,
this.slivers,
this.endDrawer,
@required List<Widget> children,
this.primary = true,
// this.extendBody = false,
this.drawerDragStartBehavior = DragStartBehavior.start,
this.backgroundColor,
this.bottomNavigationBar,
this.bottomSheet,
this.floatingActionButton,
this.floatingActionButtonAnimator,
this.floatingActionButtonLocation,
this.persistentFooterButtons,
this.resizeToAvoidBottomInset,
this.resizeToAvoidBottomPadding,
this.tabletItemNotSelected,
this.tabletSideMenu,
this.nullItems,
this.emptyItems,
this.tabletFlexDetailView = 8,
this.tabletFlexListView = 3,
this.scaffoldKey,
this.detailScaffoldKey,
this.mobileRootNavigator = false,
this.mobileNavigator,
}) : childDelagate = SliverChildListDelegate(
children,
addAutomaticKeepAlives: false,
addRepaintBoundaries: false,
addSemanticIndexes: false,
);
ResponsiveListScaffold.builder({
this.tabletBreakpoint = 720.0,
@required this.detailBuilder,
this.appBar,
this.drawer,
this.slivers,
this.endDrawer,
@required int itemCount,
@required IndexedWidgetBuilder itemBuilder,
this.primary = true,
// this.extendBody = false,
this.drawerDragStartBehavior = DragStartBehavior.start,
this.backgroundColor,
this.bottomNavigationBar,
this.bottomSheet,
this.floatingActionButton,
this.nullItems,
this.emptyItems,
this.floatingActionButtonAnimator,
this.floatingActionButtonLocation,
this.persistentFooterButtons,
this.resizeToAvoidBottomInset,
this.resizeToAvoidBottomPadding,
this.tabletItemNotSelected,
this.tabletSideMenu,
this.tabletFlexDetailView = 8,
this.tabletFlexListView = 4,
this.scaffoldKey,
this.detailScaffoldKey,
this.mobileRootNavigator = false,
this.mobileNavigator,
}) : childDelagate = SliverChildBuilderDelegate(
itemBuilder,
childCount: itemCount,
addAutomaticKeepAlives: false,
addRepaintBoundaries: false,
addSemanticIndexes: false,
);
ResponsiveListScaffold.custom({
this.tabletBreakpoint = 720.0,
@required this.detailBuilder,
this.appBar,
this.drawer,
this.slivers,
this.endDrawer,
@required this.childDelagate,
this.primary = true,
// this.extendBody = false,
this.drawerDragStartBehavior = DragStartBehavior.start,
this.backgroundColor,
this.bottomNavigationBar,
this.bottomSheet,
this.floatingActionButton,
this.nullItems,
this.emptyItems,
this.floatingActionButtonAnimator,
this.floatingActionButtonLocation,
this.persistentFooterButtons,
this.resizeToAvoidBottomInset,
this.resizeToAvoidBottomPadding,
this.tabletItemNotSelected,
this.tabletSideMenu,
this.tabletFlexDetailView = 8,
this.tabletFlexListView = 4,
this.scaffoldKey,
this.detailScaffoldKey,
this.mobileRootNavigator = false,
this.mobileNavigator,
});
final double tabletBreakpoint;
final DetailWidgetBuilder detailBuilder;
final PreferredSizeWidget appBar;
final Widget drawer, endDrawer;
final List<Widget> slivers;
final Widget floatingActionButton;
final FloatingActionButtonLocation floatingActionButtonLocation;
final Widget bottomNavigationBar;
final Widget bottomSheet;
final List<Widget> persistentFooterButtons;
final FloatingActionButtonAnimator floatingActionButtonAnimator;
final bool resizeToAvoidBottomPadding;
final bool resizeToAvoidBottomInset;
final bool primary;
// final bool extendBody;
final DragStartBehavior drawerDragStartBehavior;
final Color backgroundColor;
final Key scaffoldKey, detailScaffoldKey;
final Widget tabletItemNotSelected;
final Flexible tabletSideMenu;
final int tabletFlexListView;
final int tabletFlexDetailView;
final bool mobileRootNavigator;
final NavigatorState mobileNavigator;
final Widget nullItems, emptyItems;
final SliverChildDelegate childDelagate;
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (_, constraints) {
if (constraints.maxWidth >= tabletBreakpoint) {
// Tablet
return TabletView.custom(
key: key,
nullItems: nullItems,
emptyItems: emptyItems,
scaffoldkey: scaffoldKey,
detailScaffoldKey: detailScaffoldKey,
drawerDragStartBehavior: drawerDragStartBehavior,
floatingActionButton: floatingActionButton,
floatingActionButtonLocation: floatingActionButtonLocation,
bottomNavigationBar: bottomNavigationBar,
bottomSheet: bottomSheet,
persistentFooterButtons: persistentFooterButtons,
floatingActionButtonAnimator: floatingActionButtonAnimator,
resizeToAvoidBottomInset: resizeToAvoidBottomInset,
resizeToAvoidBottomPadding: resizeToAvoidBottomPadding,
primary: primary,
// extendBody: extendBody,
backgroundColor: backgroundColor,
drawer: drawer,
endDrawer: endDrawer,
appBar: appBar,
slivers: slivers,
detailBuilder: detailBuilder,
childDelagate: childDelagate,
flexDetailView: tabletFlexDetailView,
flexListView: tabletFlexListView,
sideMenu: tabletSideMenu,
itemNotSelected: tabletItemNotSelected,
);
}
// Mobile
return Scaffold(
key: scaffoldKey,
floatingActionButton: floatingActionButton,
floatingActionButtonLocation: floatingActionButtonLocation,
bottomNavigationBar: bottomNavigationBar,
bottomSheet: bottomSheet,
persistentFooterButtons: persistentFooterButtons,
floatingActionButtonAnimator: floatingActionButtonAnimator,
resizeToAvoidBottomInset: resizeToAvoidBottomInset,
resizeToAvoidBottomPadding: resizeToAvoidBottomPadding,
primary: primary,
// extendBody: extendBody,
backgroundColor: backgroundColor,
drawer: drawer,
endDrawer: endDrawer,
appBar: appBar,
body: MobileView.custom(
useRootNavigator: mobileRootNavigator,
nullItems: nullItems,
emptyItems: emptyItems,
slivers: slivers,
detailScaffoldKey: detailScaffoldKey,
detailBuilder: detailBuilder,
childDelagate: childDelagate,
navigator: mobileNavigator,
),
);
},
);
}
}
typedef DetailWidgetBuilder = DetailsScreen Function(
BuildContext context, int index, bool tablet);
@@ -0,0 +1,2 @@
export 'mobile.dart';
export 'tablet.dart';
@@ -0,0 +1,136 @@
import 'package:flutter/material.dart';
import '../../../responsive_scaffold.dart';
import '../responsive_list.dart';
class MobileView extends StatelessWidget {
MobileView({
Key key,
@required this.slivers,
@required this.detailBuilder,
@required List<Widget> children,
@required this.detailScaffoldKey,
@required this.useRootNavigator,
@required this.navigator,
@required this.nullItems,
@required this.emptyItems,
}) : childDelagate = SliverChildListDelegate(
children,
addAutomaticKeepAlives: false,
addRepaintBoundaries: false,
addSemanticIndexes: false,
),
super(key: key);
MobileView.builder({
Key key,
@required this.slivers,
@required this.detailBuilder,
@required int itemCount,
@required IndexedWidgetBuilder itemBuilder,
@required this.detailScaffoldKey,
@required this.useRootNavigator,
@required this.navigator,
@required this.nullItems,
@required this.emptyItems,
}) : childDelagate = SliverChildBuilderDelegate(
itemBuilder,
childCount: itemCount,
addAutomaticKeepAlives: false,
addRepaintBoundaries: false,
addSemanticIndexes: false,
),
super(key: key);
MobileView.custom({
Key key,
@required this.slivers,
@required this.detailBuilder,
@required this.childDelagate,
@required this.detailScaffoldKey,
@required this.useRootNavigator,
@required this.navigator,
@required this.nullItems,
@required this.emptyItems,
}) : super(key: key);
final List<Widget> slivers;
final DetailWidgetBuilder detailBuilder;
final Key detailScaffoldKey;
final bool useRootNavigator;
final NavigatorState navigator;
final Widget nullItems, emptyItems;
final SliverChildDelegate childDelagate;
@override
Widget build(BuildContext context) {
return CustomScrollView(
slivers: <Widget>[]
..addAll(slivers ?? [])
..add(Builder(
builder: (BuildContext context) {
if (childDelagate?.estimatedChildCount == null && nullItems != null)
return SliverFillRemaining(child: nullItems);
if (childDelagate?.estimatedChildCount != null &&
childDelagate.estimatedChildCount == 0 &&
emptyItems != null)
return SliverFillRemaining(child: emptyItems);
return SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return new KeepAlive(
keepAlive: true,
child: new IndexedSemantics(
index: index,
child: GestureDetector(
onTap: () {
(navigator ?? Navigator.of(context))
.push(MaterialPageRoute(builder: (context) {
final _details = detailBuilder(context, index, false);
return new DetailView(
detailScaffoldKey: detailScaffoldKey,
itemCount: childDelagate.estimatedChildCount,
details: _details);
}));
},
child: new Container(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: childDelagate.build(context, index),
),
),
),
);
},
childCount: childDelagate?.estimatedChildCount ?? 0,
addAutomaticKeepAlives: false,
addRepaintBoundaries: false,
addSemanticIndexes: false,
));
},
)),
);
}
}
class DetailView extends StatelessWidget {
const DetailView({
Key key,
@required this.itemCount,
@required DetailsScreen details,
@required this.detailScaffoldKey,
}) : _details = details,
super(key: key);
final int itemCount;
final DetailsScreen _details;
final Key detailScaffoldKey;
@override
Widget build(BuildContext context) {
return Scaffold(
key: detailScaffoldKey,
appBar: _details?.appBar,
body: _details.body,
);
}
}
@@ -0,0 +1,290 @@
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import '../../../responsive_scaffold.dart';
import '../responsive_list.dart';
class TabletView extends StatefulWidget {
TabletView({
Key key,
@required this.slivers,
@required this.detailBuilder,
@required List<Widget> children,
@required this.itemNotSelected,
@required this.sideMenu,
this.flexListView = 4,
this.flexDetailView = 8,
@required this.appBar,
@required this.backgroundColor,
@required this.bottomNavigationBar,
@required this.bottomSheet,
@required this.drawer,
@required this.drawerDragStartBehavior,
@required this.endDrawer,
@required this.floatingActionButton,
@required this.floatingActionButtonAnimator,
@required this.floatingActionButtonLocation,
@required this.persistentFooterButtons,
@required this.primary,
@required this.resizeToAvoidBottomInset,
@required this.resizeToAvoidBottomPadding,
@required this.scaffoldkey,
@required this.detailScaffoldKey,
@required this.nullItems,
@required this.emptyItems,
}) : childDelagate = SliverChildListDelegate(
children,
addAutomaticKeepAlives: false,
addRepaintBoundaries: false,
addSemanticIndexes: false,
),
super(key: key);
TabletView.builder({
Key key,
@required this.slivers,
@required this.detailBuilder,
@required int itemCount,
@required IndexedWidgetBuilder itemBuilder,
@required this.itemNotSelected,
@required this.sideMenu,
this.flexListView = 4,
this.flexDetailView = 8,
@required this.appBar,
@required this.backgroundColor,
@required this.bottomNavigationBar,
@required this.bottomSheet,
@required this.drawer,
@required this.drawerDragStartBehavior,
@required this.endDrawer,
@required this.floatingActionButton,
@required this.floatingActionButtonAnimator,
@required this.floatingActionButtonLocation,
@required this.persistentFooterButtons,
@required this.primary,
@required this.resizeToAvoidBottomInset,
@required this.resizeToAvoidBottomPadding,
@required this.scaffoldkey,
@required this.detailScaffoldKey,
@required this.nullItems,
@required this.emptyItems,
}) : childDelagate = SliverChildBuilderDelegate(
itemBuilder,
childCount: itemCount,
addAutomaticKeepAlives: false,
addRepaintBoundaries: false,
addSemanticIndexes: false,
),
super(key: key);
TabletView.custom({
Key key,
@required this.slivers,
@required this.detailBuilder,
@required this.childDelagate,
@required this.itemNotSelected,
@required this.sideMenu,
this.flexListView = 4,
this.flexDetailView = 8,
@required this.appBar,
@required this.backgroundColor,
@required this.bottomNavigationBar,
@required this.bottomSheet,
@required this.drawer,
@required this.drawerDragStartBehavior,
@required this.endDrawer,
@required this.floatingActionButton,
@required this.floatingActionButtonAnimator,
@required this.floatingActionButtonLocation,
@required this.persistentFooterButtons,
@required this.primary,
@required this.resizeToAvoidBottomInset,
@required this.resizeToAvoidBottomPadding,
@required this.scaffoldkey,
@required this.detailScaffoldKey,
@required this.nullItems,
@required this.emptyItems,
}) : super(key: key);
final List<Widget> slivers;
final DetailWidgetBuilder detailBuilder;
final Widget itemNotSelected;
final Flexible sideMenu;
final int flexListView;
final int flexDetailView;
final Widget nullItems, emptyItems;
final Widget floatingActionButton;
final FloatingActionButtonLocation floatingActionButtonLocation;
final Widget bottomNavigationBar;
final Widget bottomSheet;
final List<Widget> persistentFooterButtons;
final FloatingActionButtonAnimator floatingActionButtonAnimator;
final bool resizeToAvoidBottomPadding;
final bool resizeToAvoidBottomInset;
final bool primary;
final Key scaffoldkey, detailScaffoldKey;
// final bool extendBody;
final DragStartBehavior drawerDragStartBehavior;
final Color backgroundColor;
final PreferredSizeWidget appBar;
final Widget drawer, endDrawer;
final SliverChildDelegate childDelagate;
@override
_TabletViewState createState() => _TabletViewState();
}
class _TabletViewState extends State<TabletView> {
int _index;
void reset() {
setState(() {
_index = 0;
});
}
// void update(DetailsScreen value) {
// setState(() {
// _index = value;
// });
// }
@override
Widget build(BuildContext context) {
return Scaffold(
body: Flex(
direction: Axis.horizontal,
children: <Widget>[
widget?.sideMenu ?? Container(),
Flexible(
flex: widget.flexListView,
child: Scaffold(
key: widget?.scaffoldkey,
floatingActionButton: widget?.floatingActionButton,
floatingActionButtonLocation:
widget?.floatingActionButtonLocation,
bottomNavigationBar: widget?.bottomNavigationBar,
bottomSheet: widget?.bottomSheet,
persistentFooterButtons: widget?.persistentFooterButtons,
floatingActionButtonAnimator:
widget?.floatingActionButtonAnimator,
resizeToAvoidBottomInset: widget?.resizeToAvoidBottomInset,
resizeToAvoidBottomPadding: widget?.resizeToAvoidBottomPadding,
primary: widget?.primary,
// extendBody: extendBody,
backgroundColor: widget?.backgroundColor,
drawer: widget?.drawer,
endDrawer: widget?.endDrawer,
appBar: widget?.appBar,
body: CustomScrollView(
slivers: <Widget>[]
..addAll(widget.slivers ?? [])
..add(Builder(
builder: (BuildContext context) {
SliverChildDelegate _childDelagate =
widget?.childDelagate;
if (_childDelagate?.estimatedChildCount == null &&
widget?.nullItems != null)
return SliverFillRemaining(child: widget.nullItems);
if (_childDelagate?.estimatedChildCount != null &&
_childDelagate.estimatedChildCount == 0 &&
widget?.emptyItems != null)
return SliverFillRemaining(child: widget.emptyItems);
return SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return new KeepAlive(
keepAlive: true,
child: new IndexedSemantics(
index: index,
child: GestureDetector(
onTap: () {
setState(() {
_index = index;
});
},
child: new Container(
color: _index == index
? Theme.of(context)
.chipTheme
.disabledColor
: widget?.backgroundColor,
padding:
const EdgeInsets.symmetric(vertical: 8.0),
child: _childDelagate.build(context, index),
),
),
),
);
},
childCount: _childDelagate?.estimatedChildCount ?? 0,
addAutomaticKeepAlives: false,
addRepaintBoundaries: false,
addSemanticIndexes: false,
));
},
)),
),
),
),
Flexible(
flex: widget.flexDetailView,
child: new _DetailView(
detailScaffoldKey: widget?.detailScaffoldKey,
details: _index == null ||
_index > widget.childDelagate.estimatedChildCount - 1
? null
: widget.detailBuilder(context, _index, true),
itemNotSelected: widget?.itemNotSelected,
),
),
],
),
);
}
}
class _DetailView extends StatelessWidget {
const _DetailView({
Key key,
@required DetailsScreen details,
@required this.itemNotSelected,
@required this.detailScaffoldKey,
}) : _details = details,
super(key: key);
final DetailsScreen _details;
final Widget itemNotSelected;
final Key detailScaffoldKey;
@override
Widget build(BuildContext context) {
if (_details == null) {
return itemNotSelected ??
Center(
child: Text("No Item Selected"),
);
}
return Scaffold(
key: detailScaffoldKey,
appBar: _details?.appBar,
body: _details?.body,
);
}
}