Commit fa89f65
Changed files (8)
app
android
app
src
main
kotlin
com
derdilla
blood_pressure_app
lib
features
export_import
platform_integration
app/android/app/src/main/kotlin/com/derdilla/blood_pressure_app/MainActivity.kt
@@ -8,10 +8,5 @@ import java.io.File
class MainActivity: FlutterActivity() {
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
- val shareFolder = File(context.cacheDir, "share")
- if (shareFolder.exists()) shareFolder.deleteRecursively();
-
- MethodChannel(flutterEngine.dartExecutor.binaryMessenger, StorageProvider.CHANNEL)
- .setMethodCallHandler(StorageProvider(context, shareFolder))
}
}
app/android/app/src/main/kotlin/com/derdilla/blood_pressure_app/StorageProvider.kt
@@ -1,87 +0,0 @@
-package com.derdilla.blood_pressure_app
-
-import android.content.Context
-import android.content.Intent
-import android.net.Uri
-import androidx.core.content.ContextCompat.startActivity
-import androidx.core.content.FileProvider.getUriForFile
-import io.flutter.plugin.common.MethodCall
-import io.flutter.plugin.common.MethodChannel
-import java.io.File
-
-class StorageProvider(private var context: Context,
- private var shareFolder: File
- ): MethodChannel.MethodCallHandler {
- companion object {
- const val CHANNEL = "bloodPressureApp.derdilla.com/storage"
- }
-
- override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
- when (call.method) {
- "shareFile" -> shareFile(call.argument<String>("path")!!,
- call.argument<String>("mimeType")!!, call.argument<String>("name"))
- "shareData" -> shareData(call.argument<ByteArray>("data")!!,
- call.argument<String>("mimeType")!!, call.argument<String>("name")!!)
- }
- }
-
- /**
- * Show the share sheet for saving a file.
- *
- * @param path The path to the file in internal storage
- * @param mimeType The mime type that gets send with the intend
- * @param name Used to make the name of the shared file different from the original name.
- */
- private fun shareFile(path: String, mimeType: String, name: String?) {
- val uri = sharableUriFromPath(path, name)
-
- val sendIntent: Intent = Intent().apply {
- action = Intent.ACTION_SEND
- putExtra(Intent.EXTRA_STREAM, uri)
- type = mimeType
- }
-
- val shareIntent = Intent.createChooser(sendIntent, null)
- startActivity(context, shareIntent, null)
- }
-
- /**
- * Create a file from data and show start Intent to show a share sheet.
- *
- * @param data The data that gets shared
- * @param mimeType The mime type that gets send with the intend
- * @param name The name of the shared file
- */
- private fun shareData(data: ByteArray, mimeType: String, name: String) {
- val uri = sharableUriFromData(data, name)
-
- val sendIntent: Intent = Intent().apply {
- action = Intent.ACTION_SEND
- putExtra(Intent.EXTRA_STREAM, uri)
- type = mimeType
- }
-
- val shareIntent = Intent.createChooser(sendIntent, null)
- startActivity(context, shareIntent, null)
- }
-
-
- private fun sharableUriFromPath(path: String, name: String?): Uri {
- val initialFile = File(path)
- if (!initialFile.exists()) throw IllegalArgumentException("Tried to create URI from nonexistent file")
-
- val sharablePath = File(shareFolder, name ?: initialFile.name)
- if (sharablePath.exists()) sharablePath.delete()
- initialFile.copyTo(sharablePath)
- return getUriForFile(context, "com.derdilla.bloodPressureApp.share", sharablePath)
- }
-
- private fun sharableUriFromData(data: ByteArray, name: String): Uri {
- if (!shareFolder.exists()) shareFolder.mkdirs()
- val sharablePath = File(shareFolder, name)
- if (sharablePath.exists()) sharablePath.delete()
- sharablePath.createNewFile()
- sharablePath.writeBytes(data)
- return getUriForFile(context, "com.derdilla.bloodPressureApp.share", sharablePath)
- }
-}
\ No newline at end of file
app/android/app/src/main/AndroidManifest.xml
@@ -55,15 +55,5 @@
<meta-data
android:name="flutterEmbedding"
android:value="2" />
- <provider
- android:name="com.derdilla.blood_pressure_app.FileSharer"
- android:authorities="com.derdilla.bloodPressureApp.share"
- android:exported="false"
- android:grantUriPermissions="true">
- <meta-data
- android:name="android.support.FILE_PROVIDER_PATHS"
- android:resource="@xml/file_paths" />
- </provider>
-
</application>
</manifest>
app/lib/platform_integration/platform_client.dart
@@ -1,68 +0,0 @@
-import 'package:flutter/services.dart';
-
-/// Class that hosts platform specific functions for sharing files, loading files, saving files and asking for
-/// directory permissions.
-///
-/// Steps for expanding this class:
-/// - If the purpose of the class is not related to storage create a new class with a different [_platformChannel] path.
-/// - Open the android folder in Android Studio.
-/// - Implement the new method in `StorageProvider.kt`.
-/// - Add method name and arguments as a condition to the `onMethodCall` in the same class.
-/// - Implement a helper function to this class that calls uses the platform channel (like [shareFile]).
-class PlatformClient {
-
- PlatformClient._create();
- /// Platform channel for sharing files, loading files, saving files and asking for directory permissions.
- static const _platformChannel = MethodChannel('bloodPressureApp.derdilla.com/storage');
-
- /// Share a file from application storage.
- ///
- /// The file present at the [path] specified will be copied to a sharable location. The file in the sharable location
- /// will be shared with the specified [mimeType] through a
- /// [Android Sharesheet](https://developer.android.com/training/sharing/send#using-android-system-sharesheet).
- ///
- /// The [mimeType] can be any string but should generally follow the `*/*` pattern. All official mime types can be
- /// found here: https://mimetype.io/all-types
- ///
- /// When [name] is set to a non-null value the file will be shared with this name instead of the original file name.
- ///
- /// The returned value indicates whether a [PlatformException] was thrown.
- static Future<bool> shareFile(String path, String mimeType, [String? name]) async {
- try {
- await _platformChannel.invokeMethod('shareFile', {
- 'path': path,
- 'mimeType': mimeType,
- 'name': name,
- });
- return true;
- } on PlatformException {
- return false;
- }
- }
-
- /// Share binary data like a file.
- ///
- /// A file with the [data] will be created and shared with the specified [mimeType] through a
- /// [Android Sharesheet](https://developer.android.com/training/sharing/send#using-android-system-sharesheet).
- ///
- /// The [mimeType] can be any string but should generally follow the `*/*` pattern. All official mime types can be
- /// found here: https://mimetype.io/all-types
- ///
- /// The resulting file name is specified by [name].
- ///
- /// The returned value indicates whether a [PlatformException] was thrown.
- ///
- /// Using this over [shareFile] is more saves a file copy, when the data is present as binary data but not as a file.
- static Future<bool> shareData(Uint8List data, String mimeType, String name) async {
- try {
- await _platformChannel.invokeMethod('shareData', {
- 'data': data,
- 'mimeType': mimeType,
- 'name': name,
- });
- return true;
- } on PlatformException {
- return false;
- }
- }
-}
app/lib/screens/error_reporting_screen.dart
@@ -1,4 +1,6 @@
-import 'package:blood_pressure_app/platform_integration/platform_client.dart';
+import 'dart:io';
+
+import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:package_info_plus/package_info_plus.dart';
@@ -107,7 +109,11 @@ class ErrorScreen extends StatelessWidget {
assert(dbPath != inMemoryDatabasePath);
dbPath = join(dbPath, 'blood_pressure.db');
- await PlatformClient.shareFile(dbPath, 'application/vnd.sqlite3');
+ await FilePicker.platform.saveFile(
+ fileName: 'blood_pressure.db',
+ bytes: File(dbPath).readAsBytesSync(),
+ type: FileType.any, // application/vnd.sqlite3
+ );
} catch(e) {
scaffoldMessenger.showSnackBar(SnackBar(
content: Text('ERR: $e'),),);
@@ -122,7 +128,12 @@ class ErrorScreen extends StatelessWidget {
assert(dbPath != inMemoryDatabasePath);
dbPath = join(dbPath, 'config.db');
- await PlatformClient.shareFile(dbPath, 'application/vnd.sqlite3');
+
+ await FilePicker.platform.saveFile(
+ fileName: 'config.db',
+ bytes: File(dbPath).readAsBytesSync(),
+ type: FileType.any, // application/vnd.sqlite3
+ );
} catch(e) {
scaffoldMessenger.showSnackBar(SnackBar(
content: Text('ERR: $e'),),);
@@ -137,7 +148,11 @@ class ErrorScreen extends StatelessWidget {
assert(dbPath != inMemoryDatabasePath);
dbPath = join(dbPath, 'medicine.intakes');
- await PlatformClient.shareFile(dbPath, 'application/octet-stream');
+ await FilePicker.platform.saveFile(
+ fileName: 'medicine.intakes',
+ bytes: File(dbPath).readAsBytesSync(),
+ type: FileType.any, // application/octet-stream
+ );
} catch(e) {
scaffoldMessenger.showSnackBar(SnackBar(
content: Text('ERR: $e'),),);
@@ -152,7 +167,11 @@ class ErrorScreen extends StatelessWidget {
assert(dbPath != inMemoryDatabasePath);
dbPath = join(dbPath, 'bp.db');
- await PlatformClient.shareFile(dbPath, 'application/vnd.sqlite3');
+ await FilePicker.platform.saveFile(
+ fileName: 'bp.db',
+ bytes: File(dbPath).readAsBytesSync(),
+ type: FileType.any, // application/vnd.sqlite3
+ );
} catch(e) {
scaffoldMessenger.showSnackBar(SnackBar(
content: Text('ERR: $e'),),);
app/lib/screens/settings_screen.dart
@@ -3,7 +3,6 @@ import 'dart:typed_data';
import 'package:archive/archive_io.dart';
import 'package:blood_pressure_app/components/input_dialoge.dart';
-import 'package:blood_pressure_app/config.dart';
import 'package:blood_pressure_app/data_util/consistent_future_builder.dart';
import 'package:blood_pressure_app/features/settings/delete_data_screen.dart';
import 'package:blood_pressure_app/features/settings/enter_timeformat_dialoge.dart';
@@ -28,7 +27,6 @@ import 'package:blood_pressure_app/model/storage/db/settings_loader.dart';
import 'package:blood_pressure_app/model/storage/export_columns_store.dart';
import 'package:blood_pressure_app/model/storage/storage.dart';
import 'package:blood_pressure_app/model/weight_unit.dart';
-import 'package:blood_pressure_app/platform_integration/platform_client.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
@@ -354,7 +352,11 @@ class SettingsPage extends StatelessWidget {
return;
}
final archiveData = Uint8List.fromList(compressedArchive);
- await PlatformClient.shareData(archiveData, 'application/zip', 'bloodPressureSettings.zip');
+ await FilePicker.platform.saveFile(
+ type: FileType.any, // application/zip
+ fileName: 'bloodPressureSettings.zip',
+ bytes: archiveData,
+ );
},
),
ListTile(