Add Swedish localization for various app actions and inventory management strings
This commit is contained in:
@@ -3,6 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
import '../../../core/api/api_error_mapper.dart';
|
||||
import '../../../core/l10n/l10n.dart';
|
||||
import '../../auth/data/auth_providers.dart';
|
||||
import '../data/inventory_providers.dart';
|
||||
|
||||
@@ -65,8 +66,8 @@ class _ConsumeInventoryScreenState
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: itemAsync.maybeWhen(
|
||||
data: (item) => Text('Konsumera: ${item.productName}'),
|
||||
orElse: () => const Text('Konsumera'),
|
||||
data: (item) => Text(context.l10n.inventoryConsumeNameTitle(item.productName)),
|
||||
orElse: () => Text(context.l10n.inventoryConsumeAction),
|
||||
),
|
||||
),
|
||||
body: Padding(
|
||||
@@ -78,7 +79,10 @@ class _ConsumeInventoryScreenState
|
||||
children: [
|
||||
if (itemAsync.hasValue) ...[
|
||||
Text(
|
||||
'Tillgängligt: ${itemAsync.value!.quantity} ${itemAsync.value!.unit}',
|
||||
context.l10n.inventoryAvailableLabel(
|
||||
itemAsync.value!.quantity.toString(),
|
||||
itemAsync.value!.unit,
|
||||
),
|
||||
style: Theme.of(context).textTheme.bodyMedium,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
@@ -86,7 +90,7 @@ class _ConsumeInventoryScreenState
|
||||
TextFormField(
|
||||
controller: _amountController,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'Mängd att konsumera *',
|
||||
labelText: context.l10n.inventoryConsumeAmountLabel,
|
||||
border: const OutlineInputBorder(),
|
||||
suffixText: itemAsync.maybeWhen(
|
||||
data: (item) => item.unit,
|
||||
@@ -98,11 +102,11 @@ class _ConsumeInventoryScreenState
|
||||
autofocus: true,
|
||||
enabled: !_saving,
|
||||
validator: (v) {
|
||||
if (v == null || v.trim().isEmpty) return 'Ange mängd';
|
||||
if (v == null || v.trim().isEmpty) return context.l10n.quantityHint;
|
||||
final parsed =
|
||||
double.tryParse(v.trim().replaceAll(',', '.'));
|
||||
if (parsed == null || parsed <= 0) {
|
||||
return 'Ange ett positivt tal';
|
||||
return context.l10n.enterPositiveNumber;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
@@ -110,9 +114,9 @@ class _ConsumeInventoryScreenState
|
||||
const SizedBox(height: 12),
|
||||
TextFormField(
|
||||
controller: _commentController,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Kommentar (valfri)',
|
||||
border: OutlineInputBorder(),
|
||||
decoration: InputDecoration(
|
||||
labelText: context.l10n.commentOptionalLabel,
|
||||
border: const OutlineInputBorder(),
|
||||
),
|
||||
enabled: !_saving,
|
||||
),
|
||||
@@ -126,7 +130,7 @@ class _ConsumeInventoryScreenState
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2, color: Colors.white),
|
||||
)
|
||||
: const Text('Konsumera'),
|
||||
: Text(context.l10n.inventoryConsumeAction),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
import '../../../core/api/api_error_mapper.dart';
|
||||
import '../../../core/l10n/l10n.dart';
|
||||
import '../../../core/ui/async_state_views.dart';
|
||||
import '../data/inventory_providers.dart';
|
||||
import '../domain/inventory_consumption.dart';
|
||||
@@ -19,20 +20,20 @@ class ConsumptionHistoryScreen extends ConsumerWidget {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: itemAsync.maybeWhen(
|
||||
data: (item) => Text('Historik: ${item.productName}'),
|
||||
orElse: () => const Text('Konsumtionshistorik'),
|
||||
data: (item) => Text(context.l10n.inventoryHistoryTitle(item.productName)),
|
||||
orElse: () => Text(context.l10n.inventoryHistoryAction),
|
||||
),
|
||||
),
|
||||
body: historyAsync.when(
|
||||
loading: () => const LoadingStateView(label: 'Laddar historik...'),
|
||||
loading: () => LoadingStateView(label: context.l10n.inventoryHistoryLoading),
|
||||
error: (e, _) => ErrorStateView(
|
||||
message: mapErrorToUserMessage(e, context),
|
||||
onRetry: () => ref.invalidate(consumptionHistoryProvider(itemId)),
|
||||
),
|
||||
data: (history) {
|
||||
if (history.isEmpty) {
|
||||
return const EmptyStateView(
|
||||
title: 'Ingen konsumtionshistorik finns.',
|
||||
return EmptyStateView(
|
||||
title: context.l10n.inventoryHistoryEmpty,
|
||||
);
|
||||
}
|
||||
return ListView.separated(
|
||||
|
||||
@@ -6,6 +6,7 @@ import '../../../core/api/api_error_mapper.dart';
|
||||
import '../../../core/api/api_paths.dart';
|
||||
import '../../../core/api/api_providers.dart';
|
||||
import '../../../core/forms/form_options.dart';
|
||||
import '../../../core/l10n/l10n.dart';
|
||||
import '../../../core/ui/product_picker_field.dart';
|
||||
import '../../auth/data/auth_providers.dart';
|
||||
import '../data/inventory_providers.dart';
|
||||
@@ -102,7 +103,7 @@ class _CreateInventoryScreenState
|
||||
if (!_formKey.currentState!.validate()) return;
|
||||
if (_selectedProductId == null) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('Välj en produkt ur listan.')),
|
||||
SnackBar(content: Text(context.l10n.inventorySelectProduct)),
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -142,7 +143,7 @@ class _CreateInventoryScreenState
|
||||
}
|
||||
|
||||
String _formatDate(DateTime? dt) {
|
||||
if (dt == null) return 'Välj datum';
|
||||
if (dt == null) return context.l10n.selectDateLabel;
|
||||
return '${dt.year}-${dt.month.toString().padLeft(2, '0')}-${dt.day.toString().padLeft(2, '0')}';
|
||||
}
|
||||
|
||||
@@ -165,7 +166,7 @@ class _CreateInventoryScreenState
|
||||
.toList();
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: const Text('Lägg till inventariepost')),
|
||||
appBar: AppBar(title: Text(context.l10n.inventoryCreateTitle)),
|
||||
body: Form(
|
||||
key: _formKey,
|
||||
child: ListView(
|
||||
@@ -176,7 +177,7 @@ class _CreateInventoryScreenState
|
||||
value: _selectedProductId,
|
||||
isLoading: _loadingProducts,
|
||||
enabled: !_saving,
|
||||
label: 'Produkt *',
|
||||
label: context.l10n.inventoryProductLabel,
|
||||
onChanged: (value) => setState(() => _selectedProductId = value),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
@@ -187,18 +188,18 @@ class _CreateInventoryScreenState
|
||||
flex: 2,
|
||||
child: TextFormField(
|
||||
controller: _quantityController,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Mängd *',
|
||||
border: OutlineInputBorder(),
|
||||
decoration: InputDecoration(
|
||||
labelText: context.l10n.quantityLabel,
|
||||
border: const OutlineInputBorder(),
|
||||
),
|
||||
keyboardType: const TextInputType.numberWithOptions(
|
||||
decimal: true),
|
||||
enabled: !_saving,
|
||||
validator: (v) {
|
||||
if (v == null || v.trim().isEmpty) return 'Ange mängd';
|
||||
if (v == null || v.trim().isEmpty) return context.l10n.quantityHint;
|
||||
if (double.tryParse(v.trim().replaceAll(',', '.')) ==
|
||||
null) {
|
||||
return 'Ogiltigt tal';
|
||||
return context.l10n.invalidNumber;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
@@ -211,9 +212,9 @@ class _CreateInventoryScreenState
|
||||
? null
|
||||
: _unitController.text.trim(),
|
||||
isExpanded: true,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Enhet *',
|
||||
border: OutlineInputBorder(),
|
||||
decoration: InputDecoration(
|
||||
labelText: context.l10n.unitLabel,
|
||||
border: const OutlineInputBorder(),
|
||||
),
|
||||
items: unitOptions
|
||||
.map(
|
||||
@@ -228,7 +229,7 @@ class _CreateInventoryScreenState
|
||||
: (value) =>
|
||||
setState(() => _unitController.text = value ?? ''),
|
||||
validator: (value) =>
|
||||
(value == null || value.trim().isEmpty) ? 'Ange enhet' : null,
|
||||
(value == null || value.trim().isEmpty) ? context.l10n.quantityHint : null,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -239,9 +240,9 @@ class _CreateInventoryScreenState
|
||||
? null
|
||||
: _locationController.text.trim(),
|
||||
isExpanded: true,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Plats (valfri)',
|
||||
border: OutlineInputBorder(),
|
||||
decoration: InputDecoration(
|
||||
labelText: context.l10n.locationOptionalLabel,
|
||||
border: const OutlineInputBorder(),
|
||||
),
|
||||
items: inventoryLocationOptions
|
||||
.map(
|
||||
@@ -260,9 +261,9 @@ class _CreateInventoryScreenState
|
||||
const SizedBox(height: 12),
|
||||
TextFormField(
|
||||
controller: _brandController,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Märke (valfritt)',
|
||||
border: OutlineInputBorder(),
|
||||
decoration: InputDecoration(
|
||||
labelText: context.l10n.brandOptionalLabel,
|
||||
border: const OutlineInputBorder(),
|
||||
),
|
||||
enabled: !_saving,
|
||||
),
|
||||
@@ -274,7 +275,7 @@ class _CreateInventoryScreenState
|
||||
onPressed: _saving ? null : () => _pickDate(false),
|
||||
icon: const Icon(Icons.calendar_today, size: 16),
|
||||
label: Text(
|
||||
'Inköp: ${_formatDate(_purchaseDate)}',
|
||||
'${context.l10n.inventoryPurchaseDatePrefix}${_formatDate(_purchaseDate)}',
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
@@ -285,7 +286,7 @@ class _CreateInventoryScreenState
|
||||
onPressed: _saving ? null : () => _pickDate(true),
|
||||
icon: const Icon(Icons.event_available, size: 16),
|
||||
label: Text(
|
||||
'Bäst före: ${_formatDate(_bestBeforeDate)}',
|
||||
'${context.l10n.inventoryBestBeforeDatePrefix}${_formatDate(_bestBeforeDate)}',
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
@@ -293,7 +294,7 @@ class _CreateInventoryScreenState
|
||||
],
|
||||
),
|
||||
CheckboxListTile(
|
||||
title: const Text('Öppnad'),
|
||||
title: Text(context.l10n.openedLabel),
|
||||
value: _opened,
|
||||
onChanged:
|
||||
_saving ? null : (v) => setState(() => _opened = v ?? false),
|
||||
@@ -302,9 +303,9 @@ class _CreateInventoryScreenState
|
||||
),
|
||||
TextFormField(
|
||||
controller: _commentController,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Kommentar (valfri)',
|
||||
border: OutlineInputBorder(),
|
||||
decoration: InputDecoration(
|
||||
labelText: context.l10n.commentOptionalLabel,
|
||||
border: const OutlineInputBorder(),
|
||||
),
|
||||
maxLines: 2,
|
||||
enabled: !_saving,
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
import '../../../core/api/api_error_mapper.dart';
|
||||
import '../../../core/l10n/l10n.dart';
|
||||
import '../../../core/ui/async_state_views.dart';
|
||||
import '../../auth/data/auth_providers.dart';
|
||||
import '../data/inventory_providers.dart';
|
||||
@@ -20,12 +21,12 @@ class InventoryDetailScreen extends ConsumerWidget {
|
||||
appBar: AppBar(
|
||||
title: itemAsync.maybeWhen(
|
||||
data: (item) => Text(item.productName),
|
||||
orElse: () => const Text('Inventarie'),
|
||||
orElse: () => Text(context.l10n.inventoryTitle),
|
||||
),
|
||||
actions: [
|
||||
if (itemAsync.hasValue) ...[
|
||||
IconButton(
|
||||
tooltip: 'Redigera',
|
||||
tooltip: context.l10n.editTooltip,
|
||||
icon: const Icon(Icons.edit_outlined),
|
||||
onPressed: () => context.push('/inventory/$itemId/edit'),
|
||||
),
|
||||
@@ -34,7 +35,7 @@ class InventoryDetailScreen extends ConsumerWidget {
|
||||
],
|
||||
),
|
||||
body: itemAsync.when(
|
||||
loading: () => const LoadingStateView(label: 'Laddar...'),
|
||||
loading: () => LoadingStateView(label: context.l10n.loadingLabel),
|
||||
error: (e, _) => ErrorStateView(
|
||||
message: mapErrorToUserMessage(e, context),
|
||||
onRetry: () => ref.invalidate(inventoryDetailProvider(itemId)),
|
||||
@@ -42,33 +43,33 @@ class InventoryDetailScreen extends ConsumerWidget {
|
||||
data: (item) => ListView(
|
||||
padding: const EdgeInsets.all(16),
|
||||
children: [
|
||||
_InfoRow(label: 'Produkt', value: item.productName),
|
||||
_InfoRow(label: context.l10n.inventoryProductLabel, value: item.productName),
|
||||
_InfoRow(
|
||||
label: 'Mängd',
|
||||
label: context.l10n.inventoryQuantityDisplayLabel,
|
||||
value: '${item.quantity} ${item.unit}',
|
||||
),
|
||||
if (item.location != null && item.location!.isNotEmpty)
|
||||
_InfoRow(label: 'Plats', value: item.location!),
|
||||
_InfoRow(label: context.l10n.inventoryLocationDisplayLabel, value: item.location!),
|
||||
if (item.brand != null && item.brand!.isNotEmpty)
|
||||
_InfoRow(label: 'Märke', value: item.brand!),
|
||||
_InfoRow(label: context.l10n.inventoryBrandDisplayLabel, value: item.brand!),
|
||||
if (item.purchaseDate != null)
|
||||
_InfoRow(label: 'Inköpsdatum', value: _formatDate(item.purchaseDate!)),
|
||||
_InfoRow(label: context.l10n.inventoryPurchaseDateLabel, value: _formatDate(item.purchaseDate!)),
|
||||
if (item.bestBeforeDate != null)
|
||||
_InfoRow(label: 'Bäst före', value: _formatDate(item.bestBeforeDate!)),
|
||||
_InfoRow(label: 'Öppnad', value: item.opened ? 'Ja' : 'Nej'),
|
||||
_InfoRow(label: context.l10n.inventoryBestBeforeLabel, value: _formatDate(item.bestBeforeDate!)),
|
||||
_InfoRow(label: context.l10n.openedLabel, value: item.opened ? context.l10n.yesLabel : context.l10n.noLabel),
|
||||
if (item.comment != null && item.comment!.isNotEmpty)
|
||||
_InfoRow(label: 'Kommentar', value: item.comment!),
|
||||
_InfoRow(label: context.l10n.commentLabel, value: item.comment!),
|
||||
const SizedBox(height: 24),
|
||||
OutlinedButton.icon(
|
||||
onPressed: () => context.push('/inventory/$itemId/consume'),
|
||||
icon: const Icon(Icons.remove_circle_outline),
|
||||
label: const Text('Konsumera'),
|
||||
label: Text(context.l10n.inventoryConsumeAction),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
TextButton.icon(
|
||||
onPressed: () => context.push('/inventory/$itemId/history'),
|
||||
icon: const Icon(Icons.history),
|
||||
label: const Text('Konsumtionshistorik'),
|
||||
label: Text(context.l10n.inventoryHistoryAction),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -94,22 +95,22 @@ class _DeleteButton extends ConsumerWidget {
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
return IconButton(
|
||||
tooltip: 'Ta bort',
|
||||
tooltip: context.l10n.deleteTooltip,
|
||||
icon: const Icon(Icons.delete_outline),
|
||||
onPressed: () async {
|
||||
final confirmed = await showDialog<bool>(
|
||||
context: context,
|
||||
builder: (ctx) => AlertDialog(
|
||||
title: const Text('Ta bort inventariepost?'),
|
||||
content: const Text('Åtgärden kan inte ångras.'),
|
||||
title: Text(context.l10n.inventoryDeleteTitle),
|
||||
content: Text(context.l10n.cannotBeUndone),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(ctx, false),
|
||||
child: const Text('Avbryt'),
|
||||
child: Text(context.l10n.cancelAction),
|
||||
),
|
||||
FilledButton(
|
||||
onPressed: () => Navigator.pop(ctx, true),
|
||||
child: const Text('Ta bort'),
|
||||
child: Text(context.l10n.deleteAction),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -4,6 +4,7 @@ import 'package:go_router/go_router.dart';
|
||||
|
||||
import '../../../core/api/api_error_mapper.dart';
|
||||
import '../../../core/forms/form_options.dart';
|
||||
import '../../../core/l10n/l10n.dart';
|
||||
import '../../../core/ui/async_state_views.dart';
|
||||
import '../../auth/data/auth_providers.dart';
|
||||
import '../data/inventory_providers.dart';
|
||||
@@ -117,7 +118,7 @@ class _InventoryEditScreenState extends ConsumerState<InventoryEditScreen> {
|
||||
}
|
||||
|
||||
String _formatDate(DateTime? dt) {
|
||||
if (dt == null) return 'Välj datum';
|
||||
if (dt == null) return context.l10n.selectDateLabel;
|
||||
return '${dt.year}-${dt.month.toString().padLeft(2, '0')}-${dt.day.toString().padLeft(2, '0')}';
|
||||
}
|
||||
|
||||
@@ -126,9 +127,9 @@ class _InventoryEditScreenState extends ConsumerState<InventoryEditScreen> {
|
||||
final itemAsync = ref.watch(inventoryDetailProvider(widget.itemId));
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: const Text('Redigera inventariepost')),
|
||||
appBar: AppBar(title: Text(context.l10n.inventoryEditTitle)),
|
||||
body: itemAsync.when(
|
||||
loading: () => const LoadingStateView(label: 'Laddar...'),
|
||||
loading: () => LoadingStateView(label: context.l10n.loadingLabel),
|
||||
error: (e, _) => ErrorStateView(
|
||||
message: mapErrorToUserMessage(e, context),
|
||||
onRetry: () => ref.invalidate(inventoryDetailProvider(widget.itemId)),
|
||||
@@ -179,9 +180,9 @@ class _InventoryEditScreenState extends ConsumerState<InventoryEditScreen> {
|
||||
? null
|
||||
: _unitController.text.trim(),
|
||||
isExpanded: true,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Enhet *',
|
||||
border: OutlineInputBorder(),
|
||||
decoration: InputDecoration(
|
||||
labelText: context.l10n.unitLabel,
|
||||
border: const OutlineInputBorder(),
|
||||
),
|
||||
items: unitOptions
|
||||
.map(
|
||||
@@ -196,7 +197,7 @@ class _InventoryEditScreenState extends ConsumerState<InventoryEditScreen> {
|
||||
: (value) =>
|
||||
setState(() => _unitController.text = value ?? ''),
|
||||
validator: (v) => (v == null || v.trim().isEmpty)
|
||||
? 'Ange enhet'
|
||||
? context.l10n.quantityHint
|
||||
: null,
|
||||
),
|
||||
),
|
||||
@@ -208,9 +209,9 @@ class _InventoryEditScreenState extends ConsumerState<InventoryEditScreen> {
|
||||
? null
|
||||
: _locationController.text.trim(),
|
||||
isExpanded: true,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Plats',
|
||||
border: OutlineInputBorder(),
|
||||
decoration: InputDecoration(
|
||||
labelText: context.l10n.locationLabel,
|
||||
border: const OutlineInputBorder(),
|
||||
),
|
||||
items: inventoryLocationOptions
|
||||
.map(
|
||||
@@ -228,12 +229,12 @@ class _InventoryEditScreenState extends ConsumerState<InventoryEditScreen> {
|
||||
const SizedBox(height: 12),
|
||||
TextFormField(
|
||||
controller: _brandController,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Märke',
|
||||
border: OutlineInputBorder(),
|
||||
),
|
||||
enabled: !_saving,
|
||||
decoration: InputDecoration(
|
||||
labelText: context.l10n.brandLabel,
|
||||
border: const OutlineInputBorder(),
|
||||
),
|
||||
enabled: !_saving,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Row(
|
||||
children: [
|
||||
@@ -242,7 +243,7 @@ class _InventoryEditScreenState extends ConsumerState<InventoryEditScreen> {
|
||||
onPressed: _saving ? null : () => _pickDate(false),
|
||||
icon: const Icon(Icons.calendar_today, size: 16),
|
||||
label: Text(
|
||||
'Inköp: ${_formatDate(_purchaseDate)}',
|
||||
'${context.l10n.inventoryPurchaseDatePrefix}${_formatDate(_purchaseDate)}',
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
@@ -253,7 +254,7 @@ class _InventoryEditScreenState extends ConsumerState<InventoryEditScreen> {
|
||||
onPressed: _saving ? null : () => _pickDate(true),
|
||||
icon: const Icon(Icons.event_available, size: 16),
|
||||
label: Text(
|
||||
'Bäst före: ${_formatDate(_bestBeforeDate)}',
|
||||
'${context.l10n.inventoryBestBeforeDatePrefix}${_formatDate(_bestBeforeDate)}',
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
@@ -261,7 +262,7 @@ class _InventoryEditScreenState extends ConsumerState<InventoryEditScreen> {
|
||||
],
|
||||
),
|
||||
CheckboxListTile(
|
||||
title: const Text('Öppnad'),
|
||||
title: Text(context.l10n.openedLabel),
|
||||
value: _opened,
|
||||
onChanged: _saving
|
||||
? null
|
||||
@@ -271,9 +272,9 @@ class _InventoryEditScreenState extends ConsumerState<InventoryEditScreen> {
|
||||
),
|
||||
TextFormField(
|
||||
controller: _commentController,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Kommentar',
|
||||
border: OutlineInputBorder(),
|
||||
decoration: InputDecoration(
|
||||
labelText: context.l10n.commentLabel,
|
||||
border: const OutlineInputBorder(),
|
||||
),
|
||||
maxLines: 2,
|
||||
enabled: !_saving,
|
||||
@@ -288,7 +289,7 @@ class _InventoryEditScreenState extends ConsumerState<InventoryEditScreen> {
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2, color: Colors.white),
|
||||
)
|
||||
: const Text('Spara'),
|
||||
: Text(context.l10n.saveAction),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
import '../../../core/api/api_error_mapper.dart';
|
||||
import '../../../core/l10n/l10n.dart';
|
||||
import '../../../core/ui/async_state_views.dart';
|
||||
import '../data/inventory_providers.dart';
|
||||
import 'swipeable_inventory_tile.dart';
|
||||
@@ -11,11 +12,11 @@ class InventoryScreen extends ConsumerWidget {
|
||||
const InventoryScreen({super.key});
|
||||
|
||||
static const _locationOptions = <String>['', 'Kyl', 'Frys', 'Skafferi'];
|
||||
static const _sortOptions = <({String value, String label})>[
|
||||
(value: '', label: 'Senast tillagda'),
|
||||
(value: 'nameAsc', label: 'Namn A-Ö'),
|
||||
(value: 'bestBeforeAsc', label: 'Bäst före stigande'),
|
||||
(value: 'bestBeforeDesc', label: 'Bäst före fallande'),
|
||||
List<({String value, String label})> _sortOptions(BuildContext context) => [
|
||||
(value: '', label: context.l10n.inventorySortLatest),
|
||||
(value: 'nameAsc', label: context.l10n.inventorySortNameAsc),
|
||||
(value: 'bestBeforeAsc', label: context.l10n.inventorySortBestBeforeAsc),
|
||||
(value: 'bestBeforeDesc', label: context.l10n.inventorySortBestBeforeDesc),
|
||||
];
|
||||
|
||||
@override
|
||||
@@ -25,7 +26,7 @@ class InventoryScreen extends ConsumerWidget {
|
||||
final inventoryAsync = ref.watch(inventoryProvider);
|
||||
|
||||
return inventoryAsync.when(
|
||||
loading: () => const LoadingStateView(label: 'Laddar inventarie...'),
|
||||
loading: () => LoadingStateView(label: context.l10n.inventoryLoading),
|
||||
error: (e, _) => ErrorStateView(
|
||||
message: mapErrorToUserMessage(e, context),
|
||||
onRetry: () => ref.invalidate(inventoryProvider),
|
||||
@@ -36,9 +37,9 @@ class InventoryScreen extends ConsumerWidget {
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
'Filter och sortering',
|
||||
style: TextStyle(fontWeight: FontWeight.w600),
|
||||
Text(
|
||||
context.l10n.inventoryFilterAndSort,
|
||||
style: const TextStyle(fontWeight: FontWeight.w600),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Wrap(
|
||||
@@ -47,7 +48,7 @@ class InventoryScreen extends ConsumerWidget {
|
||||
children: _locationOptions
|
||||
.map(
|
||||
(option) => ChoiceChip(
|
||||
label: Text(option.isEmpty ? 'Alla' : option),
|
||||
label: Text(option.isEmpty ? context.l10n.inventoryAllFilter : option),
|
||||
selected: location == option,
|
||||
onSelected: (_) => ref
|
||||
.read(inventoryLocationFilterProvider.notifier)
|
||||
@@ -60,11 +61,11 @@ class InventoryScreen extends ConsumerWidget {
|
||||
DropdownButtonFormField<String>(
|
||||
initialValue: sort,
|
||||
isExpanded: true,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Sortering',
|
||||
border: OutlineInputBorder(),
|
||||
decoration: InputDecoration(
|
||||
labelText: context.l10n.inventorySortLabel,
|
||||
border: const OutlineInputBorder(),
|
||||
),
|
||||
items: _sortOptions
|
||||
items: _sortOptions(context)
|
||||
.map(
|
||||
(option) => DropdownMenuItem<String>(
|
||||
value: option.value,
|
||||
@@ -89,7 +90,7 @@ class InventoryScreen extends ConsumerWidget {
|
||||
padding: const EdgeInsets.only(bottom: 88),
|
||||
children: [
|
||||
filterSection,
|
||||
const EmptyStateView(title: 'Inventariet är tomt.'),
|
||||
EmptyStateView(title: context.l10n.inventoryEmpty),
|
||||
],
|
||||
),
|
||||
Positioned(
|
||||
@@ -98,7 +99,7 @@ class InventoryScreen extends ConsumerWidget {
|
||||
child: FloatingActionButton.extended(
|
||||
onPressed: () => context.push('/inventory/create'),
|
||||
icon: const Icon(Icons.add),
|
||||
label: const Text('Lägg till'),
|
||||
label: Text(context.l10n.addAction),
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -125,13 +126,13 @@ class InventoryScreen extends ConsumerWidget {
|
||||
FloatingActionButton.extended(
|
||||
onPressed: () => context.push('/inventory/create'),
|
||||
icon: const Icon(Icons.add),
|
||||
label: const Text('Lägg till'),
|
||||
label: Text(context.l10n.addAction),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
FloatingActionButton.extended(
|
||||
onPressed: () => context.go('/recipes'),
|
||||
icon: const Icon(Icons.restaurant_menu),
|
||||
label: const Text('Recept'),
|
||||
label: Text(context.l10n.inventoryRecipesAction),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user