diff --git a/flutter/lib/core/ui/product_picker_field.dart b/flutter/lib/core/ui/product_picker_field.dart index 47a20b67..41cc50f6 100644 --- a/flutter/lib/core/ui/product_picker_field.dart +++ b/flutter/lib/core/ui/product_picker_field.dart @@ -1,5 +1,8 @@ import 'package:flutter/material.dart'; +/// Typ för att hantera förändringar av värden. +typedef ValueChanged = void Function(T value); + /// A named record representing a selectable product option. typedef ProductOption = ({int id, String name}); @@ -51,197 +54,33 @@ class ProductPickerField extends StatelessWidget { final interactive = enabled && !isLoading; return MouseRegion( - cursor: interactive ? SystemMouseCursors.click : SystemMouseCursors.basic, + cursor: interactive ? SystemMouseCursors.click : MouseCursor.defer, child: GestureDetector( onTap: interactive ? () => _openPicker(context) : null, child: InputDecorator( - isEmpty: value == null, decoration: InputDecoration( labelText: label, - border: const OutlineInputBorder(), errorText: errorText, - enabled: interactive, - suffixIcon: isLoading - ? const Padding( - padding: EdgeInsets.all(12), - child: SizedBox( - width: 20, - height: 20, - child: CircularProgressIndicator(strokeWidth: 2), - ), - ) - : const Icon(Icons.search), + border: const OutlineInputBorder(), ), - child: value == null - ? null - : Text( - selected?.name ?? '', - overflow: TextOverflow.ellipsis, - ), + child: isLoading + ? const Padding( + padding: EdgeInsets.all(12), + child: SizedBox( + width: 20, + height: 20, + child: CircularProgressIndicator(strokeWidth: 2), + ), + ) + : selected == null + ? const Icon(Icons.search) + : Text(selected.name), ), ), ); } Future _openPicker(BuildContext context) async { - final result = await showModalBottomSheet( - context: context, - isScrollControlled: true, - useSafeArea: true, - builder: (_) => _ProductPickerSheet( - products: products, - selectedId: value, - ), - ); - if (result != null) { - onChanged?.call(result.id); - } - } -} - -// --------------------------------------------------------------------------- - -class _ProductPickerSheet extends StatefulWidget { - final List products; - final int? selectedId; - - const _ProductPickerSheet({ - required this.products, - this.selectedId, - }); - - @override - State<_ProductPickerSheet> createState() => _ProductPickerSheetState(); -} - -class _ProductPickerSheetState extends State<_ProductPickerSheet> { - final _searchController = TextEditingController(); - late List _filtered; - - @override - void initState() { - super.initState(); - _filtered = widget.products; - _searchController.addListener(_onSearch); - } - - @override - void dispose() { - _searchController.dispose(); - super.dispose(); - } - - void _onSearch() { - final query = _searchController.text.trim().toLowerCase(); - setState(() { - _filtered = query.isEmpty - ? widget.products - : widget.products - .where((p) => p.name.toLowerCase().contains(query)) - .toList(); - }); - } - - @override - Widget build(BuildContext context) { - final theme = Theme.of(context); - - return DraggableScrollableSheet( - expand: false, - initialChildSize: 0.6, - minChildSize: 0.35, - maxChildSize: 0.92, - builder: (context, scrollController) { - return Column( - children: [ - // Drag handle - const SizedBox(height: 8), - Container( - width: 36, - height: 4, - decoration: BoxDecoration( - color: theme.colorScheme.outlineVariant, - borderRadius: BorderRadius.circular(2), - ), - ), - const SizedBox(height: 12), - - // Search field - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16), - child: TextField( - controller: _searchController, - autofocus: true, - textInputAction: TextInputAction.search, - decoration: InputDecoration( - hintText: 'Sök produkt...', - prefixIcon: const Icon(Icons.search), - border: const OutlineInputBorder(), - suffixIcon: ListenableBuilder( - listenable: _searchController, - builder: (_, __) => _searchController.text.isNotEmpty - ? IconButton( - icon: const Icon(Icons.clear), - tooltip: 'Rensa sökning', - onPressed: _searchController.clear, - ) - : const SizedBox.shrink(), - ), - ), - ), - ), - const SizedBox(height: 4), - - // Result count - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4), - child: Align( - alignment: Alignment.centerLeft, - child: Text( - '${_filtered.length} ${_filtered.length == 1 ? 'produkt' : 'produkter'}', - style: theme.textTheme.bodySmall, - ), - ), - ), - - const Divider(height: 1), - - // Product list - Expanded( - child: _filtered.isEmpty - ? Center( - child: Padding( - padding: const EdgeInsets.all(24), - child: Text( - 'Inga produkter matchade\n"${_searchController.text}"', - textAlign: TextAlign.center, - style: theme.textTheme.bodyMedium, - ), - ), - ) - : ListView.builder( - controller: scrollController, - itemCount: _filtered.length, - itemBuilder: (context, index) { - final product = _filtered[index]; - final isSelected = product.id == widget.selectedId; - return ListTile( - title: Text(product.name), - selected: isSelected, - trailing: isSelected - ? Icon( - Icons.check, - color: theme.colorScheme.primary, - ) - : null, - onTap: () => Navigator.pop(context, product), - ); - }, - ), - ), - ], - ); - }, - ); + // Implementera logik för att öppna en bottom sheet för produktval } } diff --git a/flutter/lib/features/inventory/presentation/swipeable_inventory_tile.dart b/flutter/lib/features/inventory/presentation/swipeable_inventory_tile.dart index 7e68433f..ab15f105 100644 --- a/flutter/lib/features/inventory/presentation/swipeable_inventory_tile.dart +++ b/flutter/lib/features/inventory/presentation/swipeable_inventory_tile.dart @@ -309,7 +309,8 @@ class _TrailingActions extends ConsumerWidget { const _TrailingActions({required this.item}); @override - Widget build(BuildContext context, WidgetRef ref) { + Widget build(BuildContext context) { + final ref = ref; return Row( mainAxisSize: MainAxisSize.min, children: [ @@ -348,7 +349,7 @@ class _DeleteButton extends ConsumerWidget { const _DeleteButton({required this.item}); @override - Widget build(BuildContext context, WidgetRef ref) { + Widget build(BuildContext context) { return Tooltip( message: 'Ta bort', child: IconButton( @@ -371,18 +372,14 @@ class _DeleteButton extends ConsumerWidget { ], ), ); - if (confirmed != true) return; - try { - final token = await ref.read(authStateProvider.future); - await ref - .read(inventoryRepositoryProvider) - .deleteInventoryItem(item.id, token: token); - ref.invalidate(inventoryProvider); - } catch (e) { - if (!context.mounted) return; - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text(mapErrorToUserMessage(e, context))), - ); + if (confirmed == true) { + try { + await ref.read(inventoryRepositoryProvider).deleteItem(item.id); + } catch (e) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text(mapErrorToUserMessage(e, context))), + ); + } } }, ),