storage improvement for android 29 and above.

development-design-2.0
Sikander Saleem 3 years ago
parent fe75109017
commit ca1639fdd9

@ -7,7 +7,9 @@
additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="29" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />

@ -186,4 +186,48 @@ class Utils {
await file.copy(storagePath);
Utils.showToast("تم التنزيل");
}
static void downloadFileAboveAndroid32(String url, String path, {Function(List<int> bytes) onResponse}) {
print("url:$url");
print("path:$path");
var httpClient = http.Client();
var request = http.Request('GET', Uri.parse(url));
var response = httpClient.send(request);
String dir = path;
List<List<int>> chunks = [];
int downloaded = 0;
int lastVal;
response.asStream().listen((http.StreamedResponse r) {
r.stream.listen((List<int> chunk) {
debugPrint('downloadPercentage: ${downloaded / r.contentLength * 100}');
lastVal = (downloaded / r.contentLength * 100).toInt();
chunks.add(chunk);
downloaded += chunk.length;
}, onDone: () async {
debugPrint('downloadPercentage: ${downloaded / r.contentLength * 100}');
if (lastVal == 0) {
onResponse([]);
return;
}
final Uint8List bytes = Uint8List(r.contentLength);
int offset = 0;
for (List<int> chunk in chunks) {
bytes.setRange(offset, offset + chunk.length, chunk);
offset += chunk.length;
}
onResponse(bytes);
return;
}, onError: (ex) {
debugPrint("onError:$ex");
onResponse([]);
}, cancelOnError: true);
}).onError((ex) {
debugPrint("onError:$ex");
onResponse([]);
});
}
}

