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

General Improvements #105

Merged
merged 13 commits into from
Apr 8, 2024
4 changes: 2 additions & 2 deletions lib/business_logic/item_action.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import 'package:spare_parts/utilities/constants.dart';
import 'package:spare_parts/utilities/helpers.dart';
import 'package:spare_parts/widgets/dialogs/print_dialog/print_dialog_mobile.dart'
if (dart.library.html) 'package:spare_parts/widgets/dialogs/print_dialog/print_dialog_web.dart';
import 'package:spare_parts/widgets/inputs/user_selection_dialog.dart';
import 'package:spare_parts/widgets/dialogs/user_selection_dialog.dart';
import 'package:spare_parts/widgets/inventory_list_item/inventory_item_form.dart';

import '../services/repositories/repositories.dart';
Expand Down Expand Up @@ -97,7 +97,7 @@ class AssignItemAction extends ItemAction {
final users = await showDialog<List<CustomUser>?>(
context: context,
builder: (context) => UserSelectionDialog(
title: 'Select user',
title: 'Select User',
isSingleSelection: true,
selectedUsers: item.borrower == null ? [] : [item.borrower!],
),
Expand Down
10 changes: 10 additions & 0 deletions lib/entities/custom_user.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,14 @@ class CustomUser {
'photoURL': photoURL,
};
}

@override
bool operator ==(Object other) {
if (identical(this, other)) return true;

return other is CustomUser && other.uid == uid;
}

@override
int get hashCode => uid.hashCode;
}
4 changes: 3 additions & 1 deletion lib/factories/inventory_item_factory.dart
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import 'package:spare_parts/entities/custom_user.dart';
import 'package:spare_parts/entities/inventory_item.dart';
import 'package:spare_parts/factories/factory.dart';

