Merge pull request #126 from tom5079/Pupil-116
Pupil 116 Favorite tag backup
This commit is contained in:
@@ -118,7 +118,7 @@ class MainActivity :
|
|||||||
onFailure = {
|
onFailure = {
|
||||||
Snackbar.make(binding.contents.recyclerview, R.string.settings_backup_failed, Snackbar.LENGTH_LONG).show()
|
Snackbar.make(binding.contents.recyclerview, R.string.settings_backup_failed, Snackbar.LENGTH_LONG).show()
|
||||||
}, onSuccess = {
|
}, onSuccess = {
|
||||||
Snackbar.make(binding.contents.recyclerview, getString(R.string.settings_restore_success, it.size), Snackbar.LENGTH_LONG).show()
|
Snackbar.make(binding.contents.recyclerview, getString(R.string.settings_restore_success, it), Snackbar.LENGTH_LONG).show()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,21 +19,30 @@
|
|||||||
package xyz.quaver.pupil.ui.fragment
|
package xyz.quaver.pupil.ui.fragment
|
||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.content.res.Resources
|
||||||
|
import android.graphics.PorterDuff
|
||||||
|
import android.graphics.PorterDuffColorFilter
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.widget.EditText
|
import android.widget.EditText
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.core.graphics.drawable.DrawableCompat
|
||||||
import androidx.preference.Preference
|
import androidx.preference.Preference
|
||||||
import androidx.preference.PreferenceFragmentCompat
|
import androidx.preference.PreferenceFragmentCompat
|
||||||
|
import androidx.swiperefreshlayout.widget.CircularProgressDrawable
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
|
import kotlinx.coroutines.MainScope
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
import kotlinx.serialization.json.buildJsonObject
|
||||||
import okhttp3.*
|
import okhttp3.*
|
||||||
import xyz.quaver.pupil.R
|
import xyz.quaver.pupil.R
|
||||||
import xyz.quaver.pupil.client
|
import xyz.quaver.pupil.client
|
||||||
import xyz.quaver.pupil.favorites
|
|
||||||
import xyz.quaver.pupil.util.restore
|
import xyz.quaver.pupil.util.restore
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
class ManageFavoritesFragment : PreferenceFragmentCompat() {
|
class ManageFavoritesFragment : PreferenceFragmentCompat() {
|
||||||
|
|
||||||
@@ -47,21 +56,62 @@ class ManageFavoritesFragment : PreferenceFragmentCompat() {
|
|||||||
val context = context ?: return
|
val context = context ?: return
|
||||||
|
|
||||||
findPreference<Preference>("backup")?.setOnPreferenceClickListener {
|
findPreference<Preference>("backup")?.setOnPreferenceClickListener {
|
||||||
|
val iconSize = (24 * Resources.getSystem().displayMetrics.density).roundToInt()
|
||||||
|
val strokeWidth = (3 * Resources.getSystem().displayMetrics.density)
|
||||||
|
|
||||||
|
val icon = object: CircularProgressDrawable(context) {
|
||||||
|
override fun getIntrinsicHeight(): Int {
|
||||||
|
return iconSize
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getIntrinsicWidth(): Int {
|
||||||
|
return iconSize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
icon.strokeWidth = strokeWidth
|
||||||
|
icon.colorFilter = PorterDuffColorFilter(ContextCompat.getColor(context, R.color.colorAccent), PorterDuff.Mode.SRC_IN)
|
||||||
|
DrawableCompat.setTint(icon, ContextCompat.getColor(context, R.color.colorAccent))
|
||||||
|
icon.start()
|
||||||
|
it.icon = icon
|
||||||
|
|
||||||
|
val favorites = runCatching {
|
||||||
|
Json.parseToJsonElement(File(ContextCompat.getDataDir(context), "favorites.json").readText())
|
||||||
|
}.getOrNull()
|
||||||
|
val favoriteTags = kotlin.runCatching {
|
||||||
|
Json.parseToJsonElement(File(ContextCompat.getDataDir(context), "favorites_tags.json").readText())
|
||||||
|
}.getOrNull()
|
||||||
|
|
||||||
val request = Request.Builder()
|
val request = Request.Builder()
|
||||||
.url(context.getString(R.string.backup_url))
|
.url(context.getString(R.string.backup_url))
|
||||||
.post(
|
.post(
|
||||||
FormBody.Builder()
|
FormBody.Builder()
|
||||||
.add("f:1", File(ContextCompat.getDataDir(context), "favorites.json").readText())
|
.add("f:1", buildJsonObject {
|
||||||
|
favorites?.let {
|
||||||
|
put("favorites", it)
|
||||||
|
}
|
||||||
|
favoriteTags?.let {
|
||||||
|
put("favorite_tags", it)
|
||||||
|
}
|
||||||
|
}.toString())
|
||||||
.build()
|
.build()
|
||||||
).build()
|
).build()
|
||||||
|
|
||||||
client.newCall(request).enqueue(object: Callback {
|
client.newCall(request).enqueue(object: Callback {
|
||||||
override fun onFailure(call: Call, e: IOException) {
|
override fun onFailure(call: Call, e: IOException) {
|
||||||
val view = view ?: return
|
val view = view ?: return
|
||||||
|
|
||||||
|
MainScope().launch {
|
||||||
|
it.icon = null
|
||||||
|
}
|
||||||
Snackbar.make(view, R.string.settings_backup_failed, Snackbar.LENGTH_LONG).show()
|
Snackbar.make(view, R.string.settings_backup_failed, Snackbar.LENGTH_LONG).show()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResponse(call: Call, response: Response) {
|
override fun onResponse(call: Call, response: Response) {
|
||||||
|
MainScope().launch {
|
||||||
|
it.icon = null
|
||||||
|
}
|
||||||
|
|
||||||
if (response.code() != 200) {
|
if (response.code() != 200) {
|
||||||
response.close()
|
response.close()
|
||||||
return
|
return
|
||||||
@@ -93,7 +143,7 @@ class ManageFavoritesFragment : PreferenceFragmentCompat() {
|
|||||||
Snackbar.make(view, R.string.settings_restore_failed, Snackbar.LENGTH_LONG).show()
|
Snackbar.make(view, R.string.settings_restore_failed, Snackbar.LENGTH_LONG).show()
|
||||||
}, onSuccess = onSuccess@{
|
}, onSuccess = onSuccess@{
|
||||||
val view = view ?: return@onSuccess
|
val view = view ?: return@onSuccess
|
||||||
Snackbar.make(view, context.getString(R.string.settings_restore_success, it.size), Snackbar.LENGTH_LONG).show()
|
Snackbar.make(view, context.getString(R.string.settings_restore_success, it), Snackbar.LENGTH_LONG).show()
|
||||||
})
|
})
|
||||||
}.setNegativeButton(android.R.string.cancel) { _, _ ->
|
}.setNegativeButton(android.R.string.cancel) { _, _ ->
|
||||||
// Do Nothing
|
// Do Nothing
|
||||||
|
|||||||
@@ -27,17 +27,14 @@ import androidx.preference.PreferenceManager
|
|||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.serialization.decodeFromString
|
|
||||||
import kotlinx.serialization.json.*
|
import kotlinx.serialization.json.*
|
||||||
import okhttp3.Call
|
import okhttp3.Call
|
||||||
import okhttp3.Callback
|
import okhttp3.Callback
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import ru.noties.markwon.Markwon
|
import ru.noties.markwon.Markwon
|
||||||
import xyz.quaver.pupil.BuildConfig
|
import xyz.quaver.pupil.*
|
||||||
import xyz.quaver.pupil.R
|
import xyz.quaver.pupil.types.Tag
|
||||||
import xyz.quaver.pupil.client
|
|
||||||
import xyz.quaver.pupil.favorites
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
@@ -173,7 +170,7 @@ fun checkUpdate(context: Context, force: Boolean = false) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun restore(url: String, onFailure: ((Throwable) -> Unit)? = null, onSuccess: ((List<Int>) -> Unit)? = null) {
|
fun restore(url: String, onFailure: ((Throwable) -> Unit)? = null, onSuccess: ((Int) -> Unit)? = null) {
|
||||||
if (!URLUtil.isValidUrl(url)) {
|
if (!URLUtil.isValidUrl(url)) {
|
||||||
onFailure?.invoke(IllegalArgumentException())
|
onFailure?.invoke(IllegalArgumentException())
|
||||||
return
|
return
|
||||||
@@ -191,9 +188,20 @@ fun restore(url: String, onFailure: ((Throwable) -> Unit)? = null, onSuccess: ((
|
|||||||
|
|
||||||
override fun onResponse(call: Call, response: Response) {
|
override fun onResponse(call: Call, response: Response) {
|
||||||
kotlin.runCatching {
|
kotlin.runCatching {
|
||||||
Json.decodeFromString<List<Int>>(response.also { if (it.code() != 200) throw IOException() }.body().use { it?.string() } ?: "[]").let {
|
val data = Json.parseToJsonElement(response.also { if (it.code() != 200) throw IOException() }.body().use { it?.string() } ?: "[]")
|
||||||
favorites.addAll(it)
|
|
||||||
onSuccess?.invoke(it)
|
when (data) {
|
||||||
|
is JsonArray -> favorites.addAll(data.map { it.jsonPrimitive.int })
|
||||||
|
is JsonObject -> {
|
||||||
|
val newFavorites = data["favorites"]?.let { Json.decodeFromJsonElement<List<Int>>(it) }.orEmpty()
|
||||||
|
val newFavoriteTags = data["favorite_tags"]?.let { Json.decodeFromJsonElement<List<Tag>>(it) }.orEmpty()
|
||||||
|
|
||||||
|
favorites.addAll(newFavorites)
|
||||||
|
favoriteTags.addAll(newFavoriteTags)
|
||||||
|
|
||||||
|
onSuccess?.invoke(favorites.size + favoriteTags.size)
|
||||||
|
}
|
||||||
|
else -> error("data is neither JsonArray or JsonObject")
|
||||||
}
|
}
|
||||||
}.onFailure { onFailure?.invoke(it) }
|
}.onFailure { onFailure?.invoke(it) }
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user