Simplify mobile navigation and update progress plan
This commit is contained in:
@@ -19,18 +19,24 @@ class _AppShellState extends ConsumerState<AppShell> {
|
||||
int _index = 0;
|
||||
|
||||
static const List<_ShellDestination> _destinations = <_ShellDestination>[
|
||||
_ShellDestination('Dashboard', Icons.dashboard_rounded),
|
||||
_ShellDestination('People', Icons.people_alt_rounded),
|
||||
_ShellDestination('Moments', Icons.auto_awesome_rounded),
|
||||
_ShellDestination('Signals', Icons.tips_and_updates_rounded),
|
||||
_ShellDestination('Sync', Icons.sync_rounded),
|
||||
_ShellDestination('Settings', Icons.settings_rounded),
|
||||
_ShellDestination('Dashboard', Icons.dashboard_rounded, 0),
|
||||
_ShellDestination('People', Icons.people_alt_rounded, 1),
|
||||
_ShellDestination('Moments', Icons.auto_awesome_rounded, 2),
|
||||
_ShellDestination('Signals', Icons.tips_and_updates_rounded, 3),
|
||||
_ShellDestination('Sync', Icons.sync_rounded, 4),
|
||||
_ShellDestination('Settings', Icons.settings_rounded, 5),
|
||||
];
|
||||
|
||||
static const List<_ShellDestination> _compactPrimaryDestinations =
|
||||
<_ShellDestination>[
|
||||
_ShellDestination('Dashboard', Icons.dashboard_rounded, 0),
|
||||
_ShellDestination('People', Icons.people_alt_rounded, 1),
|
||||
_ShellDestination('Moments', Icons.auto_awesome_rounded, 2),
|
||||
_ShellDestination('Signals', Icons.tips_and_updates_rounded, 3),
|
||||
];
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final Widget body = _screenFor(_index);
|
||||
|
||||
return DecoratedBox(
|
||||
decoration: const BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
@@ -49,15 +55,36 @@ class _AppShellState extends ConsumerState<AppShell> {
|
||||
child: LayoutBuilder(
|
||||
builder: (BuildContext context, BoxConstraints constraints) {
|
||||
if (constraints.maxWidth < 1000) {
|
||||
final int compactIndex = _compactSelectedIndex(_index);
|
||||
final _ShellDestination active =
|
||||
_compactPrimaryDestinations[compactIndex];
|
||||
return _CompactShell(
|
||||
index: _index,
|
||||
body: body,
|
||||
destinations: _destinations,
|
||||
title: active.label,
|
||||
index: compactIndex,
|
||||
body: _screenFor(active.screenIndex),
|
||||
destinations: _compactPrimaryDestinations,
|
||||
onChange: (int value) {
|
||||
setState(() {
|
||||
_index = value;
|
||||
_index = _compactPrimaryDestinations[value].screenIndex;
|
||||
});
|
||||
},
|
||||
onOpenSecondary: (_SecondaryDestination destination) {
|
||||
final int screenIndex = switch (destination) {
|
||||
_SecondaryDestination.sync => 4,
|
||||
_SecondaryDestination.settings => 5,
|
||||
};
|
||||
|
||||
Navigator.of(context).push<void>(
|
||||
MaterialPageRoute<void>(
|
||||
builder: (BuildContext context) {
|
||||
return _CompactSecondaryScreen(
|
||||
title: _destinations[screenIndex].label,
|
||||
child: _screenFor(screenIndex),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -77,7 +104,7 @@ class _AppShellState extends ConsumerState<AppShell> {
|
||||
duration: const Duration(milliseconds: 250),
|
||||
child: KeyedSubtree(
|
||||
key: ValueKey<int>(_index),
|
||||
child: body,
|
||||
child: _screenFor(_index),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -90,6 +117,15 @@ class _AppShellState extends ConsumerState<AppShell> {
|
||||
);
|
||||
}
|
||||
|
||||
int _compactSelectedIndex(int fullIndex) {
|
||||
for (int i = 0; i < _compactPrimaryDestinations.length; i += 1) {
|
||||
if (_compactPrimaryDestinations[i].screenIndex == fullIndex) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Widget _screenFor(int index) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
@@ -227,22 +263,60 @@ class _Sidebar extends StatelessWidget {
|
||||
|
||||
class _CompactShell extends StatelessWidget {
|
||||
const _CompactShell({
|
||||
required this.title,
|
||||
required this.index,
|
||||
required this.body,
|
||||
required this.destinations,
|
||||
required this.onChange,
|
||||
required this.onOpenSecondary,
|
||||
});
|
||||
|
||||
final String title;
|
||||
final int index;
|
||||
final Widget body;
|
||||
final List<_ShellDestination> destinations;
|
||||
final ValueChanged<int> onChange;
|
||||
final ValueChanged<_SecondaryDestination> onOpenSecondary;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
Expanded(child: body),
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 12, 16, 4),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Text(
|
||||
title,
|
||||
style: Theme.of(context).textTheme.titleLarge,
|
||||
),
|
||||
),
|
||||
PopupMenuButton<_SecondaryDestination>(
|
||||
tooltip: 'More',
|
||||
icon: const Icon(Icons.more_horiz_rounded),
|
||||
onSelected: onOpenSecondary,
|
||||
itemBuilder: (BuildContext context) =>
|
||||
<PopupMenuEntry<_SecondaryDestination>>[
|
||||
const PopupMenuItem<_SecondaryDestination>(
|
||||
value: _SecondaryDestination.sync,
|
||||
child: Text('Sync'),
|
||||
),
|
||||
const PopupMenuItem<_SecondaryDestination>(
|
||||
value: _SecondaryDestination.settings,
|
||||
child: Text('Settings'),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: AnimatedSwitcher(
|
||||
duration: const Duration(milliseconds: 220),
|
||||
child: KeyedSubtree(key: ValueKey<int>(index), child: body),
|
||||
),
|
||||
),
|
||||
NavigationBar(
|
||||
selectedIndex: index,
|
||||
onDestinationSelected: onChange,
|
||||
@@ -260,9 +334,37 @@ class _CompactShell extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
class _CompactSecondaryScreen extends StatelessWidget {
|
||||
const _CompactSecondaryScreen({required this.title, required this.child});
|
||||
|
||||
final String title;
|
||||
final Widget child;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return DecoratedBox(
|
||||
decoration: const BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
colors: <Color>[Color(0xFFF3F8FB), Color(0xFFEAF1F8)],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
),
|
||||
),
|
||||
child: Scaffold(
|
||||
backgroundColor: Colors.transparent,
|
||||
appBar: AppBar(title: Text(title)),
|
||||
body: child,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
enum _SecondaryDestination { sync, settings }
|
||||
|
||||
class _ShellDestination {
|
||||
const _ShellDestination(this.label, this.icon);
|
||||
const _ShellDestination(this.label, this.icon, this.screenIndex);
|
||||
|
||||
final String label;
|
||||
final IconData icon;
|
||||
final int screenIndex;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user