Choose directory when backing up automatically - 1.135

Related to #146.
This commit is contained in:
Brandon Presley 2023-03-27 14:29:12 +13:00
parent 2fb46e1dcc
commit 76e5aeacfd
6 changed files with 55 additions and 50 deletions

View File

@ -6,6 +6,7 @@ import {NativeModules, ScrollView, View} from 'react-native'
import DocumentPicker from 'react-native-document-picker' import DocumentPicker from 'react-native-document-picker'
import {Dirs, FileSystem} from 'react-native-file-access' import {Dirs, FileSystem} from 'react-native-file-access'
import {Button, Subheading} from 'react-native-paper' import {Button, Subheading} from 'react-native-paper'
import {PERMISSIONS, request} from 'react-native-permissions'
import ConfirmDialog from './ConfirmDialog' import ConfirmDialog from './ConfirmDialog'
import {ITEM_PADDING, MARGIN} from './constants' import {ITEM_PADDING, MARGIN} from './constants'
import {AppDataSource} from './data-source' import {AppDataSource} from './data-source'
@ -134,8 +135,14 @@ export default function SettingsPage() {
return return
case 'backup': case 'backup':
if (value) { if (value) {
const granted = await request(
PERMISSIONS.ANDROID.WRITE_EXTERNAL_STORAGE,
)
if (!granted) return
const result = await DocumentPicker.pickDirectory()
console.log(result.uri)
toast('Backup database daily.') toast('Backup database daily.')
NativeModules.BackupModule.start() NativeModules.BackupModule.start(result.uri)
} else { } else {
toast('Stopped backing up daily') toast('Stopped backing up daily')
NativeModules.BackupModule.stop() NativeModules.BackupModule.stop()

View File

@ -41,8 +41,8 @@ android {
missingDimensionStrategy "RNNotifications.reactNativeVersion", "reactNative60" missingDimensionStrategy "RNNotifications.reactNativeVersion", "reactNative60"
minSdkVersion rootProject.ext.minSdkVersion minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 36160 versionCode 36161
versionName "1.134" versionName "1.135"
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString() buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
if (isNewArchitectureEnabled()) { if (isNewArchitectureEnabled()) {

View File

@ -1,75 +1,44 @@
package com.massive package com.massive
import android.Manifest
import android.app.AlarmManager import android.app.AlarmManager
import android.app.PendingIntent import android.app.PendingIntent
import android.content.BroadcastReceiver import android.content.*
import android.content.Context import android.net.Uri
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.PackageManager
import android.os.Build import android.os.Build
import android.os.Environment
import android.widget.Toast
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import androidx.core.app.ActivityCompat import androidx.documentfile.provider.DocumentFile
import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.bridge.ReactContextBaseJavaModule import com.facebook.react.bridge.ReactContextBaseJavaModule
import com.facebook.react.bridge.ReactMethod import com.facebook.react.bridge.ReactMethod
import java.io.File import java.io.*
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.IOException
import java.util.* import java.util.*
class BackupModule constructor(context: ReactApplicationContext?) : class BackupModule constructor(context: ReactApplicationContext?) :
ReactContextBaseJavaModule(context) { ReactContextBaseJavaModule(context) {
val context: ReactApplicationContext = reactApplicationContext val context: ReactApplicationContext = reactApplicationContext
private var targetDir: String? = null
private val copyReceiver = object : BroadcastReceiver() { private val copyReceiver = object : BroadcastReceiver() {
@RequiresApi(Build.VERSION_CODES.O) @RequiresApi(Build.VERSION_CODES.O)
override fun onReceive(context: Context?, intent: Intent?) { override fun onReceive(context: Context?, intent: Intent?) {
val treeUri: Uri = Uri.parse(targetDir)
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 sourceFile = File(context?.getDatabasePath("massive.db")!!.path)
val targetDir = val input = FileInputStream(sourceFile)
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) if (output != null) {
val targetFile = File(targetDir, "massive.db")
try {
val input = FileInputStream(sourceFile)
val output = FileOutputStream(targetFile)
input.copyTo(output) input.copyTo(output)
input.close()
output.close()
} catch (e: IOException) {
Toast.makeText(
reactApplicationContext,
"Access to massive.db is denied. Try deleting it first.",
Toast.LENGTH_LONG
).show()
} }
output?.flush()
output?.close()
} }
} }
@RequiresApi(Build.VERSION_CODES.M) @RequiresApi(Build.VERSION_CODES.M)
@ReactMethod @ReactMethod
fun start() { fun start(baseUri: String) {
val permission: Int = targetDir = baseUri
ActivityCompat.checkSelfPermission(
reactApplicationContext,
Manifest.permission.WRITE_EXTERNAL_STORAGE
)
if (permission != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(
currentActivity!!,
arrayOf<String>(
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
),
1
)
}
val alarmMgr = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager val alarmMgr = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
val intent = Intent(COPY_BROADCAST) val intent = Intent(COPY_BROADCAST)
val pendingIntent = val pendingIntent =

View File

@ -11,6 +11,7 @@ NativeModules.SettingsModule = NativeModules.SettingsModule || {
jest.mock('react-native-file-access', () => jest.fn()) jest.mock('react-native-file-access', () => jest.fn())
jest.mock('react-native-share', () => jest.fn()) jest.mock('react-native-share', () => jest.fn())
jest.mock('react-native-permissions', () => jest.fn())
jest.mock('react-native/Libraries/Animated/NativeAnimatedHelper') jest.mock('react-native/Libraries/Animated/NativeAnimatedHelper')
jest.mock('react-native/Libraries/EventEmitter/NativeEventEmitter') jest.mock('react-native/Libraries/EventEmitter/NativeEventEmitter')

View File

@ -1,6 +1,6 @@
{ {
"name": "massive", "name": "massive",
"version": "1.134", "version": "1.135",
"private": true, "private": true,
"license": "GPL-3.0-only", "license": "GPL-3.0-only",
"scripts": { "scripts": {
@ -39,6 +39,7 @@
"react-native-linear-gradient": "^2.6.2", "react-native-linear-gradient": "^2.6.2",
"react-native-pager-view": "^6.0.1", "react-native-pager-view": "^6.0.1",
"react-native-paper": "^4.12.5", "react-native-paper": "^4.12.5",
"react-native-permissions": "^3.8.0",
"react-native-reanimated": "^2.12.0", "react-native-reanimated": "^2.12.0",
"react-native-safe-area-context": "^4.4.1", "react-native-safe-area-context": "^4.4.1",
"react-native-screens": "^3.18.2", "react-native-screens": "^3.18.2",

View File

@ -7313,6 +7313,7 @@ __metadata:
react-native-linear-gradient: ^2.6.2 react-native-linear-gradient: ^2.6.2
react-native-pager-view: ^6.0.1 react-native-pager-view: ^6.0.1
react-native-paper: ^4.12.5 react-native-paper: ^4.12.5
react-native-permissions: ^3.8.0
react-native-reanimated: ^2.12.0 react-native-reanimated: ^2.12.0
react-native-safe-area-context: ^4.4.1 react-native-safe-area-context: ^4.4.1
react-native-screens: ^3.18.2 react-native-screens: ^3.18.2
@ -8592,6 +8593,15 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"pkg-dir@npm:^5.0.0":
version: 5.0.0
resolution: "pkg-dir@npm:5.0.0"
dependencies:
find-up: ^5.0.0
checksum: b167bb8dac7bbf22b1d5e30ec223e6b064b84b63010c9d49384619a36734caf95ed23ad23d4f9bd975e8e8082b60a83395f43a89bb192df53a7c25a38ecb57d9
languageName: node
linkType: hard
"posix-character-classes@npm:^0.1.0": "posix-character-classes@npm:^0.1.0":
version: 0.1.1 version: 0.1.1
resolution: "posix-character-classes@npm:0.1.1" resolution: "posix-character-classes@npm:0.1.1"
@ -8898,6 +8908,23 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"react-native-permissions@npm:^3.8.0":
version: 3.8.0
resolution: "react-native-permissions@npm:3.8.0"
dependencies:
picocolors: ^1.0.0
pkg-dir: ^5.0.0
peerDependencies:
react: ">=16.13.1"
react-native: ">=0.63.3"
react-native-windows: ">=0.62.0"
peerDependenciesMeta:
react-native-windows:
optional: true
checksum: acbd8605adabfc48e19fbc468a3a143fb85bd34d3ed0fe6a4b52f16304591b8a4b3c561a507c11643fcc8ce1b4dc09e31f149387d1ea461098a2e40c43989f7c
languageName: node
linkType: hard
"react-native-reanimated@npm:^2.12.0": "react-native-reanimated@npm:^2.12.0":
version: 2.12.0 version: 2.12.0
resolution: "react-native-reanimated@npm:2.12.0" resolution: "react-native-reanimated@npm:2.12.0"