From 5e5f0052a47e50f4cd91806fb6ae1fd641f5fb73 Mon Sep 17 00:00:00 2001 From: vishad-tyagi <78733360+vishad-tyagi@users.noreply.github.com> Date: Thu, 29 Feb 2024 05:31:52 +0530 Subject: [PATCH 1/4] Add a placeholder name when saving --- ios/Podfile.lock | 2 +- .../lib/src/service/file_service.dart | 54 ++++++++++++++++++- .../lib/src/ui/save_image_dialog.dart | 43 +++++++++++++-- 3 files changed, 91 insertions(+), 8 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 62cb12ec..b124104e 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -140,4 +140,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: a62623f56f2d1d0e85a4a3c73509cd2832d5c86f -COCOAPODS: 1.14.3 +COCOAPODS: 1.15.0 diff --git a/packages/io_library/lib/src/service/file_service.dart b/packages/io_library/lib/src/service/file_service.dart index 2d72e9b9..0d89da71 100644 --- a/packages/io_library/lib/src/service/file_service.dart +++ b/packages/io_library/lib/src/service/file_service.dart @@ -7,6 +7,7 @@ import 'package:io_library/io_library.dart'; import 'package:oxidized/oxidized.dart'; import 'package:path_provider/path_provider.dart'; +import 'package:shared_preferences/shared_preferences.dart'; abstract class IFileService { Future> save(String filename, Uint8List data); @@ -18,6 +19,13 @@ abstract class IFileService { Result getFile(String path); + + // Declare the new methods in the interface + Future getNextImageNumber(); + Future getNextProjectNumber(); + //end + + static final provider = Provider((ref) => FileService()); Future checkIfFileExistsInApplicationDirectory(String fileName); @@ -31,7 +39,7 @@ class FileService with LoggableMixin implements IFileService { Future> pick() async { try { final result = - await FilePicker.platform.pickFiles(allowCompression: false); + await FilePicker.platform.pickFiles(allowCompression: false); if (result == null) { return const Result.err(LoadImageFailure.userCancelled); } @@ -54,7 +62,7 @@ class FileService with LoggableMixin implements IFileService { return const Result.err(SaveImageFailure.userCancelled); } final file = - await File('$saveDirectory/$filename').create(recursive: true); + await File('$saveDirectory/$filename').create(recursive: true); return Result.ok(await file.writeAsBytes(data)); } catch (err, stacktrace) { logger.severe('Could not save file', err, stacktrace); @@ -107,4 +115,46 @@ class FileService with LoggableMixin implements IFileService { return const Result.err(LoadImageFailure.unidentified); } } + + + + + @override + Future getNextImageNumber() async { + final prefs = await SharedPreferences.getInstance(); + int lastNumber = prefs.getInt('lastImageNumber') ?? 0; + int nextNumber = lastNumber + 1; + await prefs.setInt('lastImageNumber', nextNumber); + return nextNumber; + } + + + + + @override + Future getNextProjectNumber() async { + final directory = await getApplicationDocumentsDirectory(); + final files = await directory.list().toList(); + int maxNum = 0; + + for (var file in files) { + if (file is File) { + final fileName = file.path.split('/').last; + + if (fileName.startsWith('project')) { + final match = RegExp(r'project(\d+)').firstMatch(fileName); + if (match != null) { + final num = int.tryParse(match.group(1)!) ?? 0; + + if (num > maxNum) maxNum = num; + } + } + } + } + + return maxNum + 1; + } + + + } diff --git a/packages/io_library/lib/src/ui/save_image_dialog.dart b/packages/io_library/lib/src/ui/save_image_dialog.dart index 104f4bb5..dc80a0e1 100644 --- a/packages/io_library/lib/src/ui/save_image_dialog.dart +++ b/packages/io_library/lib/src/ui/save_image_dialog.dart @@ -1,10 +1,12 @@ import 'package:component_library/component_library.dart'; import 'package:flutter/material.dart'; import 'package:io_library/io_library.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + /// Returns [null] if user dismissed the dialog by tapping outside Future showSaveImageDialog( - BuildContext context, bool savingProject) => + BuildContext context, bool savingProject) => showGeneralDialog( context: context, pageBuilder: (_, __, ___) => @@ -12,17 +14,17 @@ Future showSaveImageDialog( barrierDismissible: true, barrierLabel: 'Dismiss save image dialog box'); -class SaveImageDialog extends StatefulWidget { +class SaveImageDialog extends ConsumerStatefulWidget { final bool savingProject; const SaveImageDialog({Key? key, required this.savingProject}) : super(key: key); @override - State createState() => _SaveImageDialogState(); + _SaveImageDialogState createState() => _SaveImageDialogState(); } -class _SaveImageDialogState extends State { +class _SaveImageDialogState extends ConsumerState { final TextEditingController nameFieldController = TextEditingController(); final formKey = GlobalKey(debugLabel: 'SaveImageDialog Form'); var selectedFormat = ImageFormat.jpg; @@ -31,12 +33,43 @@ class _SaveImageDialogState extends State { @override void initState() { super.initState(); - + print('this'); if (widget.savingProject) { selectedFormat = ImageFormat.catrobatImage; } + + + WidgetsBinding.instance.addPostFrameCallback((_) { + _setDefaultFileName(); + }); + } + + + + + void _setDefaultFileName() async { + final fileService = ref.read(IFileService.provider); + String defaultName; + if (widget.savingProject) { + final nextNumber = await fileService.getNextProjectNumber(); + defaultName = 'project$nextNumber'; + print(nextNumber); + } + else { + + final nextNumber = await fileService.getNextImageNumber(); + defaultName = 'image$nextNumber'; + + } + + setState(() { + nameFieldController.text = defaultName; + }); } + + + void _dismissDialogWithData() { late ImageMetaData data; switch (selectedFormat) { From 4bf857ab406a34c64e9f4d5a8189f94070438a49 Mon Sep 17 00:00:00 2001 From: vishad-tyagi <78733360+vishad-tyagi@users.noreply.github.com> Date: Wed, 6 Mar 2024 20:41:22 +0530 Subject: [PATCH 2/4] Edited test for added functionality --- .../test/widget/landing_page_test.dart | 1 + .../test/widget/landing_page_test.mocks.dart | 7 +++++++ packages/io_library/lib/src/ui/save_image_dialog.dart | 8 +++----- packages/io_library/pubspec.yaml | 1 + 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/packages/features/landing_page_screen/test/widget/landing_page_test.dart b/packages/features/landing_page_screen/test/widget/landing_page_test.dart index a9842fd2..937ce136 100644 --- a/packages/features/landing_page_screen/test/widget/landing_page_test.dart +++ b/packages/features/landing_page_screen/test/widget/landing_page_test.dart @@ -411,6 +411,7 @@ void main() { expect(saveProjectButton, findsOneWidget); await tester.tap(saveProjectButton); + when(fileService.getNextProjectNumber()).thenAnswer((_) async => 1); await tester.pumpAndSettle(); final textFormField = find.widgetWithText(TextFormField, 'Project name'); diff --git a/packages/features/landing_page_screen/test/widget/landing_page_test.mocks.dart b/packages/features/landing_page_screen/test/widget/landing_page_test.mocks.dart index 15d8c48f..df439781 100644 --- a/packages/features/landing_page_screen/test/widget/landing_page_test.mocks.dart +++ b/packages/features/landing_page_screen/test/widget/landing_page_test.mocks.dart @@ -298,6 +298,13 @@ class MockIFileService extends _i1.Mock implements _i8.IFileService { _i1.throwOnMissingStub(this); } + @override + Future getNextProjectNumber() => super.noSuchMethod( + Invocation.method(#getNextProjectNumber, []), + returnValue: Future.value(1), + returnValueForMissingStub: Future.value(-1), + ); + @override _i3.Future<_i5.Result<_i11.File, _i8.Failure>> save( String? filename, diff --git a/packages/io_library/lib/src/ui/save_image_dialog.dart b/packages/io_library/lib/src/ui/save_image_dialog.dart index dc80a0e1..80b14f82 100644 --- a/packages/io_library/lib/src/ui/save_image_dialog.dart +++ b/packages/io_library/lib/src/ui/save_image_dialog.dart @@ -21,10 +21,10 @@ class SaveImageDialog extends ConsumerStatefulWidget { : super(key: key); @override - _SaveImageDialogState createState() => _SaveImageDialogState(); + SaveImageDialogState createState() => SaveImageDialogState(); } -class _SaveImageDialogState extends ConsumerState { +class SaveImageDialogState extends ConsumerState { final TextEditingController nameFieldController = TextEditingController(); final formKey = GlobalKey(debugLabel: 'SaveImageDialog Form'); var selectedFormat = ImageFormat.jpg; @@ -33,7 +33,6 @@ class _SaveImageDialogState extends ConsumerState { @override void initState() { super.initState(); - print('this'); if (widget.savingProject) { selectedFormat = ImageFormat.catrobatImage; } @@ -47,13 +46,12 @@ class _SaveImageDialogState extends ConsumerState { - void _setDefaultFileName() async { + Future _setDefaultFileName() async { final fileService = ref.read(IFileService.provider); String defaultName; if (widget.savingProject) { final nextNumber = await fileService.getNextProjectNumber(); defaultName = 'project$nextNumber'; - print(nextNumber); } else { diff --git a/packages/io_library/pubspec.yaml b/packages/io_library/pubspec.yaml index 33e1fe2b..19c513db 100644 --- a/packages/io_library/pubspec.yaml +++ b/packages/io_library/pubspec.yaml @@ -27,6 +27,7 @@ dependencies: oxidized: ^5.2.0 intl: ^0.18.0 json_annotation: ^4.8.1 + shared_preferences: ^2.0.15 # Internal packages: component_library: From 968254dee3fd821f7f95beb3a02532a471ac7f2e Mon Sep 17 00:00:00 2001 From: vishad-tyagi <78733360+vishad-tyagi@users.noreply.github.com> Date: Sun, 21 Apr 2024 13:47:35 +0530 Subject: [PATCH 3/4] Removed Comments --- .../lib/src/service/file_service.dart | 18 +++--------------- .../lib/src/ui/save_image_dialog.dart | 15 ++------------- 2 files changed, 5 insertions(+), 28 deletions(-) diff --git a/packages/io_library/lib/src/service/file_service.dart b/packages/io_library/lib/src/service/file_service.dart index 0d89da71..da6daddc 100644 --- a/packages/io_library/lib/src/service/file_service.dart +++ b/packages/io_library/lib/src/service/file_service.dart @@ -19,12 +19,9 @@ abstract class IFileService { Result getFile(String path); - - // Declare the new methods in the interface Future getNextImageNumber(); - Future getNextProjectNumber(); - //end + Future getNextProjectNumber(); static final provider = Provider((ref) => FileService()); @@ -39,7 +36,7 @@ class FileService with LoggableMixin implements IFileService { Future> pick() async { try { final result = - await FilePicker.platform.pickFiles(allowCompression: false); + await FilePicker.platform.pickFiles(allowCompression: false); if (result == null) { return const Result.err(LoadImageFailure.userCancelled); } @@ -62,7 +59,7 @@ class FileService with LoggableMixin implements IFileService { return const Result.err(SaveImageFailure.userCancelled); } final file = - await File('$saveDirectory/$filename').create(recursive: true); + await File('$saveDirectory/$filename').create(recursive: true); return Result.ok(await file.writeAsBytes(data)); } catch (err, stacktrace) { logger.severe('Could not save file', err, stacktrace); @@ -116,9 +113,6 @@ class FileService with LoggableMixin implements IFileService { } } - - - @override Future getNextImageNumber() async { final prefs = await SharedPreferences.getInstance(); @@ -128,9 +122,6 @@ class FileService with LoggableMixin implements IFileService { return nextNumber; } - - - @override Future getNextProjectNumber() async { final directory = await getApplicationDocumentsDirectory(); @@ -154,7 +145,4 @@ class FileService with LoggableMixin implements IFileService { return maxNum + 1; } - - - } diff --git a/packages/io_library/lib/src/ui/save_image_dialog.dart b/packages/io_library/lib/src/ui/save_image_dialog.dart index 80b14f82..1109acd3 100644 --- a/packages/io_library/lib/src/ui/save_image_dialog.dart +++ b/packages/io_library/lib/src/ui/save_image_dialog.dart @@ -3,10 +3,9 @@ import 'package:flutter/material.dart'; import 'package:io_library/io_library.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; - /// Returns [null] if user dismissed the dialog by tapping outside Future showSaveImageDialog( - BuildContext context, bool savingProject) => + BuildContext context, bool savingProject) => showGeneralDialog( context: context, pageBuilder: (_, __, ___) => @@ -37,27 +36,20 @@ class SaveImageDialogState extends ConsumerState { selectedFormat = ImageFormat.catrobatImage; } - WidgetsBinding.instance.addPostFrameCallback((_) { _setDefaultFileName(); }); } - - - Future _setDefaultFileName() async { final fileService = ref.read(IFileService.provider); String defaultName; if (widget.savingProject) { final nextNumber = await fileService.getNextProjectNumber(); defaultName = 'project$nextNumber'; - } - else { - + } else { final nextNumber = await fileService.getNextImageNumber(); defaultName = 'image$nextNumber'; - } setState(() { @@ -65,9 +57,6 @@ class SaveImageDialogState extends ConsumerState { }); } - - - void _dismissDialogWithData() { late ImageMetaData data; switch (selectedFormat) { From a4d5353f0a1ceca079887e380be23df7776a1b12 Mon Sep 17 00:00:00 2001 From: vishad-tyagi <78733360+vishad-tyagi@users.noreply.github.com> Date: Wed, 1 May 2024 02:43:57 +0530 Subject: [PATCH 4/4] Null check --- packages/io_library/lib/src/service/file_service.dart | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/io_library/lib/src/service/file_service.dart b/packages/io_library/lib/src/service/file_service.dart index da6daddc..963c4396 100644 --- a/packages/io_library/lib/src/service/file_service.dart +++ b/packages/io_library/lib/src/service/file_service.dart @@ -135,9 +135,14 @@ class FileService with LoggableMixin implements IFileService { if (fileName.startsWith('project')) { final match = RegExp(r'project(\d+)').firstMatch(fileName); if (match != null) { - final num = int.tryParse(match.group(1)!) ?? 0; - - if (num > maxNum) maxNum = num; + final numString = match.group(1); + if (numString != null) { + final num = int.tryParse(numString) ?? 0; + + if (num > maxNum) { + maxNum = num; + } + } } } }