Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -140,4 +140,4 @@ SPEC CHECKSUMS:

PODFILE CHECKSUM: a62623f56f2d1d0e85a4a3c73509cd2832d5c86f

COCOAPODS: 1.14.3
COCOAPODS: 1.15.0
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,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');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,13 @@ class MockIFileService extends _i1.Mock implements _i9.IFileService {
_i1.throwOnMissingStub(this);
}

@override
Future<int> getNextProjectNumber() => super.noSuchMethod(
Invocation.method(#getNextProjectNumber, []),
returnValue: Future<int>.value(1),
returnValueForMissingStub: Future<int>.value(-1),
);

@override
_i3.Future<_i5.Result<_i11.File, _i9.Failure>> save(
String? filename,
Expand Down
54 changes: 52 additions & 2 deletions packages/io_library/lib/src/service/file_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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<Result<File, Failure>> save(String filename, Uint8List data);
Expand All @@ -18,6 +19,13 @@ abstract class IFileService {

Result<File, Failure> getFile(String path);


// Declare the new methods in the interface
Future<int> getNextImageNumber();
Future<int> getNextProjectNumber();
//end


static final provider = Provider<IFileService>((ref) => FileService());

Future<bool> checkIfFileExistsInApplicationDirectory(String fileName);
Expand All @@ -31,7 +39,7 @@ class FileService with LoggableMixin implements IFileService {
Future<Result<File, Failure>> 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);
}
Expand All @@ -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);
Expand Down Expand Up @@ -107,4 +115,46 @@ class FileService with LoggableMixin implements IFileService {
return const Result.err(LoadImageFailure.unidentified);
}
}




@override
Future<int> 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<int> 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;
}



}
41 changes: 36 additions & 5 deletions packages/io_library/lib/src/ui/save_image_dialog.dart
Original file line number Diff line number Diff line change
@@ -1,28 +1,30 @@
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<ImageMetaData?> showSaveImageDialog(
BuildContext context, bool savingProject) =>
BuildContext context, bool savingProject) =>
showGeneralDialog<ImageMetaData?>(
context: context,
pageBuilder: (_, __, ___) =>
SaveImageDialog(savingProject: savingProject),
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<SaveImageDialog> createState() => _SaveImageDialogState();
SaveImageDialogState createState() => SaveImageDialogState();
}

class _SaveImageDialogState extends State<SaveImageDialog> {
class SaveImageDialogState extends ConsumerState<SaveImageDialog> {
final TextEditingController nameFieldController = TextEditingController();
final formKey = GlobalKey<FormState>(debugLabel: 'SaveImageDialog Form');
var selectedFormat = ImageFormat.jpg;
Expand All @@ -31,12 +33,41 @@ class _SaveImageDialogState extends State<SaveImageDialog> {
@override
void initState() {
super.initState();

if (widget.savingProject) {
selectedFormat = ImageFormat.catrobatImage;
}


WidgetsBinding.instance.addPostFrameCallback((_) {
_setDefaultFileName();
});
}




Future<void> _setDefaultFileName() async {
final fileService = ref.read(IFileService.provider);
String defaultName;
if (widget.savingProject) {
final nextNumber = await fileService.getNextProjectNumber();
defaultName = 'project$nextNumber';
}
else {

final nextNumber = await fileService.getNextImageNumber();
defaultName = 'image$nextNumber';

}

setState(() {
nameFieldController.text = defaultName;
});
}




void _dismissDialogWithData() {
late ImageMetaData data;
switch (selectedFormat) {
Expand Down
1 change: 1 addition & 0 deletions packages/io_library/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down