Fixes
This commit is contained in:
@@ -312,6 +312,7 @@ class AppSettings(context: Context) {
|
||||
const val KEY_DOWNLOADS_SLOWDOWN = "downloads_slowdown"
|
||||
const val KEY_ALL_FAVOURITES_VISIBLE = "all_favourites_visible"
|
||||
const val KEY_DOH = "doh"
|
||||
const val KEY_SYNC = "sync"
|
||||
|
||||
// About
|
||||
const val KEY_APP_UPDATE = "app_update"
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package org.koitharu.kotatsu.settings
|
||||
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.os.Bundle
|
||||
import android.provider.Settings
|
||||
import android.view.View
|
||||
import androidx.preference.ListPreference
|
||||
import androidx.preference.Preference
|
||||
@@ -76,6 +78,10 @@ class ContentSettingsFragment :
|
||||
AppSettings.KEY_SOURCES_HIDDEN -> {
|
||||
bindRemoteSourcesSummary()
|
||||
}
|
||||
AppSettings.KEY_SYNC -> {
|
||||
val intent = Intent(Settings.ACTION_SYNC_SETTINGS)
|
||||
startActivity(intent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import android.content.*
|
||||
import android.database.Cursor
|
||||
import android.net.Uri
|
||||
import androidx.annotation.WorkerThread
|
||||
import androidx.core.content.contentValuesOf
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import org.json.JSONArray
|
||||
@@ -13,9 +14,9 @@ import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.db.*
|
||||
import org.koitharu.kotatsu.parsers.util.json.mapJSONTo
|
||||
import org.koitharu.kotatsu.parsers.util.parseJson
|
||||
import org.koitharu.kotatsu.sync.data.SyncAuthApi
|
||||
import org.koitharu.kotatsu.sync.data.SyncAuthenticator
|
||||
import org.koitharu.kotatsu.sync.data.SyncInterceptor
|
||||
import org.koitharu.kotatsu.sync.data.SyncAuthApi
|
||||
import org.koitharu.kotatsu.utils.GZipInterceptor
|
||||
import org.koitharu.kotatsu.utils.ext.toContentValues
|
||||
import org.koitharu.kotatsu.utils.ext.toJson
|
||||
@@ -86,6 +87,7 @@ class SyncHelper(
|
||||
.withSelection("updated_at < ?", arrayOf(timestamp.toString()))
|
||||
.build()
|
||||
json.mapJSONTo(operations) { jo ->
|
||||
operations.addAll(upsertManga(jo.removeJSONObject("manga"), AUTHORITY_HISTORY))
|
||||
ContentProviderOperation.newInsert(uri)
|
||||
.withValues(jo.toContentValues())
|
||||
.build()
|
||||
@@ -114,6 +116,7 @@ class SyncHelper(
|
||||
.withSelection("created_at < ?", arrayOf(timestamp.toString()))
|
||||
.build()
|
||||
json.mapJSONTo(operations) { jo ->
|
||||
operations.addAll(upsertManga(jo.removeJSONObject("manga"), AUTHORITY_FAVOURITES))
|
||||
ContentProviderOperation.newInsert(uri)
|
||||
.withValues(jo.toContentValues())
|
||||
.build()
|
||||
@@ -121,6 +124,31 @@ class SyncHelper(
|
||||
return provider.applyBatch(operations)
|
||||
}
|
||||
|
||||
private fun upsertManga(json: JSONObject, authority: String): List<ContentProviderOperation> {
|
||||
val tags = json.removeJSONArray(TABLE_TAGS)
|
||||
val result = ArrayList<ContentProviderOperation>(tags.length() * 2 + 1)
|
||||
for (i in 0 until tags.length()) {
|
||||
val tag = tags.getJSONObject(i)
|
||||
result += ContentProviderOperation.newInsert(uri(authority, TABLE_TAGS))
|
||||
.withValues(tag.toContentValues())
|
||||
.build()
|
||||
result += ContentProviderOperation.newInsert(uri(authority, TABLE_MANGA_TAGS))
|
||||
.withValues(
|
||||
contentValuesOf(
|
||||
"manga_id" to json.getLong("manga_id"),
|
||||
"tag_id" to tag.getLong("tag_id"),
|
||||
)
|
||||
).build()
|
||||
}
|
||||
result.add(
|
||||
0,
|
||||
ContentProviderOperation.newInsert(uri(authority, TABLE_MANGA))
|
||||
.withValues(json.toContentValues())
|
||||
.build()
|
||||
)
|
||||
return result
|
||||
}
|
||||
|
||||
private fun getHistory(): JSONArray {
|
||||
return provider.query(AUTHORITY_HISTORY, TABLE_HISTORY).use { cursor ->
|
||||
val json = JSONArray()
|
||||
@@ -217,4 +245,8 @@ class SyncHelper(
|
||||
}
|
||||
|
||||
private fun uri(authority: String, table: String) = Uri.parse("content://$authority/$table")
|
||||
|
||||
private fun JSONObject.removeJSONObject(name: String) = remove(name) as JSONObject
|
||||
|
||||
private fun JSONObject.removeJSONArray(name: String) = remove(name) as JSONArray
|
||||
}
|
||||
@@ -7,10 +7,11 @@ import android.content.ContentValues
|
||||
import android.database.Cursor
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
import android.net.Uri
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
import androidx.sqlite.db.SupportSQLiteQueryBuilder
|
||||
import java.util.concurrent.Callable
|
||||
import org.koin.android.ext.android.inject
|
||||
import org.koitharu.kotatsu.core.db.*
|
||||
import java.util.concurrent.Callable
|
||||
|
||||
abstract class SyncProvider : ContentProvider() {
|
||||
|
||||
@@ -55,15 +56,14 @@ abstract class SyncProvider : ContentProvider() {
|
||||
return null
|
||||
}
|
||||
val db = database.openHelper.writableDatabase
|
||||
db.insert(table, SQLiteDatabase.CONFLICT_REPLACE, values)
|
||||
return null
|
||||
if (db.insert(table, SQLiteDatabase.CONFLICT_IGNORE, values) < 0) {
|
||||
db.update(table, values)
|
||||
}
|
||||
return uri
|
||||
}
|
||||
|
||||
override fun delete(uri: Uri, selection: String?, selectionArgs: Array<out String>?): Int {
|
||||
val table = getTableName(uri)
|
||||
if (table == null) {
|
||||
return 0
|
||||
}
|
||||
val table = getTableName(uri) ?: return 0
|
||||
return database.openHelper.writableDatabase.delete(table, selection, selectionArgs)
|
||||
}
|
||||
|
||||
@@ -77,14 +77,35 @@ abstract class SyncProvider : ContentProvider() {
|
||||
}
|
||||
|
||||
override fun applyBatch(operations: ArrayList<ContentProviderOperation>): Array<ContentProviderResult> {
|
||||
return database.runInTransaction(Callable { super.applyBatch(operations) })
|
||||
return runAtomicTransaction { super.applyBatch(operations) }
|
||||
}
|
||||
|
||||
override fun bulkInsert(uri: Uri, values: Array<out ContentValues>): Int {
|
||||
return database.runInTransaction(Callable { super.bulkInsert(uri, values) })
|
||||
return runAtomicTransaction { super.bulkInsert(uri, values) }
|
||||
}
|
||||
|
||||
private fun getTableName(uri: Uri): String? {
|
||||
return uri.pathSegments.singleOrNull()?.takeIf { it in supportedTables }
|
||||
}
|
||||
|
||||
private fun <R> runAtomicTransaction(callable: Callable<R>): R {
|
||||
return synchronized(database) {
|
||||
database.runInTransaction(callable)
|
||||
}
|
||||
}
|
||||
|
||||
private fun SupportSQLiteDatabase.update(table: String, values: ContentValues) {
|
||||
val keys = when (table) {
|
||||
TABLE_TAGS -> listOf("tag_id")
|
||||
TABLE_MANGA_TAGS -> listOf("tag_id", "manga_id")
|
||||
TABLE_MANGA -> listOf("manga_id")
|
||||
TABLE_FAVOURITES -> listOf("manga_id", "category_id")
|
||||
TABLE_FAVOURITE_CATEGORIES -> listOf("category_id")
|
||||
TABLE_HISTORY -> listOf("manga_id")
|
||||
else -> throw IllegalArgumentException("Update for $table is not supported")
|
||||
}
|
||||
val whereClause = keys.joinToString(" AND ") { "`$it` = ?" }
|
||||
val whereArgs = Array<Any>(keys.size) { i -> values.get("`${keys[i]}`") ?: values.get(keys[i]) }
|
||||
this.update(table, SQLiteDatabase.CONFLICT_IGNORE, values, whereClause, whereArgs)
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,7 @@ fun JSONObject.toContentValues(): ContentValues {
|
||||
for (key in keys()) {
|
||||
val name = key.escapeName()
|
||||
when (val value = get(key)) {
|
||||
null -> cv.putNull(name)
|
||||
JSONObject.NULL, "null", null -> cv.putNull(name)
|
||||
is String -> cv.put(name, value)
|
||||
is Float -> cv.put(name, value)
|
||||
is Double -> cv.put(name, value)
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<string name="url_forpda" translatable="false">https://4pda.to/forum/index.php?showtopic=697669</string>
|
||||
<string name="url_weblate" translatable="false">https://hosted.weblate.org/engage/kotatsu</string>
|
||||
<string name="account_type_sync" translatable="false">org.kotatsu.sync</string>
|
||||
<string name="url_sync_server" translatable="false">http://192.168.0.113:8080</string>
|
||||
<string name="url_sync_server" translatable="false">http://95.216.215.49:8080</string>
|
||||
<string-array name="values_theme" translatable="false">
|
||||
<item>-1</item>
|
||||
<item>1</item>
|
||||
|
||||
@@ -40,9 +40,14 @@
|
||||
android:valueTo="5"
|
||||
app:defaultValue="2" />
|
||||
|
||||
<Preference
|
||||
android:key="sync"
|
||||
android:persistent="false"
|
||||
android:summary="@string/sync_title"
|
||||
android:title="@string/sync" />
|
||||
|
||||
<PreferenceScreen
|
||||
android:fragment="org.koitharu.kotatsu.settings.backup.BackupSettingsFragment"
|
||||
android:title="@string/backup_restore"
|
||||
app:allowDividerAbove="true" />
|
||||
android:title="@string/backup_restore" />
|
||||
|
||||
</PreferenceScreen>
|
||||
Reference in New Issue
Block a user