@ -2,11 +2,13 @@ import 'dart:async';
import 'dart:io';
import 'dart:ui';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:shared_storage/shared_storage.dart';
import 'package:syncfusion_flutter_pdfviewer/pdfviewer.dart';
import 'package:tangheem/api/tangheem_user_api_client.dart';
import 'package:tangheem/app_state/app_state.dart';
@ -121,10 +123,14 @@ class _PdfListScreenState extends State<PdfListScreen> {
width: 44,
height: 50,
).onPress(() async {
if (await _requestStoragePermission()) {
startFileDownload(contentList[index].exposeFilePath, contentList[index].fileName);
if (Platform.isAndroid && (await DeviceInfoPlugin().androidInfo).version.sdkInt > 29) {
savePdfToAboveAndroid32(contentList[index].exposeFilePath, contentList[index].fileName);
} else {
Utils.showToast("يجب أن تعطي الإذن للتنزيل.");
if (await _requestStoragePermission()) {
startFileDownload(contentList[index].exposeFilePath, contentList[index].fileName);
} else {
Utils.showToast("يجب أن تعطي الإذن للتنزيل.");
}
}
}),
7.width,
@ -181,6 +187,51 @@ class _PdfListScreenState extends State<PdfListScreen> {
),
);
}
void savePdfToAboveAndroid32(String pathUrl, String fileName) async {
List<UriPermission> _persistedPermissionUris = await persistedUriPermissions();
if (_persistedPermissionUris.isNotEmpty) {
UriPermission permissionUri = _persistedPermissionUris.first;
startFileDownloadAboveAndroid32(pathUrl, fileName, permissionUri.uri);
} else {
Uri selectedDocumentUris = await openDocumentTree();
if (selectedDocumentUris == null) return;
savePdfToAboveAndroid32(pathUrl, fileName);
}
}
void startFileDownloadAboveAndroid32(String url, String fileName, Uri persistentUri) async {
try {
Utils.showLoading(context);
//String path = await Utils.getStoragePath(fileName);
Utils.downloadFileAboveAndroid32(ApiConsts.baseUrl + url, "path", onResponse: (bytes) async {
Utils.hideLoading(context);
if (bytes.isNotEmpty) {
final documentFile = await persistentUri.toDocumentFile();
final child = await documentFile?.child(fileName);
if (child == null) {
documentFile?.createFileAsBytes(
mimeType: 'application/pdf ',
bytes: bytes,
displayName: fileName,
);
} else {
documentFile?.writeToFileAsBytes(
bytes: bytes,
mode: FileMode.write,
);
}
Utils.showToast("تم حفظ الملف بنجاح");
} else {
Utils.showToast("فشل حفظ الملف ، حاول مرة أخرى");
}
});
} catch (ex) {
print(ex);
Utils.hideLoading(context);
}
}
}
class PdfViewerScreen extends StatelessWidget {

@ -4,6 +4,7 @@ import 'dart:io';
import 'dart:math' as math;
import 'dart:typed_data';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:dotted_border/dotted_border.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
@ -12,6 +13,7 @@ import 'package:http/http.dart' as http;
import 'package:just_audio/just_audio.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:shared_storage/shared_storage.dart' as saf;
import 'package:tangheem/classes/colors.dart';
import 'package:tangheem/classes/consts.dart';
import 'package:tangheem/classes/utils.dart';
@ -185,7 +187,11 @@ class _AyaPlayerWidgetState extends State<AyaPlayerWidget> {
),
if (widget.voiceNoteList?.isNotEmpty ?? false)
commonIconButton("assets/icons/download_aya.svg", () async {
if (await _requestPermission()) {
if (Platform.isAndroid && (await DeviceInfoPlugin().androidInfo).version.sdkInt > 29) {
String filePath = widget.voiceNoteList[_player.currentIndex].exposeFilePath;
saveAudioToAboveAndroid32(filePath, "Tangheem-${widget.voiceNoteList[_player.currentIndex].userName ?? ""}-${widget.voiceNoteList[_player.currentIndex].fileName}",
widget.voiceNoteList[_player.currentIndex].fileType);
} else if (await _requestPermission()) {
saveToPhoneStorage(widget.voiceNoteList[_player.currentIndex].exposeFilePath, widget.voiceNoteList[_player.currentIndex].userName ?? "");
} else {
Utils.showToast("يجب اعطاء الاذن لتنزيل الآية");
@ -393,4 +399,49 @@ class _AyaPlayerWidgetState extends State<AyaPlayerWidget> {
onResponse(false);
});
}
void saveAudioToAboveAndroid32(String pathUrl, String fileName, String fileType) async {
List<saf.UriPermission> _persistedPermissionUris = await saf.persistedUriPermissions();
if (_persistedPermissionUris.isNotEmpty) {
saf.UriPermission permissionUri = _persistedPermissionUris.first;
startFileDownloadAboveAndroid32(pathUrl, fileName, permissionUri.uri, fileType);
} else {
Uri selectedDocumentUris = await saf.openDocumentTree();
if (selectedDocumentUris == null) return;
saveAudioToAboveAndroid32(pathUrl, fileName, fileType);
}
}
void startFileDownloadAboveAndroid32(String url, String fileName, Uri persistentUri, String fileType) async {
try {
Utils.showLoading(context);
//String path = await Utils.getStoragePath(fileName);
Utils.downloadFileAboveAndroid32(ApiConsts.baseUrl + url, "path", onResponse: (bytes) async {
Utils.hideLoading(context);
if (bytes.isNotEmpty) {
final documentFile = await persistentUri.toDocumentFile();
final child = await documentFile?.child(fileName);
if (child == null) {
documentFile?.createFileAsBytes(
mimeType: fileType,
bytes: bytes,
displayName: fileName,
);
} else {
documentFile?.writeToFileAsBytes(
bytes: bytes,
mode: FileMode.write,
);
}
Utils.showToast("تم حفظ الملف بنجاح");
} else {
Utils.showToast("فشل حفظ الملف ، حاول مرة أخرى");
}
});
} catch (ex) {
print(ex);
Utils.hideLoading(context);
}
}
}

@ -1,5 +1,6 @@
import 'dart:io';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:just_audio/just_audio.dart';
@ -7,9 +8,11 @@ import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:record_mp3/record_mp3.dart';
import 'package:tangheem/classes/colors.dart';
import 'package:tangheem/classes/consts.dart';
import 'package:tangheem/classes/utils.dart';
import 'package:tangheem/extensions/string_extensions.dart';
import 'package:tangheem/extensions/widget_extensions.dart';
import 'package:shared_storage/shared_storage.dart' as saf;
class AyaRecordWidget extends StatefulWidget {
AyaRecordWidget({Key key}) : super(key: key);
@ -219,7 +222,13 @@ class _AyaRecordWidgetState extends State<AyaRecordWidget> {
InkWell(
borderRadius: BorderRadius.circular(20),
onTap: () async {
if (await _requestStoragePermission()) {
if (Platform.isAndroid && (await DeviceInfoPlugin().androidInfo).version.sdkInt > 29) {
if (recordFilePath != null && File(recordFilePath).existsSync()) {
saveAudioToAboveAndroid32(recordFilePath, "Tangheem${DateTime.now().millisecondsSinceEpoch}.mp3", "audio/mpeg");
} else {
Utils.showToast("يجب عليك تسجيل صوتك أولا");
}
} else if (await _requestStoragePermission()) {
if (recordFilePath != null && File(recordFilePath).existsSync()) {
saveToPhoneStorage(recordFilePath);
} else {
@ -231,7 +240,7 @@ class _AyaRecordWidgetState extends State<AyaRecordWidget> {
},
child: Container(
height: 31,
width: 135,
width: 135,
padding: EdgeInsets.only(left: 12, right: 12),
alignment: Alignment.center,
decoration: BoxDecoration(
@ -321,4 +330,41 @@ class _AyaRecordWidgetState extends State<AyaRecordWidget> {
await file.copy(storagePath);
Utils.showToast("تم التنزيل");
}
void saveAudioToAboveAndroid32(String pathUrl, String fileName, String fileType) async {
List<saf.UriPermission> _persistedPermissionUris = await saf.persistedUriPermissions();
if (_persistedPermissionUris.isNotEmpty) {
saf.UriPermission permissionUri = _persistedPermissionUris.first;
startFileAboveAndroid32(pathUrl, fileName, permissionUri.uri, fileType);
} else {
Uri selectedDocumentUris = await saf.openDocumentTree();
if (selectedDocumentUris == null) return;
saveAudioToAboveAndroid32(pathUrl, fileName, fileType);
}
}
void startFileAboveAndroid32(String filePath, String fileName, Uri persistentUri, String fileType) async {
try {
File file = File(filePath);
final documentFile = await persistentUri.toDocumentFile();
final child = await documentFile?.child(fileName);
if (child == null) {
documentFile?.createFileAsBytes(
mimeType: fileType,
bytes: file.readAsBytesSync(),
displayName: fileName,
);
} else {
documentFile?.writeToFileAsBytes(
bytes: file.readAsBytesSync(),
mode: FileMode.write,
);
}
Utils.showToast("تم حفظ الملف بنجاح");
} catch (ex) {
print(ex);
Utils.hideLoading(context);
}
}
}

@ -54,6 +54,9 @@ dependencies:
flutter_html: ^2.2.1
flutter_inappwebview: ^5.7.2+3
dotted_border: ^2.0.0+1
device_info_plus: ^6.0.0
shared_storage: ^0.7.1
dev_dependencies:
flutter_test:
sdk: flutter

Loading…
Cancel
Save