Skip to content

Commit

Permalink
Conditional tab order (#98)
Browse files Browse the repository at this point in the history
* Rename borrowed items

* Switch order of first 2 tabs depending on the role

* Create TabFactory

* Add page titles list to the factory

* Extract desktop pages

* Refactor repetition
  • Loading branch information
ANDREYDEN authored Mar 7, 2024
1 parent e2f393d commit cef1450
Show file tree
Hide file tree
Showing 3 changed files with 179 additions and 84 deletions.
107 changes: 23 additions & 84 deletions lib/pages/home_page/home_page.dart
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:spare_parts/pages/home_page/borrowed_items_view.dart';
import 'package:spare_parts/pages/home_page/borrowing_requests_view/borrowing_requests_view.dart';
import 'package:spare_parts/pages/home_page/inventory_view/inventory_view.dart';
import 'package:spare_parts/pages/home_page/settings_view/settings_view.dart';
import 'package:spare_parts/pages/home_page/tab_factory.dart';
import 'package:spare_parts/pages/qr_scan_page.dart';
import 'package:spare_parts/services/repositories/inventory_item_repository.dart';
import 'package:spare_parts/utilities/constants.dart';
import 'package:spare_parts/widgets/add_inventory_item_button.dart';
import 'package:spare_parts/widgets/custom_layout_builder.dart';
import 'package:spare_parts/widgets/title_text.dart';

class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
Expand All @@ -21,8 +18,16 @@ class HomePage extends StatefulWidget {

class _HomePageState extends State<HomePage> {
int _selectedBottomNavItemIndex = 0;
String _pageTitle = 'Spare Parts';
late String _pageTitle;
final PageController pageController = PageController();
late final TabFactory tabFactory;

@override
void initState() {
_pageTitle = isAdmin ? 'Inventory' : 'My Items';
tabFactory = TabFactory(isAdmin: isAdmin, isDesktop: false);
super.initState();
}

void _handleSignOut() {
final auth = context.read<FirebaseAuth>();
Expand Down Expand Up @@ -75,19 +80,7 @@ class _HomePageState extends State<HomePage> {

setState(() {
_selectedBottomNavItemIndex = index;
switch (index) {
case 1:
_pageTitle = 'Borrowed Items';
break;
case 2:
_pageTitle = 'Borrowing Requests';
break;
case 3:
_pageTitle = 'Settings';
break;
default:
_pageTitle = 'Spare Parts';
}
_pageTitle = tabFactory.getPageTitles()[index];
});
}

Expand All @@ -103,20 +96,22 @@ class _HomePageState extends State<HomePage> {
Widget build(BuildContext context) {
return CustomLayoutBuilder(
builder: (context, layout) {
final isDesktop = layout == LayoutType.desktop;
tabFactory.isDesktop = isDesktop;

return Scaffold(
floatingActionButtonLocation: layout == LayoutType.desktop
? FloatingActionButtonLocation.startFloat
: null,
floatingActionButtonLocation:
isDesktop ? FloatingActionButtonLocation.startFloat : null,
appBar: AppBar(
centerTitle: true,
title: Text(_pageTitle),
title: Text(isDesktop ? 'Spare Parts' : _pageTitle),
actions: [
IconButton(
icon: const Icon(Icons.qr_code_scanner),
onPressed: _handleScan,
color: Theme.of(context).colorScheme.primary,
),
if (layout == LayoutType.desktop && isAdmin)
if (isDesktop && isAdmin)
TextButton.icon(
label: Text('Settings'),
onPressed: _handleSettings,
Expand All @@ -130,76 +125,20 @@ class _HomePageState extends State<HomePage> {
],
),
floatingActionButton: isAdmin ? AddInventoryItemButton() : null,
body: layout == LayoutType.desktop
body: isDesktop
? SizedBox(
child: Row(
children: [
Expanded(
child: Column(
children: const [
TitleText('Inventory'),
Expanded(child: InventoryView()),
],
),
),
VerticalDivider(),
Expanded(
child: Column(
children: const [
TitleText('Borrowed Items'),
Expanded(child: BorrowedItemsView())
],
),
),
VerticalDivider(),
Expanded(
child: Column(
children: const [
TitleText('Borrowing Requests'),
Expanded(child: BorrowingRequestsView())
],
),
)
],
),
child: Row(children: tabFactory.getDesktopPages()),
)
: PageView(
controller: pageController,
onPageChanged: _onPageChanged,
children: [
InventoryView(),
BorrowedItemsView(),
BorrowingRequestsView(),
if (isAdmin) SettingsView()
],
children: tabFactory.getPages(),
),
bottomNavigationBar: layout == LayoutType.desktop
bottomNavigationBar: isDesktop
? null
: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
items: [
BottomNavigationBarItem(
icon: Icon(Icons.home_outlined),
activeIcon: Icon(Icons.home),
label: 'Inventory',
),
BottomNavigationBarItem(
icon: Icon(Icons.backpack_outlined),
activeIcon: Icon(Icons.backpack),
label: 'Borrowed Items',
),
BottomNavigationBarItem(
icon: Icon(Icons.waving_hand_outlined),
activeIcon: Icon(Icons.waving_hand),
label: 'Borrowing Requests',
),
if (isAdmin)
BottomNavigationBarItem(
icon: Icon(Icons.settings_outlined),
activeIcon: Icon(Icons.settings),
label: 'Settings',
),
],
items: tabFactory.getBottomNavBarItems(),
currentIndex: _selectedBottomNavItemIndex,
onTap: _onBottomNavItemTapped,
),
Expand Down
116 changes: 116 additions & 0 deletions lib/pages/home_page/tab_factory.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import 'package:flutter/material.dart';
import 'package:spare_parts/pages/home_page/borrowed_items_view.dart';
import 'package:spare_parts/pages/home_page/borrowing_requests_view/borrowing_requests_view.dart';
import 'package:spare_parts/pages/home_page/inventory_view/inventory_view.dart';
import 'package:spare_parts/pages/home_page/settings_view/settings_view.dart';
import 'package:spare_parts/widgets/title_text.dart';

class TabFactory {
bool isAdmin;
bool isDesktop;

TabFactory({required this.isAdmin, required this.isDesktop});

List<BottomNavigationBarItem> getBottomNavBarItems() {
return getTabs()
.map(
(tab) => BottomNavigationBarItem(
icon: Icon(tab.activeIcon),
activeIcon: Icon(tab.inactiveIcon),
label: tab.title,
),
)
.toList();
}

List<Widget> getPages() {
return getTabs().map((tab) => tab.widget).toList();
}

List<Widget> getDesktopPages() {
final List<Widget> pages = [];
final tabs = getTabs();

for (var i = 0; i < tabs.length; i++) {
pages.add(Expanded(
child: Column(
children: [
TitleText(tabs[i].title),
Expanded(child: tabs[i].widget),
],
),
));

if (i != tabs.length - 1) {
pages.add(VerticalDivider());
}
}

return pages;
}

List<String> getPageTitles() {
return getTabs().map((tab) => tab.title).toList();
}

List<TabInfo> getTabs() {
final tabs = [
TabInfo(
title: 'Inventory',
activeIcon: Icons.home_outlined,
inactiveIcon: Icons.home,
widget: InventoryView(),
ordinal: isDesktop
? 1
: isAdmin
? 1
: 2,
),
TabInfo(
title: 'My Items',
activeIcon: Icons.backpack_outlined,
inactiveIcon: Icons.backpack,
widget: BorrowedItemsView(),
ordinal: isDesktop
? 2
: isAdmin
? 2
: 1,
),
TabInfo(
title: 'Borrowing Requests',
activeIcon: Icons.waving_hand_outlined,
inactiveIcon: Icons.waving_hand,
widget: BorrowingRequestsView(),
ordinal: 3,
),
TabInfo(
title: 'Settings',
activeIcon: Icons.settings_outlined,
inactiveIcon: Icons.settings,
widget: SettingsView(),
ordinal: isDesktop ? -1 : 4,
),
];

final activeTabs = tabs.where((tab) => tab.ordinal != -1).toList();
activeTabs.sort((tab1, tab2) => tab1.ordinal - tab2.ordinal);
return activeTabs;
}
}

class TabInfo {
final String title;
final IconData activeIcon;
final IconData inactiveIcon;
final int ordinal;
Widget widget;

TabInfo({
required this.title,
required this.activeIcon,
required this.inactiveIcon,
required this.widget,
required this.ordinal,
});
}
40 changes: 40 additions & 0 deletions test/pages/home_page/home_page_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:spare_parts/pages/home_page/home_page.dart';
import 'package:spare_parts/utilities/constants.dart';

import '../../helpers/test_helpers.dart';

void main() {
group('Home Page', () {
testWidgets('renders My Items page when current user is not admin',
(WidgetTester tester) async {
await pumpPage(
HomePage(),
tester,
userRole: UserRole.user,
);

final matchingTitle = find.descendant(
of: find.byType(AppBar),
matching: find.text('My Items'),
);
expect(matchingTitle, findsOneWidget);
});

testWidgets('renders Inventory page when current user is admin',
(WidgetTester tester) async {
await pumpPage(
HomePage(),
tester,
userRole: UserRole.admin,
);

final matchingTitle = find.descendant(
of: find.byType(AppBar),
matching: find.text('Inventory'),
);
expect(matchingTitle, findsOneWidget);
});
});
}

0 comments on commit cef1450

Please sign in to comment.