fixes before build 2
This commit is contained in:
@@ -1,8 +1,6 @@
|
|||||||
# Receipity
|
# Groci
|
||||||
|
|
||||||
Single-screen Flutter app that proves **capture → OCR**: take a photo of a shopping receipt (or pick one from the gallery), run Google ML Kit Text Recognition, and show the raw extracted text.
|
Flutter app for scanning shopping receipts, tracking products and prices, shopping lists, and bonus cards.
|
||||||
|
|
||||||
No database, no saving, no other screens.
|
|
||||||
|
|
||||||
## Run
|
## Run
|
||||||
|
|
||||||
@@ -11,4 +9,4 @@ flutter pub get
|
|||||||
flutter run
|
flutter run
|
||||||
```
|
```
|
||||||
|
|
||||||
Use a physical Android device or emulator with Google Play. ML Kit text recognition is on-device and does not require a network call.
|
Use a physical Android device or emulator with Google Play for receipt OCR.
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<uses-permission android:name="android.permission.CAMERA"/>
|
<uses-permission android:name="android.permission.CAMERA"/>
|
||||||
<uses-feature android:name="android.hardware.camera" android:required="false"/>
|
<uses-feature android:name="android.hardware.camera" android:required="false"/>
|
||||||
<application
|
<application
|
||||||
android:label="Receipity"
|
android:label="Groci"
|
||||||
android:name="${applicationName}"
|
android:name="${applicationName}"
|
||||||
android:icon="@mipmap/ic_launcher">
|
android:icon="@mipmap/ic_launcher">
|
||||||
<activity
|
<activity
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Receipt parsing (implementation)
|
# Receipt parsing (implementation)
|
||||||
|
|
||||||
This is the working guide for Receipity's receipt parser. Use it when a new
|
This is the working guide for Groci's receipt parser. Use it when a new
|
||||||
shop's receipt does not parse well.
|
shop's receipt does not parse well.
|
||||||
|
|
||||||
The original design notes live in [`receipt-parsing-spec.md`](../receipt-parsing-spec.md).
|
The original design notes live in [`receipt-parsing-spec.md`](../receipt-parsing-spec.md).
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ class _CropReceiptScreenState extends State<CropReceiptScreen> {
|
|||||||
Future<void> _saveAndPop(Uint8List bytes) async {
|
Future<void> _saveAndPop(Uint8List bytes) async {
|
||||||
try {
|
try {
|
||||||
final file = File(
|
final file = File(
|
||||||
'${Directory.systemTemp.path}/receipity_crop_${DateTime.now().millisecondsSinceEpoch}.jpg',
|
'${Directory.systemTemp.path}/groci_crop_${DateTime.now().millisecondsSinceEpoch}.jpg',
|
||||||
);
|
);
|
||||||
await file.writeAsBytes(bytes, flush: true);
|
await file.writeAsBytes(bytes, flush: true);
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
|
|||||||
+5
-5
@@ -13,20 +13,20 @@ import 'utils/constants.dart';
|
|||||||
Future<void> main() async {
|
Future<void> main() async {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
await ReceiptParser.loadConfig();
|
await ReceiptParser.loadConfig();
|
||||||
runApp(ReceipityApp());
|
runApp(GrociApp());
|
||||||
}
|
}
|
||||||
|
|
||||||
class ReceipityApp extends StatefulWidget {
|
class GrociApp extends StatefulWidget {
|
||||||
ReceipityApp({super.key, ProductRepository? repository})
|
GrociApp({super.key, ProductRepository? repository})
|
||||||
: repository = repository ?? ProductRepository();
|
: repository = repository ?? ProductRepository();
|
||||||
|
|
||||||
final ProductRepository repository;
|
final ProductRepository repository;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<ReceipityApp> createState() => _ReceipityAppState();
|
State<GrociApp> createState() => _GrociAppState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ReceipityAppState extends State<ReceipityApp> {
|
class _GrociAppState extends State<GrociApp> {
|
||||||
late final AppSettings _settings;
|
late final AppSettings _settings;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ class _ScanScreenState extends State<ScanScreen> {
|
|||||||
try {
|
try {
|
||||||
final data = await rootBundle.load(kSampleReceiptAsset);
|
final data = await rootBundle.load(kSampleReceiptAsset);
|
||||||
final file = File(
|
final file = File(
|
||||||
'${Directory.systemTemp.path}/receipity_sample_receipt.jpeg',
|
'${Directory.systemTemp.path}/groci_sample_receipt.jpeg',
|
||||||
);
|
);
|
||||||
await file.writeAsBytes(data.buffer.asUint8List(), flush: true);
|
await file.writeAsBytes(data.buffer.asUint8List(), flush: true);
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ import 'dart:convert';
|
|||||||
|
|
||||||
const int kBackupVersion = 3;
|
const int kBackupVersion = 3;
|
||||||
|
|
||||||
|
const String kBackupFormat = 'groci-backup';
|
||||||
|
const String kLegacyBackupFormat = 'receipity-backup';
|
||||||
|
|
||||||
class BackupDocument {
|
class BackupDocument {
|
||||||
const BackupDocument({
|
const BackupDocument({
|
||||||
required this.version,
|
required this.version,
|
||||||
@@ -33,7 +36,7 @@ class BackupDocument {
|
|||||||
final Map<String, String> images;
|
final Map<String, String> images;
|
||||||
|
|
||||||
Map<String, Object?> toJson() => {
|
Map<String, Object?> toJson() => {
|
||||||
'format': 'receipity-backup',
|
'format': kBackupFormat,
|
||||||
'version': version,
|
'version': version,
|
||||||
'exportedAt': exportedAt,
|
'exportedAt': exportedAt,
|
||||||
'darkMode': darkMode,
|
'darkMode': darkMode,
|
||||||
@@ -54,8 +57,9 @@ class BackupDocument {
|
|||||||
if (decoded is! Map<String, dynamic>) {
|
if (decoded is! Map<String, dynamic>) {
|
||||||
throw const FormatException('Backup is not a JSON object.');
|
throw const FormatException('Backup is not a JSON object.');
|
||||||
}
|
}
|
||||||
if (decoded['format'] != 'receipity-backup') {
|
final format = decoded['format'];
|
||||||
throw const FormatException('This file is not a Receipity backup.');
|
if (format != kBackupFormat && format != kLegacyBackupFormat) {
|
||||||
|
throw const FormatException('This file is not a Groci backup.');
|
||||||
}
|
}
|
||||||
final version = decoded['version'];
|
final version = decoded['version'];
|
||||||
if (version is! int || version < 1 || version > kBackupVersion) {
|
if (version is! int || version < 1 || version > kBackupVersion) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/// Build, share, and restore a Receipity JSON backup.
|
/// Build, share, and restore a Groci JSON backup.
|
||||||
library;
|
library;
|
||||||
|
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
@@ -68,11 +68,11 @@ class BackupService {
|
|||||||
final document = await buildBackup();
|
final document = await buildBackup();
|
||||||
final bytes = Uint8List.fromList(utf8.encode(document.encode()));
|
final bytes = Uint8List.fromList(utf8.encode(document.encode()));
|
||||||
final stamp = DateTime.now().toIso8601String().split('T').first;
|
final stamp = DateTime.now().toIso8601String().split('T').first;
|
||||||
final fileName = 'receipity-backup-$stamp.json';
|
final fileName = 'groci-backup-$stamp.json';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final saved = await FilePicker.saveFile(
|
final saved = await FilePicker.saveFile(
|
||||||
dialogTitle: 'Save Receipity backup',
|
dialogTitle: 'Save Groci backup',
|
||||||
fileName: fileName,
|
fileName: fileName,
|
||||||
bytes: bytes,
|
bytes: bytes,
|
||||||
mimeType: 'application/json',
|
mimeType: 'application/json',
|
||||||
@@ -90,8 +90,8 @@ class BackupService {
|
|||||||
final result = await SharePlus.instance.share(
|
final result = await SharePlus.instance.share(
|
||||||
ShareParams(
|
ShareParams(
|
||||||
files: [XFile(file.path, mimeType: 'application/json')],
|
files: [XFile(file.path, mimeType: 'application/json')],
|
||||||
subject: 'Receipity backup',
|
subject: 'Groci backup',
|
||||||
text: 'Receipity backup $stamp',
|
text: 'Groci backup $stamp',
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
return result.status != ShareResultStatus.dismissed;
|
return result.status != ShareResultStatus.dismissed;
|
||||||
@@ -99,7 +99,7 @@ class BackupService {
|
|||||||
|
|
||||||
Future<bool> importBackup() async {
|
Future<bool> importBackup() async {
|
||||||
final picked = await FilePicker.pickFile(
|
final picked = await FilePicker.pickFile(
|
||||||
dialogTitle: 'Import Receipity backup',
|
dialogTitle: 'Import Groci backup',
|
||||||
type: FileType.custom,
|
type: FileType.custom,
|
||||||
allowedExtensions: const ['json'],
|
allowedExtensions: const ['json'],
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -31,10 +31,18 @@ class ProductRepository extends ChangeNotifier {
|
|||||||
return _opening!;
|
return _opening!;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<String> _defaultDatabasePath() async {
|
||||||
|
final dir = (await getApplicationDocumentsDirectory()).path;
|
||||||
|
final groci = p.join(dir, 'groci.db');
|
||||||
|
final legacy = p.join(dir, 'receipity.db');
|
||||||
|
if (!File(groci).existsSync() && File(legacy).existsSync()) {
|
||||||
|
await File(legacy).rename(groci);
|
||||||
|
}
|
||||||
|
return groci;
|
||||||
|
}
|
||||||
|
|
||||||
Future<Database> _open() async {
|
Future<Database> _open() async {
|
||||||
final path =
|
final path = databasePath ?? await _defaultDatabasePath();
|
||||||
databasePath ??
|
|
||||||
p.join((await getApplicationDocumentsDirectory()).path, 'receipity.db');
|
|
||||||
return openDatabase(
|
return openDatabase(
|
||||||
path,
|
path,
|
||||||
version: 9,
|
version: 9,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/// Shared strings used across the app.
|
/// Shared strings used across the app.
|
||||||
library;
|
library;
|
||||||
|
|
||||||
const String kAppName = 'Receipity';
|
const String kAppName = 'Groci';
|
||||||
|
|
||||||
/// Bundled Jumbo receipt used to test OCR without the camera.
|
/// Bundled Jumbo receipt used to test OCR without the camera.
|
||||||
const String kSampleReceiptAsset = 'assets/receipt.jpeg';
|
const String kSampleReceiptAsset = 'assets/receipt.jpeg';
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
name: receipity
|
name: groci
|
||||||
description: Capture a shopping receipt and show Google ML Kit text recognition output.
|
description: Capture a shopping receipt and show Google ML Kit text recognition output.
|
||||||
publish_to: 'none'
|
publish_to: 'none'
|
||||||
version: 1.0.0+1
|
version: 1.0.0+1
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:receipity/services/backup_format.dart';
|
import 'package:groci/services/backup_format.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
test('round-trips a backup document', () {
|
test('round-trips a backup document', () {
|
||||||
@@ -81,9 +81,10 @@ void main() {
|
|||||||
expect(parsed.shoppingLists.single['name'], 'Weekly');
|
expect(parsed.shoppingLists.single['name'], 'Weekly');
|
||||||
expect(parsed.shoppingListItems.single['name'], 'Milk');
|
expect(parsed.shoppingListItems.single['name'], 'Milk');
|
||||||
expect(parsed.images['products/product_1.jpg'], 'abc123');
|
expect(parsed.images['products/product_1.jpg'], 'abc123');
|
||||||
|
expect(parsed.encode(), contains('"format": "groci-backup"'));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('accepts a version 1 backup without shopping lists', () {
|
test('accepts legacy receipity backup format', () {
|
||||||
const json = '''
|
const json = '''
|
||||||
{
|
{
|
||||||
"format": "receipity-backup",
|
"format": "receipity-backup",
|
||||||
@@ -104,7 +105,7 @@ void main() {
|
|||||||
expect(parsed.shopTags, isEmpty);
|
expect(parsed.shopTags, isEmpty);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('rejects a file that is not a Receipity backup', () {
|
test('rejects a file that is not a Groci backup', () {
|
||||||
expect(
|
expect(
|
||||||
() => BackupDocument.parse('{"hello":"world"}'),
|
() => BackupDocument.parse('{"hello":"world"}'),
|
||||||
throwsFormatException,
|
throwsFormatException,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:receipity/models/line_item.dart';
|
import 'package:groci/models/line_item.dart';
|
||||||
|
|
||||||
import 'test_helpers.dart';
|
import 'test_helpers.dart';
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:receipity/utils/fuzzy.dart';
|
import 'package:groci/utils/fuzzy.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
test('matches substrings and character subsequences', () {
|
test('matches substrings and character subsequences', () {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:receipity/models/line_item.dart';
|
import 'package:groci/models/line_item.dart';
|
||||||
import 'package:receipity/models/product.dart';
|
import 'package:groci/models/product.dart';
|
||||||
import 'package:receipity/utils/product_names.dart';
|
import 'package:groci/utils/product_names.dart';
|
||||||
|
|
||||||
import 'test_helpers.dart';
|
import 'test_helpers.dart';
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:receipity/services/receipt_parser.dart';
|
import 'package:groci/services/receipt_parser.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
test('parses name and price at the end of a line', () {
|
test('parses name and price at the end of a line', () {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:receipity/models/shop.dart';
|
import 'package:groci/models/shop.dart';
|
||||||
import 'package:receipity/utils/shop_calendar.dart';
|
import 'package:groci/utils/shop_calendar.dart';
|
||||||
import 'package:receipity/utils/shop_log_filter.dart';
|
import 'package:groci/utils/shop_log_filter.dart';
|
||||||
|
|
||||||
Shop _shop({
|
Shop _shop({
|
||||||
required int id,
|
required int id,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:receipity/models/supermarket.dart';
|
import 'package:groci/models/supermarket.dart';
|
||||||
import 'package:receipity/utils/supermarkets.dart';
|
import 'package:groci/utils/supermarkets.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
test('detects Jumbo and Lidl from receipt text', () {
|
test('detects Jumbo and Lidl from receipt text', () {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import 'dart:math';
|
|||||||
|
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:path/path.dart' as p;
|
import 'package:path/path.dart' as p;
|
||||||
import 'package:receipity/services/product_repository.dart';
|
import 'package:groci/services/product_repository.dart';
|
||||||
import 'package:sqflite_common_ffi/sqflite_ffi.dart';
|
import 'package:sqflite_common_ffi/sqflite_ffi.dart';
|
||||||
|
|
||||||
var _dbSeq = 0;
|
var _dbSeq = 0;
|
||||||
@@ -18,7 +18,7 @@ void ensureTestSqlite() {
|
|||||||
|
|
||||||
ProductRepository memoryRepository() {
|
ProductRepository memoryRepository() {
|
||||||
ensureTestSqlite();
|
ensureTestSqlite();
|
||||||
final dir = Directory(p.join('.dart_tool', 'receipity_test_db'))
|
final dir = Directory(p.join('.dart_tool', 'groci_test_db'))
|
||||||
..createSync(recursive: true);
|
..createSync(recursive: true);
|
||||||
final name =
|
final name =
|
||||||
'db_${DateTime.now().microsecondsSinceEpoch}_${_dbSeq++}_${Random().nextInt(1 << 32)}.sqlite';
|
'db_${DateTime.now().microsecondsSinceEpoch}_${_dbSeq++}_${Random().nextInt(1 << 32)}.sqlite';
|
||||||
|
|||||||
+17
-17
@@ -1,9 +1,9 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:receipity/main.dart';
|
import 'package:groci/main.dart';
|
||||||
import 'package:receipity/models/line_item.dart';
|
import 'package:groci/models/line_item.dart';
|
||||||
import 'package:receipity/review_screen.dart';
|
import 'package:groci/review_screen.dart';
|
||||||
import 'package:receipity/widgets/shop_heatmap.dart';
|
import 'package:groci/widgets/shop_heatmap.dart';
|
||||||
|
|
||||||
import 'test_helpers.dart';
|
import 'test_helpers.dart';
|
||||||
|
|
||||||
@@ -13,7 +13,7 @@ void main() {
|
|||||||
testWidgets('home screen shows overview and bottom navigation', (
|
testWidgets('home screen shows overview and bottom navigation', (
|
||||||
tester,
|
tester,
|
||||||
) async {
|
) async {
|
||||||
await tester.pumpWidget(ReceipityApp(repository: memoryRepository()));
|
await tester.pumpWidget(GrociApp(repository: memoryRepository()));
|
||||||
await pumpUntilFound(tester, find.text('Nothing logged yet.'));
|
await pumpUntilFound(tester, find.text('Nothing logged yet.'));
|
||||||
|
|
||||||
expect(find.text('Home'), findsWidgets);
|
expect(find.text('Home'), findsWidgets);
|
||||||
@@ -27,12 +27,12 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('scan screen shows capture actions', (tester) async {
|
testWidgets('scan screen shows capture actions', (tester) async {
|
||||||
await tester.pumpWidget(ReceipityApp(repository: memoryRepository()));
|
await tester.pumpWidget(GrociApp(repository: memoryRepository()));
|
||||||
await pumpUntilFound(tester, find.text('Overview'));
|
await pumpUntilFound(tester, find.text('Overview'));
|
||||||
await tester.tap(find.byTooltip('Add'));
|
await tester.tap(find.byTooltip('Add'));
|
||||||
await tester.pump();
|
await tester.pump();
|
||||||
|
|
||||||
expect(find.text('Receipity'), findsOneWidget);
|
expect(find.text('Groci'), findsOneWidget);
|
||||||
expect(find.text('Take photo'), findsOneWidget);
|
expect(find.text('Take photo'), findsOneWidget);
|
||||||
expect(find.text('Pick from gallery'), findsOneWidget);
|
expect(find.text('Pick from gallery'), findsOneWidget);
|
||||||
expect(find.text('Enter manually'), findsOneWidget);
|
expect(find.text('Enter manually'), findsOneWidget);
|
||||||
@@ -44,7 +44,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('empty shop log hides edit and disables search', (tester) async {
|
testWidgets('empty shop log hides edit and disables search', (tester) async {
|
||||||
await tester.pumpWidget(ReceipityApp(repository: memoryRepository()));
|
await tester.pumpWidget(GrociApp(repository: memoryRepository()));
|
||||||
await pumpUntilFound(tester, find.text('Overview'));
|
await pumpUntilFound(tester, find.text('Overview'));
|
||||||
await tester.tap(find.text('Shop log'));
|
await tester.tap(find.text('Shop log'));
|
||||||
await pumpUntilFound(
|
await pumpUntilFound(
|
||||||
@@ -80,7 +80,7 @@ void main() {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
await tester.pumpWidget(ReceipityApp(repository: repository));
|
await tester.pumpWidget(GrociApp(repository: repository));
|
||||||
await pumpUntilFound(tester, find.text('Overview'));
|
await pumpUntilFound(tester, find.text('Overview'));
|
||||||
await tester.tap(find.text('Shop log'));
|
await tester.tap(find.text('Shop log'));
|
||||||
await pumpUntilFound(tester, find.text('Weekly shop'));
|
await pumpUntilFound(tester, find.text('Weekly shop'));
|
||||||
@@ -116,7 +116,7 @@ void main() {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
await tester.pumpWidget(ReceipityApp(repository: repository));
|
await tester.pumpWidget(GrociApp(repository: repository));
|
||||||
await pumpUntilFound(tester, find.text('Overview'));
|
await pumpUntilFound(tester, find.text('Overview'));
|
||||||
await tester.tap(find.text('Products').last);
|
await tester.tap(find.text('Products').last);
|
||||||
await pumpUntilFound(tester, find.text('Milk'));
|
await pumpUntilFound(tester, find.text('Milk'));
|
||||||
@@ -142,7 +142,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('profile screen is a placeholder', (tester) async {
|
testWidgets('profile screen is a placeholder', (tester) async {
|
||||||
await tester.pumpWidget(ReceipityApp(repository: memoryRepository()));
|
await tester.pumpWidget(GrociApp(repository: memoryRepository()));
|
||||||
await pumpUntilFound(tester, find.text('Overview'));
|
await pumpUntilFound(tester, find.text('Overview'));
|
||||||
await tester.tap(find.byTooltip('Profile'));
|
await tester.tap(find.byTooltip('Profile'));
|
||||||
await pumpUntilFound(tester, find.text('Guest'));
|
await pumpUntilFound(tester, find.text('Guest'));
|
||||||
@@ -172,7 +172,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('enter manually opens a blank trip', (tester) async {
|
testWidgets('enter manually opens a blank trip', (tester) async {
|
||||||
await tester.pumpWidget(ReceipityApp(repository: memoryRepository()));
|
await tester.pumpWidget(GrociApp(repository: memoryRepository()));
|
||||||
await pumpUntilFound(tester, find.text('Overview'));
|
await pumpUntilFound(tester, find.text('Overview'));
|
||||||
await tester.tap(find.byTooltip('Add'));
|
await tester.tap(find.byTooltip('Add'));
|
||||||
await tester.pump();
|
await tester.pump();
|
||||||
@@ -182,7 +182,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('lists tab shows shopping lists', (tester) async {
|
testWidgets('lists tab shows shopping lists', (tester) async {
|
||||||
await tester.pumpWidget(ReceipityApp(repository: memoryRepository()));
|
await tester.pumpWidget(GrociApp(repository: memoryRepository()));
|
||||||
await pumpUntilFound(tester, find.text('Overview'));
|
await pumpUntilFound(tester, find.text('Overview'));
|
||||||
await tester.tap(find.text('Lists'));
|
await tester.tap(find.text('Lists'));
|
||||||
await tester.pump();
|
await tester.pump();
|
||||||
@@ -264,7 +264,7 @@ void main() {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
await tester.pumpWidget(ReceipityApp(repository: repository));
|
await tester.pumpWidget(GrociApp(repository: repository));
|
||||||
await pumpUntilFound(tester, find.text('Overview'));
|
await pumpUntilFound(tester, find.text('Overview'));
|
||||||
await tester.tap(find.text('Products').last);
|
await tester.tap(find.text('Products').last);
|
||||||
await pumpUntilFound(tester, find.text('Milk'));
|
await pumpUntilFound(tester, find.text('Milk'));
|
||||||
@@ -286,7 +286,7 @@ void main() {
|
|||||||
final repository = memoryRepository();
|
final repository = memoryRepository();
|
||||||
await tester.runAsync(() => seedCaseConflictCatalog(repository));
|
await tester.runAsync(() => seedCaseConflictCatalog(repository));
|
||||||
|
|
||||||
await tester.pumpWidget(ReceipityApp(repository: repository));
|
await tester.pumpWidget(GrociApp(repository: repository));
|
||||||
await pumpUntilFound(tester, find.text('Overview'));
|
await pumpUntilFound(tester, find.text('Overview'));
|
||||||
await tester.tap(find.text('Products').last);
|
await tester.tap(find.text('Products').last);
|
||||||
await pumpUntilFound(tester, find.text('1 duplicate product'));
|
await pumpUntilFound(tester, find.text('1 duplicate product'));
|
||||||
@@ -313,7 +313,7 @@ void main() {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
await tester.pumpWidget(ReceipityApp(repository: repository));
|
await tester.pumpWidget(GrociApp(repository: repository));
|
||||||
await pumpUntilFound(tester, find.text('Overview'));
|
await pumpUntilFound(tester, find.text('Overview'));
|
||||||
await tester.tap(find.text('Products').last);
|
await tester.tap(find.text('Products').last);
|
||||||
await pumpUntilFound(tester, find.text('1 product, multiple spellings'));
|
await pumpUntilFound(tester, find.text('1 product, multiple spellings'));
|
||||||
@@ -328,7 +328,7 @@ void main() {
|
|||||||
final repository = memoryRepository();
|
final repository = memoryRepository();
|
||||||
await tester.runAsync(() => seedCaseConflictCatalog(repository));
|
await tester.runAsync(() => seedCaseConflictCatalog(repository));
|
||||||
|
|
||||||
await tester.pumpWidget(ReceipityApp(repository: repository));
|
await tester.pumpWidget(GrociApp(repository: repository));
|
||||||
await pumpUntilFound(tester, find.text('Overview'));
|
await pumpUntilFound(tester, find.text('Overview'));
|
||||||
await tester.tap(find.text('Products').last);
|
await tester.tap(find.text('Products').last);
|
||||||
await pumpUntilFound(tester, find.text('1 duplicate product'));
|
await pumpUntilFound(tester, find.text('1 duplicate product'));
|
||||||
|
|||||||
Reference in New Issue
Block a user