birday icon indicating copy to clipboard operation
birday copied to clipboard

Export functionality using file dialog

Open Jogi04 opened this issue 2 years ago • 9 comments

Hi,

I really like the simplicity and the look and feel of the app. But I miss the feature to export the events using a file dialog so that you can save the backup file wherever you want. On my device (Samsung A71, Android 12) I'm unable to locate the backup file in Android/data/com.minar.birday/files since the folder com.minar.birday doesn't exist in Android/data.

Thank you very much for your dedication to this awesome project!

Jogi04 avatar Aug 10 '22 11:08 Jogi04

@Jogi123 Actually it's the normal behavior; after Android 11 update, preloaded My Files app doesn't show files and folders within 'android/data'. (due to access permissions) As a workaround, you can use a third party file manager to access the location and copy the files into anywhere you want.

I agree with you - If we can save the export file in a specific location it would be great though...

Dilshan-H avatar Aug 19 '22 04:08 Dilshan-H

When i wrote the export function, i wasn't able to provide such feature, but i agree that it could be useful and more user friendly. I'll see what i can do ;)

m-i-n-a-r avatar Aug 19 '22 13:08 m-i-n-a-r

@Dilshan-H Sorry, my bad. Thanks for the advice! @m-i-n-a-r Thank you for your quick answer!

Jogi04 avatar Aug 20 '22 19:08 Jogi04

I also use a Samsung phone and cannot access the data folder with the default file manager. However, when you export the backup, a share dialog should pop up. The options will vary based on the device and the apps you use, but it may even have an option to save the file wherever you want. Mine, of course, doesn't. So the easiest solution for me personally is to send the file to my computer using KDE Connect and back to my phone so it ends up in my Downloads folder, which is accessible using conventional means.

Is it ideal? Nope. Will most people find it practical to do the same? Nope. Can it be fixed in the app? Super nope. This up to Android and Samsung to fix.

DominikNovosel avatar Nov 13 '22 20:11 DominikNovosel

Yep, i agree. I always tend let the OS work instead of writing features in the app from scratch (and that's what Goole suggest normally, since Android is becoming really restrictive regarding privacy, see the need to ask for a permission to send notifications 😵‍💫 ). This means that to avoid asking additional permissions and follow the scoped storage principle, the backup is saved in that folder and shared afterwards. Same story for the app language (selectable from settings in Android 13+), the notification sound, the battery optimization disabling process and the file selection. Another very important fact to consider is that, if i add a new feature, i have to translate it in a A LOT of languages, or wait for the translators. That's why i added an "experimental settings" section in v4.x.x: it contains advanced, experimental and untranslated settings!

m-i-n-a-r avatar Nov 14 '22 09:11 m-i-n-a-r

Why not just replicate the behaviour of the default “Contacts” application, in which a dialog is shown the user to ask which file to back up the data in? It should be cleanly feasible even with Android 11+ file permission system, right?

victorbnl avatar Aug 31 '23 12:08 victorbnl

Here is a draft I came up with by looking at other projects.

val launcher = (context as MainActivity).registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
    val intent = result.data
    val uri = intent?.data
    uri?.let { uri ->
        fileFullPath = uri.path ?: ""
        context.contentResolver.openOutputStream(uri)?.use { outputStream ->
            outputStream.write(dbFile.readBytes())
            (context as MainActivity).runOnUiThread {
                context.showSnackbar(context.getString(R.string.birday_export_success))
            }
        } ?: run {
            (context as MainActivity).runOnUiThread {
                context.showSnackbar(context.getString(R.string.birday_export_failure))
            }
        }
    }
}

val intent = Intent(Intent.ACTION_CREATE_DOCUMENT)
    .addCategory(Intent.CATEGORY_OPENABLE)
    .setType("application/octet-stream")
    .putExtra(Intent.EXTRA_TITLE, fileName)
    
launcher.launch(intent)

I can’t implement it myself because I’m not a Kotlin developer and I don’t have a good grasp of Android features such as Lifecycles (I tried to put the code above in BirdayExporter.exportEvents but it didn’t work because MainActivity.registerForActivityResult should be called before the state is STARTED). Plus, I don’t even completely understand the code I have written above, it is mostly copy-pasted snippets put together. But here is what I think it would look like in broad strokes.

victorbnl avatar Aug 31 '23 16:08 victorbnl

Hi and sorry for the super late reply. I'll take a look as soon as I have some free time, thanks!

m-i-n-a-r avatar Oct 17 '23 13:10 m-i-n-a-r

Don’t worry, take your time!

victorbnl avatar Oct 17 '23 13:10 victorbnl