class InventoryItemFactory extends Factory<InventoryItem> {
@override
InventoryItem create({String? name}) {
InventoryItem create({String? name, CustomUser? borrower}) {
return InventoryItem(
id: faker.guid.guid(),
type: faker.company.suffix(),
name: name ?? faker.company.name(),
borrower: borrower
);
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:spare_parts/pages/home_page/inventory_view/filters/inventory_view_filter_selection.dart';

class AvailableItemsFilter extends StatelessWidget {
final bool value;
final void Function() onPressed;
const AvailableItemsFilter({super.key});

const AvailableItemsFilter({
super.key,
required this.value,
required this.onPressed,
});
void onPressed(BuildContext context) {
final selection = context.read<InventoryViewFilterSelection>();
selection.toggleShowOnlyAvailableItems();
}

@override
Widget build(BuildContext context) {
final value = context.select<InventoryViewFilterSelection, bool>(
(selection) => selection.showOnlyAvailableItems);

return TextButton.icon(
label: Text('Only available items'),
icon: Icon(
Expand All @@ -20,7 +23,7 @@ class AvailableItemsFilter extends StatelessWidget {
style: TextButton.styleFrom(
foregroundColor: Theme.of(context).textTheme.bodyLarge!.color,
),
onPressed: onPressed,
onPressed: () => onPressed(context),
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import 'package:flutter/foundation.dart';
import 'package:spare_parts/entities/custom_user.dart';

class InventoryViewFilterSelection extends ChangeNotifier {
List<String> selectedItemTypes = [];
List<CustomUser> selectedBorrowers = [];
bool showOnlyAvailableItems = false;

InventoryViewFilterSelection({
this.selectedItemTypes = const [],
this.selectedBorrowers = const [],
this.showOnlyAvailableItems = false,
});

void updateSelectedItemTypes(List<String> selectedItemTypes) {
this.selectedItemTypes = selectedItemTypes;
notifyListeners();
}

void updateSelectedBorrowers(List<CustomUser> selectedBorrowers) {
this.selectedBorrowers = selectedBorrowers;
notifyListeners();
}

void toggleShowOnlyAvailableItems() {
showOnlyAvailableItems = !showOnlyAvailableItems;
notifyListeners();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:spare_parts/pages/home_page/inventory_view/filters/available_items_filter.dart';
import 'package:spare_parts/pages/home_page/inventory_view/filters/item_type_filter.dart';
import 'package:spare_parts/pages/home_page/inventory_view/filters/user_filter.dart';
import 'package:spare_parts/utilities/constants.dart';

class InventoryViewFilters extends StatelessWidget {
const InventoryViewFilters({
super.key,
});

@override
Widget build(BuildContext context) {
bool isAdmin = context.watch<UserRole>() == UserRole.admin;

return SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: [
SizedBox(width: 5),
ItemTypeFilter(),
if (isAdmin) ...[
SizedBox(width: 10),
UserFilter(),
SizedBox(width: 10),
AvailableItemsFilter(),
],
],
),
);
}
}
37 changes: 37 additions & 0 deletions lib/pages/home_page/inventory_view/filters/item_type_filter.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:spare_parts/pages/home_page/inventory_view/filters/inventory_view_filter_selection.dart';
import 'package:spare_parts/utilities/constants.dart';
import 'package:spare_parts/widgets/dialogs/value_selection_dialog.dart';
import 'package:spare_parts/widgets/inputs/multiselect_button.dart';

class ItemTypeFilter extends StatelessWidget {
const ItemTypeFilter({
super.key,
});

void onChanged(BuildContext context, List<String> selectedItemTypes) {
final selection = context.read<InventoryViewFilterSelection>();
selection.updateSelectedItemTypes(selectedItemTypes);
}

@override
Widget build(BuildContext context) {
final selectedItemTypes =
context.select<InventoryViewFilterSelection, List<String>>(
(selection) => selection.selectedItemTypes);

return MultiselectButton<String>(
buttonLabel: 'Item Types',
hasSelection: selectedItemTypes.isNotEmpty,
onConfirm: (values) => onChanged(context, values),
dialog: ValueSelectionDialog<String>(
values: itemTypes.keys.toList(),
selectedValues: selectedItemTypes,
title: 'Pick Item Types',
leadingBuilder: (itemType) =>
Icon(itemTypes[itemType] ?? itemTypes['Other']!),
),
);
}
}
36 changes: 0 additions & 36 deletions lib/pages/home_page/inventory_view/filters/search_field.dart

This file was deleted.

71 changes: 20 additions & 51 deletions lib/pages/home_page/inventory_view/filters/user_filter.dart
Original file line number Diff line number Diff line change
@@ -1,65 +1,34 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:spare_parts/dtos/user_dto.dart';
import 'package:spare_parts/services/callable_service.dart';
import 'package:spare_parts/entities/custom_user.dart';
import 'package:spare_parts/pages/home_page/inventory_view/filters/inventory_view_filter_selection.dart';
import 'package:spare_parts/widgets/dialogs/user_selection_dialog.dart';
import 'package:spare_parts/widgets/inputs/multiselect_button.dart';
import 'package:spare_parts/widgets/user_avatar.dart';

class UserFilter extends StatefulWidget {
final List<String> selectedUsers;
final void Function(List<String>) onChanged;
final IconData? icon;

class UserFilter extends StatelessWidget {
const UserFilter({
super.key,
required this.selectedUsers,
required this.onChanged,
this.icon,
super.key
});

@override
State<UserFilter> createState() => _UserFilterState();
}

class _UserFilterState extends State<UserFilter> {
late Future<List<UserDto>> _userQuery;

@override
void initState() {
final callableService = context.read<CallableService>();
_userQuery = callableService.getUsers();

super.initState();
void onChanged(BuildContext context, List<CustomUser> selectedUsers) {
final selection = context.read<InventoryViewFilterSelection>();
selection.updateSelectedBorrowers(selectedUsers);
}

@override
Widget build(BuildContext context) {
return FutureBuilder<List<UserDto>>(
future: _userQuery,
builder: (context, snap) {
if (!snap.hasData || snap.hasError) {
return SizedBox.square(
dimension: 20,
child: CircularProgressIndicator(strokeWidth: 3),
);
}

final users = snap.data!;

return MultiselectButton(
buttonLabel: 'Borrowers',
values: users.map((u) => u.id).toList(),
selectedValues: widget.selectedUsers,
onConfirm: widget.onChanged,
icon: widget.icon,
labelBuilder: (uid) =>
users.singleWhere((user) => user.id == uid).name,
leadingBuilder: (uid) {
final user = users.singleWhere((user) => user.id == uid);
return UserAvatar(photoUrl: user.photoUrl);
},
);
},
final selectedUsers =
context.select<InventoryViewFilterSelection, List<CustomUser>>(
(selection) => selection.selectedBorrowers);

return MultiselectButton<CustomUser>(
buttonLabel: 'Borrowers',
hasSelection: selectedUsers.isNotEmpty,
onConfirm: (values) => onChanged(context, values),
dialog: UserSelectionDialog(
selectedUsers: selectedUsers,
title: 'Pick Borrowers',
),
);
}
}
Loading
Loading