Skip to content

Commit

Permalink
Umoznit sharovat subor ak na Android neexistuje Downloads (#24)
Browse files Browse the repository at this point in the history
#18 | Allow sharing signed Document even when failed to save file
  • Loading branch information
Matej-Hlatky authored Jun 27, 2024
1 parent 37d6d18 commit 3d69abe
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 30 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

## NEXT - v1.0.2(33)

- Refactor Settings model
- Refactor Settings model
- #18 | Allow sharing signed Document even when failed to save file

## 2024-06-17 - v1.0.1(1)

Expand Down
43 changes: 28 additions & 15 deletions lib/bloc/present_signed_document_cubit.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import 'dart:convert' show base64Decode;
import 'dart:io' show File;
import 'dart:io' show File, Platform;

import 'package:autogram_sign/autogram_sign.dart' show SignDocumentResponseBody;
import 'package:flutter/foundation.dart';
Expand All @@ -18,6 +18,9 @@ import 'present_signed_document_state.dart';
export 'present_signed_document_state.dart';

/// Cubit for [PresentSignedDocumentScreen].
///
/// Allows saving document into public directory or getting [File] instance
/// which can be shared.
@injectable
class PresentSignedDocumentCubit extends Cubit<PresentSignedDocumentState> {
static final _log = Logger("PresentSignedDocumentCubit");
Expand All @@ -33,6 +36,7 @@ class PresentSignedDocumentCubit extends Cubit<PresentSignedDocumentState> {
}) : _appService = appService,
super(const PresentSignedDocumentInitialState());

/// Saves [signedDocument] into public directory.
Future<void> saveDocument() async {
_log.info("Saving signed document: ${signedDocument.filename}.");

Expand All @@ -41,11 +45,10 @@ class PresentSignedDocumentCubit extends Cubit<PresentSignedDocumentState> {
File? file;

try {
file = await _getTargetFile();
final bytes = await Future.microtask(
() => base64Decode(signedDocument.content),
);
await file.writeAsBytes(bytes);
file = await _getTargetPath().then((path) => File(path));
// TODO Catch and still allow sharing
// Need to change PresentSignedDocumentSuccessState impl. to allow File?
await _saveDocumentIntoFile(file!);

_log.info("Signed Document was saved into $file");

Expand Down Expand Up @@ -73,32 +76,42 @@ class PresentSignedDocumentCubit extends Cubit<PresentSignedDocumentState> {
final name = signedDocument.filename;
final directory = await getTemporaryDirectory();
final path = p.join(directory.path, name);
final bytes = await Future.microtask(
() => base64Decode(signedDocument.content),
);
final file = File(path);

return file.writeAsBytes(bytes, flush: true);
await _saveDocumentIntoFile(file);

return file;
}

/// Returns target [File] where to save new file from [signedDocument].
/// Returns file path, where [signedDocument] content should be saved.
///
/// See also:
/// - [getTargetFileName]
Future<File> _getTargetFile() async {
Future<String> _getTargetPath() async {
final directory = await _appService.getDocumentsDirectory();

// Attempt to create Directory if not exists
if (!(await directory.exists()) && Platform.isAndroid) {
await directory.create(recursive: true);
}

final name = getTargetFileName(signedDocument.filename);
final path = p.join(directory.path, name);

return File(path);
return p.join(directory.path, name);
}

/// Saves [signedDocument] content into given [file].
Future<void> _saveDocumentIntoFile(File file) {
return Future.microtask(() => base64Decode(signedDocument.content))
.then((bytes) => file.writeAsBytes(bytes, flush: true));
}

/// Gets the target file name.
/// Drops suffix and adds timestamp.
@visibleForTesting
static String getTargetFileName(
String name, [
// TODO This should get exact DateTime from previous cubit when it was really signed
// TODO This should get exact DateTime from previous cubit when it was actually signed
// SignDocumentCubit signingTime
ValueGetter<DateTime> clock = DateTime.now,
]) {
Expand Down
1 change: 1 addition & 0 deletions lib/pages/test_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import 'package:share_plus/share_plus.dart';

import '../utils.dart' as utils;

// TODO Move to ui/screens, add some docs
class TestPage extends HookWidget {
const TestPage({super.key});

Expand Down
42 changes: 34 additions & 8 deletions lib/ui/screens/present_signed_document_screen.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'dart:developer' as developer;
import 'dart:io' show File, OSError, PathAccessException;

import 'package:autogram_sign/autogram_sign.dart' show SignDocumentResponseBody;
Expand All @@ -20,6 +21,9 @@ import '../widgets/result_view.dart';

/// Screen for presenting signed document.
///
/// When [signingType] is [DocumentSigningType.local], then document is saved
/// into this device and also "Share" button is visible.
///
/// Uses [PresentSignedDocumentCubit].
class PresentSignedDocumentScreen extends StatelessWidget {
final SignDocumentResponseBody signedDocument;
Expand Down Expand Up @@ -144,6 +148,10 @@ class _Body extends StatelessWidget {
}

Widget _getChild(BuildContext context) {
final sharingEnabled = (signingType == DocumentSigningType.local);
final onShareFileRequested =
sharingEnabled ? this.onShareFileRequested : null;

return switch (state) {
PresentSignedDocumentInitialState _ => _SuccessContent(
file: null,
Expand All @@ -153,7 +161,7 @@ class _Body extends StatelessWidget {
PresentSignedDocumentLoadingState _ => const LoadingContent(),
PresentSignedDocumentErrorState _ => _SuccessContent(
file: null,
onShareFileRequested: null,
onShareFileRequested: onShareFileRequested,
onCloseRequested: onCloseRequested,
),
PresentSignedDocumentSuccessState state => _SuccessContent(
Expand Down Expand Up @@ -257,7 +265,12 @@ Widget previewInitialPresentSignedDocumentScreen(BuildContext context) {
return _Body(
state: const PresentSignedDocumentInitialState(),
signingType: signingType,
onCloseRequested: () {},
onShareFileRequested: () {
developer.log('onShareFileRequested');
},
onCloseRequested: () {
developer.log('onCloseRequested');
},
);
}

Expand All @@ -276,6 +289,12 @@ Widget previewLoadingPresentSignedDocumentScreen(BuildContext context) {
return _Body(
state: const PresentSignedDocumentLoadingState(),
signingType: signingType,
onShareFileRequested: () {
developer.log('onShareFileRequested');
},
onCloseRequested: () {
developer.log('onCloseRequested');
},
);
}

Expand All @@ -291,7 +310,7 @@ Widget previewErrorPresentSignedDocumentScreen(BuildContext context) {
initialOption: DocumentSigningType.local,
);

// TODO Should preview whole Screen class also with BlocConsumer.listener
// TODO Should preview whole Screen class also with BlocConsumer.listener to display error in SnackBar
const error = PathAccessException(
"/storage/emulated/0/Download/container-signed-xades-baseline-b.sce",
OSError("Permission denied", 13),
Expand All @@ -301,8 +320,12 @@ Widget previewErrorPresentSignedDocumentScreen(BuildContext context) {
return _Body(
state: const PresentSignedDocumentErrorState(error),
signingType: signingType,
onShareFileRequested: () {},
onCloseRequested: () {},
onShareFileRequested: () {
developer.log('onShareFileRequested');
},
onCloseRequested: () {
developer.log('onCloseRequested');
},
);
}

Expand All @@ -326,8 +349,11 @@ Widget previewSuccessPresentSignedDocumentScreen(BuildContext context) {
return _Body(
state: PresentSignedDocumentSuccessState(file),
signingType: signingType,
onShareFileRequested:
signingType == DocumentSigningType.local ? () {} : null,
onCloseRequested: () {},
onShareFileRequested: () {
developer.log('onShareFileRequested');
},
onCloseRequested: () {
developer.log('onCloseRequested');
},
);
}
16 changes: 12 additions & 4 deletions lib/ui/screens/sign_document_screen.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import 'dart:developer' as developer;

import 'package:autogram_sign/autogram_sign.dart'
show SignDocumentResponseBody, SignDocumentResponseBodyMimeType;
import 'package:eidmsdk/types.dart' show Certificate;
Expand Down Expand Up @@ -141,8 +143,11 @@ Widget previewLoadingSignDocumentScreen(BuildContext context) {
type: SignDocumentScreen,
)
Widget previewErrorSignDocumentScreen(BuildContext context) {
return const _Body(
state: SignDocumentErrorState("Error message!"),
return _Body(
state: const SignDocumentErrorState("Error message!"),
onRetryRequested: () {
developer.log('onRetryRequested');
},
);
}

Expand All @@ -152,8 +157,8 @@ Widget previewErrorSignDocumentScreen(BuildContext context) {
type: SignDocumentScreen,
)
Widget previewSuccessSignDocumentScreen(BuildContext context) {
return const _Body(
state: SignDocumentSuccessState(
return _Body(
state: const SignDocumentSuccessState(
SignDocumentResponseBody(
filename: "document.pdf",
mimeType: SignDocumentResponseBodyMimeType.applicationPdfBase64,
Expand All @@ -162,5 +167,8 @@ Widget previewSuccessSignDocumentScreen(BuildContext context) {
signedBy: "",
),
),
onRetryRequested: () {
developer.log('onRetryRequested');
},
);
}
4 changes: 2 additions & 2 deletions pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -767,10 +767,10 @@ packages:
dependency: "direct main"
description:
name: pdf
sha256: "243f05342fc0bdf140eba5b069398985cdbdd3dbb1d776cf43d5ea29cc570ba6"
sha256: "81d5522bddc1ef5c28e8f0ee40b71708761753c163e0c93a40df56fd515ea0f0"
url: "https://pub.dev"
source: hosted
version: "3.10.8"
version: "3.11.0"
pdf_widget_wrapper:
dependency: transitive
description:
Expand Down

0 comments on commit 3d69abe

Please sign in to comment.