fbmobile/lib/core/viewmodels/upload_model.dart

283 lines
9 KiB
Dart
Raw Normal View History

import 'dart:async';
2021-02-02 14:33:23 +00:00
import 'dart:io';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_translate/flutter_translate.dart';
import 'package:logger/logger.dart';
import 'package:path/path.dart';
import 'package:receive_sharing_intent/receive_sharing_intent.dart';
2021-02-02 14:33:23 +00:00
import '../../locator.dart';
import '../enums/error_code.dart';
import '../enums/refresh_event.dart';
import '../enums/swipe_event.dart';
2021-02-02 14:33:23 +00:00
import '../enums/viewstate.dart';
import '../error/rest_service_exception.dart';
import '../error/service_exception.dart';
import '../models/rest/rest_error.dart';
2021-02-02 17:17:48 +00:00
import '../models/rest/uploaded_multi_response.dart';
2021-02-02 14:33:23 +00:00
import '../models/rest/uploaded_response.dart';
import '../services/file_service.dart';
import '../services/link_service.dart';
import '../services/refresh_service.dart';
import '../services/swipe_service.dart';
2021-02-02 14:33:23 +00:00
import '../util/logger.dart';
import '../util/paste_util.dart';
2021-02-02 14:33:23 +00:00
import 'base_model.dart';
class UploadModel extends BaseModel {
final Logger _logger = getLogger();
final FileService _fileService = locator<FileService>();
final LinkService _linkService = locator<LinkService>();
final RefreshService _refreshService = locator<RefreshService>();
final SwipeService _swipeService = locator<SwipeService>();
2021-02-02 14:33:23 +00:00
TextEditingController _pasteTextController = TextEditingController();
bool pasteTextTouched = false;
late StreamSubscription _intentDataStreamSubscription;
2021-02-02 14:33:23 +00:00
bool createMulti = false;
String? fileName;
List<PlatformFile>? paths;
String? _extension;
2021-02-02 14:33:23 +00:00
bool loadingPath = false;
String? errorMessage;
2021-02-02 14:33:23 +00:00
TextEditingController get pasteTextController => _pasteTextController;
void init() {
_pasteTextController.addListener(() {
pasteTextTouched = pasteTextController.text.isNotEmpty;
setStateValue("PASTE_TEXT_TOUCHED", pasteTextTouched);
});
// For sharing images coming from outside the app while the app is in the memory
_intentDataStreamSubscription = ReceiveSharingIntent.getMediaStream()
.listen((List<SharedMediaFile> value) {
if (value.length > 0) {
setStateView(ViewState.Busy);
paths = value.map((sharedFile) {
return PlatformFile.fromMap({
'path': sharedFile.path,
'name': basename(sharedFile.path),
'size': File(sharedFile.path).lengthSync(),
'bytes': null
});
}).toList();
setStateView(ViewState.Idle);
if (paths!.isNotEmpty && paths!.length > 0) {
_swipeService.addEvent(SwipeEvent.Start);
}
}
}, onError: (err) {
_errorIntentHandle(err);
});
// For sharing images coming from outside the app while the app is closed
ReceiveSharingIntent.getInitialMedia().then((List<SharedMediaFile> value) {
if (value.length > 0) {
setStateView(ViewState.Busy);
paths = value.map((sharedFile) {
return PlatformFile.fromMap({
'path': sharedFile.path,
'name': basename(sharedFile.path),
'size': File(sharedFile.path).lengthSync(),
'bytes': null
});
}).toList();
setStateView(ViewState.Idle);
if (paths!.isNotEmpty && paths!.length > 0) {
_swipeService.addEvent(SwipeEvent.Start);
}
}
}, onError: (err) {
_errorIntentHandle(err);
});
// For sharing or opening urls/text coming from outside the app while the app is in the memory
_intentDataStreamSubscription =
ReceiveSharingIntent.getTextStream().listen((String value) {
if (value.isNotEmpty) {
setStateView(ViewState.Busy);
pasteTextController.text = value;
setStateView(ViewState.Idle);
_swipeService.addEvent(SwipeEvent.Start);
}
}, onError: (err) {
_errorIntentHandle(err);
});
// For sharing or opening urls/text coming from outside the app while the app is closed
ReceiveSharingIntent.getInitialText().then((String? value) {
if (value != null && value.isNotEmpty) {
setStateView(ViewState.Busy);
pasteTextController.text = value;
setStateView(ViewState.Idle);
if (paths!.isNotEmpty && paths!.length > 0) {
_swipeService.addEvent(SwipeEvent.Start);
}
}
}, onError: (err) {
_errorIntentHandle(err);
});
}
void _errorIntentHandle(err) {
setStateView(ViewState.Busy);
errorMessage = translate('upload.retrieval_intent');
_logger.e('Error while retrieving shared data: $err');
setStateView(ViewState.Idle);
_swipeService.addEvent(SwipeEvent.Start);
}
String? generatePasteLinks(Map<String, bool>? uploads, String url) {
if (uploads != null && uploads.length > 0) {
var links = '';
uploads.forEach((id, isMulti) {
if (isMulti && createMulti || !isMulti && !createMulti) {
links += '${PasteUtil.generateLink(url, id)}\n';
}
});
return links;
}
return null;
}
2021-02-02 14:33:23 +00:00
void toggleCreateMulti() {
setStateView(ViewState.Busy);
2021-02-02 14:33:23 +00:00
createMulti = !createMulti;
setStateView(ViewState.Idle);
2021-02-02 14:33:23 +00:00
}
void openFileExplorer() async {
setStateView(ViewState.Busy);
2021-02-02 14:33:23 +00:00
setStateMessage(translate('upload.file_explorer_open'));
loadingPath = true;
try {
paths = (await FilePicker.platform.pickFiles(
type: FileType.any,
allowMultiple: true,
withData: false,
withReadStream: true,
allowedExtensions: (_extension?.isNotEmpty ?? false)
? _extension?.replaceAll(' ', '').split(',')
: null,
2021-02-02 14:33:23 +00:00
))
?.files;
} on PlatformException catch (e) {
_logger.e('Unsupported operation', e);
} catch (ex) {
_logger.e('An unknown error occurred', ex);
}
loadingPath = false;
fileName = paths != null ? paths!.map((e) => e.name).toString() : '...';
2021-02-02 14:33:23 +00:00
setStateMessage(null);
setStateView(ViewState.Idle);
2021-02-02 14:33:23 +00:00
}
void clearCachedFiles() async {
setStateView(ViewState.Busy);
2021-02-02 14:33:23 +00:00
await FilePicker.platform.clearTemporaryFiles();
paths = null;
fileName = null;
errorMessage = null;
setStateView(ViewState.Idle);
2021-02-02 14:33:23 +00:00
}
Future<Map<String, bool>?> upload() async {
setStateView(ViewState.Busy);
2021-02-02 14:33:23 +00:00
setStateMessage(translate('upload.uploading_now'));
Map<String, bool> uploadedPasteIds = new Map();
2021-02-02 14:33:23 +00:00
try {
List<File>? files;
Map<String, String>? additionalFiles;
if (pasteTextController.text.isNotEmpty) {
additionalFiles = Map.from({
'paste-${(new DateTime.now().millisecondsSinceEpoch / 1000).round()}.txt':
pasteTextController.text
});
2021-02-02 14:33:23 +00:00
}
if (paths != null && paths!.length > 0) {
files = paths!.map((e) => new File(e.path!)).toList();
2021-02-02 14:33:23 +00:00
}
UploadedResponse response =
await _fileService.uploadPaste(files, additionalFiles);
response.data.ids.forEach((element) {
uploadedPasteIds.putIfAbsent(element, () => false);
});
2021-02-02 14:33:23 +00:00
if (createMulti && response.data.ids.length > 1) {
UploadedMultiResponse multiResponse =
await _fileService.uploadMultiPaste(response.data.ids);
uploadedPasteIds.putIfAbsent(multiResponse.data.urlId, () => true);
2021-02-02 14:33:23 +00:00
}
clearCachedFiles();
_pasteTextController.clear();
_refreshService.addEvent(RefreshEvent.RefreshHistory);
2021-02-02 14:33:23 +00:00
errorMessage = null;
2021-02-02 17:17:48 +00:00
return uploadedPasteIds;
2021-02-02 14:33:23 +00:00
} catch (e) {
if (e is RestServiceException) {
if (e.statusCode == HttpStatus.notFound) {
errorMessage = translate('upload.errors.not_found');
} else if (e.statusCode == HttpStatus.forbidden) {
errorMessage = translate('api.forbidden');
} else if (e.statusCode != HttpStatus.notFound &&
e.statusCode != HttpStatus.forbidden &&
e.responseBody is RestError &&
e.responseBody.message != null) {
if (e.statusCode == HttpStatus.badRequest) {
errorMessage = translate('api.bad_request',
args: {'reason': e.responseBody.message});
2021-02-02 14:33:23 +00:00
} else {
errorMessage = translate('api.general_rest_error_payload',
args: {'message': e.responseBody.message});
2021-02-02 14:33:23 +00:00
}
} else {
errorMessage = translate('api.general_rest_error');
}
} else if (e is ServiceException && e.code == ErrorCode.SOCKET_ERROR) {
errorMessage = translate('api.socket_error');
} else if (e is ServiceException && e.code == ErrorCode.SOCKET_TIMEOUT) {
errorMessage = translate('api.socket_timeout');
} else {
errorMessage = translate('app.unknown_error');
setStateMessage(null);
setStateView(ViewState.Idle);
2021-02-02 14:33:23 +00:00
_logger.e('An unknown error occurred', e);
throw e;
}
}
setStateMessage(null);
setStateView(ViewState.Idle);
2021-02-02 17:17:48 +00:00
return null;
2021-02-02 14:33:23 +00:00
}
void openLink(String link) {
_linkService.open(link);
}
2021-02-02 14:33:23 +00:00
@override
void dispose() {
_pasteTextController.dispose();
_intentDataStreamSubscription.cancel();
2021-02-02 14:33:23 +00:00
super.dispose();
}
}