Add ExportModule

It is writing the exported sets.csv correctly,
however afterwards the device has no access to
any files on it's system anymore.
This commit is contained in:
Brandon Presley 2022-07-05 17:42:48 +12:00
parent 6581b32afe
commit 76e6ffbc25
8 changed files with 113 additions and 4 deletions

View File

@ -6,7 +6,7 @@ import {
NavigationContainer,
} from '@react-navigation/native';
import React, {useEffect} from 'react';
import {StatusBar, useColorScheme} from 'react-native';
import {NativeModules, StatusBar, useColorScheme} from 'react-native';
import {setupSchema} from './db';
import Exercises from './Exercises';
import Home from './Home';
@ -28,6 +28,7 @@ const App = () => {
AsyncStorage.getItem('minutes').then(async minutes => {
if (!minutes) await AsyncStorage.setItem('minutes', '3');
});
console.log(NativeModules.ExportModule.sets());
}, []);
return (

View File

@ -5,6 +5,7 @@
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:name=".MainApplication"

View File

@ -0,0 +1,86 @@
package com.massive
import android.annotation.SuppressLint
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Intent
import android.os.Build
import android.os.Environment
import android.provider.DocumentsContract
import android.util.Log
import androidx.annotation.RequiresApi
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.bridge.ReactContextBaseJavaModule
import com.facebook.react.bridge.ReactMethod
import okhttp3.internal.notify
import java.io.File
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
class ExportModule internal constructor(context: ReactApplicationContext?) :
ReactContextBaseJavaModule(context) {
override fun getName(): String {
return "ExportModule"
}
@RequiresApi(Build.VERSION_CODES.O)
@SuppressLint("Recycle", "Range")
@ReactMethod(isBlockingSynchronousMethod = true)
fun sets(): String {
Log.d("ExportModule", "Exporting sets...")
val dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
val current = LocalDateTime.now()
val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd")
val formatted = current.format(formatter)
val sets = File(dir, "sets$formatted.csv")
sets.createNewFile()
sets.setWritable(true)
sets.setReadable(true)
sets.writeText("id,name,reps,weight,created,unit\n")
val db = MassiveHelper(reactApplicationContext).readableDatabase
db.use {
with (it.query("sets", null, null, null, null, null, null)) {
while (moveToNext()) {
val id = getInt(getColumnIndex("id"))
val name = getString(getColumnIndex("name"))
val reps = getInt(getColumnIndex("reps"))
val weight = getInt(getColumnIndex("weight"))
val created = getString(getColumnIndex("created"))
val unit = getString(getColumnIndex("unit"))
sets.appendText("$id,$name,$reps,$weight,$created,$unit\n")
}
}
}
val notificationManager = NotificationManagerCompat.from(reactApplicationContext)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val importance = NotificationManager.IMPORTANCE_LOW
val channel = NotificationChannel(CHANNEL_ID, CHANNEL_ID, importance)
channel.description = "Alarms for rest timings."
notificationManager.createNotificationChannel(channel)
}
val contentIntent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
addCategory(Intent.CATEGORY_OPENABLE)
type = "text/csv"
}
val pendingContent =
PendingIntent.getActivity(reactApplicationContext, 0, contentIntent, PendingIntent.FLAG_IMMUTABLE)
val builder = NotificationCompat.Builder(reactApplicationContext, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_baseline_arrow_downward_24)
.setContentTitle("Downloaded sets")
.setContentIntent(pendingContent)
.setAutoCancel(true)
notificationManager.notify(NOTIFICATION_ID, builder.build())
return sets.absolutePath
}
companion object {
private const val CHANNEL_ID = "Exports"
private const val NOTIFICATION_ID = 2
}
}

View File

@ -18,7 +18,7 @@ class MainApplication : Application(), ReactApplication {
override fun getPackages(): List<ReactPackage> {
val packages: MutableList<ReactPackage> = PackageList(this).packages
packages.add(SQLitePluginPackage())
packages.add(AlarmPackage())
packages.add(MassivePackage())
return packages
}

View File

@ -0,0 +1,15 @@
package com.massive
import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
class MassiveHelper(context: Context) : SQLiteOpenHelper(context, "massive.db", null, 1) {
override fun onCreate(db: SQLiteDatabase) {
return
}
override fun onUpgrade(p0: SQLiteDatabase?, p1: Int, p2: Int) {
return
}
}

View File

@ -7,7 +7,7 @@ import com.facebook.react.uimanager.ViewManager
import com.massive.AlarmModule
import java.util.ArrayList
class AlarmPackage : ReactPackage {
class MassivePackage : ReactPackage {
override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
return emptyList()
}
@ -17,6 +17,7 @@ class AlarmPackage : ReactPackage {
): List<NativeModule> {
val modules: MutableList<NativeModule> = ArrayList()
modules.add(AlarmModule(reactContext))
modules.add(ExportModule(reactContext))
return modules
}
}

View File

@ -86,7 +86,7 @@ class TimerService : Service() {
}
companion object {
private const val CHANNEL_ID = "MassiveAlarm"
private const val CHANNEL_ID = "Alarms"
private const val ALARM_ID = 1
}
}

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#000000"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M20,12l-1.41,-1.41L13,16.17V4h-2v12.17l-5.58,-5.59L4,12l8,8 8,-8z"/>
</vector>