Remove reliance on WRITE_EXTERNAL_STORAGE
https://developer.android.com/about/versions/11/privacy/storage#permissions-target-11
This commit is contained in:
parent
bfc1b3d546
commit
5e34bd4570
|
@ -478,7 +478,7 @@ export default function SettingsPage() {
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: `Backup directory: ${backupString || "Downloads"}`,
|
name: `Backup directory: ${backupString || "Not set yet!"}`,
|
||||||
renderItem: (name: string) => (
|
renderItem: (name: string) => (
|
||||||
<Button
|
<Button
|
||||||
style={{ alignSelf: "flex-start" }}
|
style={{ alignSelf: "flex-start" }}
|
||||||
|
@ -522,15 +522,15 @@ export default function SettingsPage() {
|
||||||
<Button
|
<Button
|
||||||
style={{ alignSelf: "flex-start" }}
|
style={{ alignSelf: "flex-start" }}
|
||||||
onPress={async () => {
|
onPress={async () => {
|
||||||
const result = await check(
|
let target = settings.backupDir
|
||||||
PERMISSIONS.ANDROID.WRITE_EXTERNAL_STORAGE
|
if (!FileSystem.exists(target)) {
|
||||||
);
|
const result = await DocumentPicker.pickDirectory();
|
||||||
if (result === RESULTS.DENIED || result === RESULTS.BLOCKED) {
|
target = result.uri
|
||||||
await request(PERMISSIONS.ANDROID.WRITE_EXTERNAL_STORAGE);
|
setValue("backupDir", result.uri);
|
||||||
}
|
}
|
||||||
const path = Dirs.DatabaseDir + "/massive.db";
|
const error = await NativeModules.BackupModule.once(target);
|
||||||
await FileSystem.cpExternal(path, "massive.db", "downloads");
|
if (error) toast(error);
|
||||||
toast("Database exported. Check downloads.");
|
else toast("Database exported.");
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{name}
|
{name}
|
||||||
|
@ -543,13 +543,13 @@ export default function SettingsPage() {
|
||||||
<Button
|
<Button
|
||||||
style={{ alignSelf: "flex-start" }}
|
style={{ alignSelf: "flex-start" }}
|
||||||
onPress={async () => {
|
onPress={async () => {
|
||||||
const result = await check(
|
let target = settings.backupDir
|
||||||
PERMISSIONS.ANDROID.WRITE_EXTERNAL_STORAGE
|
if (!target || !FileSystem.exists(target)) {
|
||||||
);
|
const result = await DocumentPicker.pickDirectory();
|
||||||
if (result === RESULTS.DENIED || result === RESULTS.BLOCKED) {
|
target = result.uri
|
||||||
await request(PERMISSIONS.ANDROID.WRITE_EXTERNAL_STORAGE);
|
setValue("backupDir", result.uri);
|
||||||
}
|
}
|
||||||
await NativeModules.BackupModule.exportToCSV();
|
await NativeModules.BackupModule.exportToCSV(target);
|
||||||
toast("Exported sets as CSV.");
|
toast("Exported sets as CSV.");
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||||
<uses-permission android:name="android.permission.VIBRATE" />
|
<uses-permission android:name="android.permission.VIBRATE" />
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
|
||||||
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
|
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
|
||||||
<uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />
|
<uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||||
|
|
|
@ -7,7 +7,6 @@ import android.content.*
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.annotation.RequiresApi
|
|
||||||
import androidx.documentfile.provider.DocumentFile
|
import androidx.documentfile.provider.DocumentFile
|
||||||
import com.facebook.react.bridge.Promise
|
import com.facebook.react.bridge.Promise
|
||||||
import com.facebook.react.bridge.ReactApplicationContext
|
import com.facebook.react.bridge.ReactApplicationContext
|
||||||
|
@ -22,7 +21,6 @@ class BackupModule(context: ReactApplicationContext?) :
|
||||||
val context: ReactApplicationContext = reactApplicationContext
|
val context: ReactApplicationContext = reactApplicationContext
|
||||||
|
|
||||||
private val copyReceiver = object : BroadcastReceiver() {
|
private val copyReceiver = object : BroadcastReceiver() {
|
||||||
@RequiresApi(Build.VERSION_CODES.O)
|
|
||||||
override fun onReceive(context: Context?, intent: Intent?) {
|
override fun onReceive(context: Context?, intent: Intent?) {
|
||||||
val targetDir = intent?.getStringExtra("targetDir")
|
val targetDir = intent?.getStringExtra("targetDir")
|
||||||
Log.d("BackupModule", "onReceive $targetDir")
|
Log.d("BackupModule", "onReceive $targetDir")
|
||||||
|
@ -40,7 +38,28 @@ class BackupModule(context: ReactApplicationContext?) :
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.M)
|
@ReactMethod
|
||||||
|
fun once(target: String, promise: Promise) {
|
||||||
|
Log.d("BackupModule", "once $target")
|
||||||
|
try {
|
||||||
|
val treeUri: Uri = Uri.parse(target)
|
||||||
|
val documentFile = context.let { DocumentFile.fromTreeUri(it, treeUri) }
|
||||||
|
val file = documentFile?.createFile("application/octet-stream", "massive.db")
|
||||||
|
val output = context.contentResolver?.openOutputStream(file!!.uri)
|
||||||
|
val sourceFile = File(context.getDatabasePath("massive.db")!!.path)
|
||||||
|
val input = FileInputStream(sourceFile)
|
||||||
|
if (output != null) {
|
||||||
|
input.copyTo(output)
|
||||||
|
}
|
||||||
|
output?.flush()
|
||||||
|
output?.close()
|
||||||
|
promise.resolve(0)
|
||||||
|
}
|
||||||
|
catch (error: Exception) {
|
||||||
|
promise.reject("ERROR", error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ReactMethod
|
@ReactMethod
|
||||||
fun start(baseUri: String) {
|
fun start(baseUri: String) {
|
||||||
Log.d("BackupModule", "start $baseUri")
|
Log.d("BackupModule", "start $baseUri")
|
||||||
|
@ -66,7 +85,6 @@ class BackupModule(context: ReactApplicationContext?) :
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.M)
|
|
||||||
@ReactMethod(isBlockingSynchronousMethod = true)
|
@ReactMethod(isBlockingSynchronousMethod = true)
|
||||||
fun stop() {
|
fun stop() {
|
||||||
val alarmMgr = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
val alarmMgr = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
||||||
|
@ -77,10 +95,10 @@ class BackupModule(context: ReactApplicationContext?) :
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactMethod
|
@ReactMethod
|
||||||
fun exportToCSV(promise: Promise) {
|
fun exportToCSV(target: String, promise: Promise) {
|
||||||
try {
|
try {
|
||||||
val db = DatabaseHelper(reactApplicationContext)
|
val db = DatabaseHelper(reactApplicationContext)
|
||||||
db.exportToCSV()
|
db.exportToCSV(target, reactApplicationContext)
|
||||||
promise.resolve("Export successful!")
|
promise.resolve("Export successful!")
|
||||||
}
|
}
|
||||||
catch (e: Exception) {
|
catch (e: Exception) {
|
||||||
|
|
|
@ -3,7 +3,10 @@ package com.massive
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.database.sqlite.SQLiteDatabase
|
import android.database.sqlite.SQLiteDatabase
|
||||||
import android.database.sqlite.SQLiteOpenHelper
|
import android.database.sqlite.SQLiteOpenHelper
|
||||||
|
import android.net.Uri
|
||||||
import android.os.Environment
|
import android.os.Environment
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.documentfile.provider.DocumentFile
|
||||||
import com.opencsv.CSVWriter
|
import com.opencsv.CSVWriter
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileWriter
|
import java.io.FileWriter
|
||||||
|
@ -15,30 +18,29 @@ class DatabaseHelper(context: Context) :
|
||||||
private const val DATABASE_VERSION = 1
|
private const val DATABASE_VERSION = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
fun exportToCSV() {
|
fun exportToCSV(target: String, context: Context) {
|
||||||
val exportDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
|
Log.d("DatabaseHelper", "exportToCSV $target")
|
||||||
if (!exportDir.exists()) {
|
val treeUri: Uri = Uri.parse(target)
|
||||||
exportDir.mkdirs()
|
val documentFile = context.let { DocumentFile.fromTreeUri(it, treeUri) }
|
||||||
}
|
val file = documentFile?.createFile("application/octet-stream", "sets.csv") ?: return
|
||||||
|
|
||||||
val file = File(exportDir, "gym_sets.csv")
|
context.contentResolver.openOutputStream(file.uri).use { outputStream ->
|
||||||
file.createNewFile()
|
val csvWrite = CSVWriter(outputStream?.writer())
|
||||||
|
val db = this.readableDatabase
|
||||||
|
val cursor = db.rawQuery("SELECT * FROM sets", null)
|
||||||
|
csvWrite.writeNext(cursor.columnNames)
|
||||||
|
|
||||||
val csvWrite = CSVWriter(FileWriter(file))
|
while(cursor.moveToNext()) {
|
||||||
val db = this.readableDatabase
|
val arrStr = arrayOfNulls<String>(cursor.columnCount)
|
||||||
val cursor = db.rawQuery("SELECT * FROM sets", null)
|
for(i in 0 until cursor.columnCount) {
|
||||||
csvWrite.writeNext(cursor.columnNames)
|
arrStr[i] = cursor.getString(i)
|
||||||
|
}
|
||||||
while(cursor.moveToNext()) {
|
csvWrite.writeNext(arrStr)
|
||||||
val arrStr = arrayOfNulls<String>(cursor.columnCount)
|
|
||||||
for(i in 0 until cursor.columnCount) {
|
|
||||||
arrStr[i] = cursor.getString(i)
|
|
||||||
}
|
}
|
||||||
csvWrite.writeNext(arrStr)
|
|
||||||
}
|
|
||||||
|
|
||||||
csvWrite.close()
|
csvWrite.close()
|
||||||
cursor.close()
|
cursor.close()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreate(db: SQLiteDatabase) {
|
override fun onCreate(db: SQLiteDatabase) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user