diff --git a/app/build.gradle b/app/build.gradle index e04cb7c..11ce402 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -10,8 +10,8 @@ android { applicationId "org.mosad.teapod" minSdkVersion 23 targetSdkVersion 30 - versionCode 4100 //00.04.100 - versionName "0.4.1" + versionCode 4180 //00.04.100 + versionName "0.4.2-alpha1" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" resValue "string", "build_time", buildTime() diff --git a/app/src/main/java/org/mosad/teapod/ui/activity/main/fragments/AccountFragment.kt b/app/src/main/java/org/mosad/teapod/ui/activity/main/fragments/AccountFragment.kt index 5f0b4ae..87dc432 100644 --- a/app/src/main/java/org/mosad/teapod/ui/activity/main/fragments/AccountFragment.kt +++ b/app/src/main/java/org/mosad/teapod/ui/activity/main/fragments/AccountFragment.kt @@ -1,5 +1,6 @@ package org.mosad.teapod.ui.activity.main.fragments +import android.app.Activity import android.content.Intent import android.net.Uri import android.os.Bundle @@ -7,6 +8,7 @@ import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.Toast import androidx.core.view.isVisible import androidx.fragment.app.Fragment import com.afollestad.materialdialogs.MaterialDialog @@ -14,20 +16,24 @@ import com.afollestad.materialdialogs.list.listItemsSingleChoice import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch import org.mosad.teapod.BuildConfig -import org.mosad.teapod.ui.activity.main.MainActivity import org.mosad.teapod.R import org.mosad.teapod.databinding.FragmentAccountBinding import org.mosad.teapod.parser.AoDParser import org.mosad.teapod.preferences.EncryptedPreferences import org.mosad.teapod.preferences.Preferences +import org.mosad.teapod.ui.activity.main.MainActivity import org.mosad.teapod.ui.components.LoginDialog import org.mosad.teapod.util.DataTypes.Theme +import org.mosad.teapod.util.StorageController import org.mosad.teapod.util.showFragment class AccountFragment : Fragment() { private lateinit var binding: FragmentAccountBinding + private val exportFileCode = 1111 + private val importFileCode = 1122 + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { binding = FragmentAccountBinding.inflate(inflater, container, false) return binding.root @@ -60,6 +66,30 @@ class AccountFragment : Fragment() { initActions() } + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + // return if the result was not ok + if (resultCode != Activity.RESULT_OK) { + Log.e(javaClass.name, "Error while computing result. Result code is: $resultCode") + return + } + + when(requestCode) { + exportFileCode -> data?.data?.also { uri -> + StorageController.exportMyList(requireContext(), uri) + } + + importFileCode -> data?.data?.also { uri -> + val success = StorageController.importMyList(requireContext(), uri) + if (success == 0) { + Toast.makeText( + context, getString(R.string.import_data_success), + Toast.LENGTH_SHORT + ).show() + } + } + } + } + private fun initActions() { binding.linearAccountLogin.setOnClickListener { showLoginDialog(true) @@ -86,11 +116,20 @@ class AccountFragment : Fragment() { } binding.linearExportData.setOnClickListener { - println("TODO") + val i = Intent(Intent.ACTION_CREATE_DOCUMENT).apply { + addCategory(Intent.CATEGORY_OPENABLE) + type = "text/json" + putExtra(Intent.EXTRA_TITLE, "my-list.json") + } + startActivityForResult(i, exportFileCode) } binding.linearImportData.setOnClickListener { - println("TODO") + val i = Intent(Intent.ACTION_OPEN_DOCUMENT).apply { + addCategory(Intent.CATEGORY_OPENABLE) + type = "*/*" + } + startActivityForResult(i, importFileCode) } } @@ -120,7 +159,7 @@ class AccountFragment : Fragment() { when(index) { 0 -> Preferences.saveTheme(context, Theme.LIGHT) 1 -> Preferences.saveTheme(context, Theme.DARK) - else -> Preferences.saveTheme(context, Theme.LIGHT) + else -> Preferences.saveTheme(context, Theme.DARK) } (activity as MainActivity).restart() diff --git a/app/src/main/java/org/mosad/teapod/util/StorageController.kt b/app/src/main/java/org/mosad/teapod/util/StorageController.kt index ac4309f..291ac81 100644 --- a/app/src/main/java/org/mosad/teapod/util/StorageController.kt +++ b/app/src/main/java/org/mosad/teapod/util/StorageController.kt @@ -1,12 +1,18 @@ package org.mosad.teapod.util import android.content.Context +import android.net.Uri import android.util.Log +import android.widget.Toast import com.google.gson.Gson import com.google.gson.JsonParser import kotlinx.coroutines.* +import org.mosad.teapod.R import java.io.File +import java.io.FileReader +import java.io.FileWriter import java.lang.Exception +import java.net.URI /** * This controller contains the logic for permanently saved data. @@ -19,6 +25,10 @@ object StorageController { val myList = ArrayList() // a list of saved mediaIds fun load(context: Context) { + loadMyList(context) + } + + fun loadMyList(context: Context) { val file = File(context.filesDir, fileNameMyList) if (!file.exists()) runBlocking { saveMyList(context).join() } @@ -30,7 +40,6 @@ object StorageController { myList.clear() Log.e(javaClass.name, "Parsing of My-List failed.") } - } fun saveMyList(context: Context): Job { @@ -41,4 +50,44 @@ object StorageController { } } + fun exportMyList(context: Context, uri: Uri) { + try { + context.contentResolver.openFileDescriptor(uri, "w")?.use { + FileWriter(it.fileDescriptor).use { writer -> + writer.write(Gson().toJson(myList.distinct())) + } + } + } catch (ex: Exception) { + Log.e(javaClass.name, "Exporting my list failed.", ex) + } + } + + /** + * import my list from a (previously exported) json file + * @param context the current context + * @param uri the uri of the selected file + * @return 0 if import was successfull, else 1 + */ + fun importMyList(context: Context, uri: Uri): Int { + try { + val text = context.contentResolver.openFileDescriptor(uri, "r")?.use { + FileReader(it.fileDescriptor).use { reader -> + reader.readText() + } + } + + myList.clear() + myList.addAll(JsonParser.parseString(text).asJsonArray.map { it.asInt }.distinct()) + + // after the list has been imported also save it + saveMyList(context) + } catch (ex: Exception) { + myList.clear() + Log.e(javaClass.name, "Importing my list failed.", ex) + return 1 + } + + return 0 + } + } \ No newline at end of file diff --git a/app/src/main/res/values-de-rDE/strings.xml b/app/src/main/res/values-de-rDE/strings.xml index b1d7d0b..b2adda2 100644 --- a/app/src/main/res/values-de-rDE/strings.xml +++ b/app/src/main/res/values-de-rDE/strings.xml @@ -51,6 +51,7 @@ Speichere "meine Liste" in eine Datei Daten importieren Lade "meine Liste" aus einer Datei + "meine Liste" erfolgreich importiert Version diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 712e8ac..8c7fbed 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -59,9 +59,10 @@ Dark Developer Settings export data - export my list to a file + export "my list" to a file import data - import my list from a file + import "my list" from a file + imported "my list" successfully