mirror of
https://github.com/karasevm/PrivateDNSAndroid.git
synced 2025-06-28 20:29:56 +00:00
Replace gson with kotlinx-serialization
This commit is contained in:
parent
fa9d259a21
commit
6a5f405211
7 changed files with 50 additions and 53 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -67,3 +67,6 @@ fastlane/Preview.html
|
||||||
fastlane/screenshots
|
fastlane/screenshots
|
||||||
fastlane/test_output
|
fastlane/test_output
|
||||||
fastlane/readme.md
|
fastlane/readme.md
|
||||||
|
|
||||||
|
# kotlin
|
||||||
|
.kotlin/
|
||||||
|
|
2
.idea/kotlinc.xml
generated
2
.idea/kotlinc.xml
generated
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="KotlinJpsPluginSettings">
|
<component name="KotlinJpsPluginSettings">
|
||||||
<option name="version" value="1.9.10" />
|
<option name="version" value="2.0.20" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
|
@ -2,6 +2,7 @@ plugins {
|
||||||
id 'com.android.application'
|
id 'com.android.application'
|
||||||
id 'kotlin-android'
|
id 'kotlin-android'
|
||||||
id 'com.google.devtools.ksp'
|
id 'com.google.devtools.ksp'
|
||||||
|
id 'org.jetbrains.kotlin.plugin.serialization'
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
|
@ -51,11 +52,12 @@ dependencies {
|
||||||
implementation 'androidx.appcompat:appcompat:1.7.0'
|
implementation 'androidx.appcompat:appcompat:1.7.0'
|
||||||
implementation 'androidx.recyclerview:recyclerview:1.3.2'
|
implementation 'androidx.recyclerview:recyclerview:1.3.2'
|
||||||
implementation 'androidx.activity:activity-ktx:1.9.2'
|
implementation 'androidx.activity:activity-ktx:1.9.2'
|
||||||
implementation 'androidx.fragment:fragment-ktx:1.8.3'
|
implementation 'androidx.fragment:fragment-ktx:1.8.4'
|
||||||
implementation 'com.google.android.material:material:1.12.0'
|
implementation 'com.google.android.material:material:1.12.0'
|
||||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
|
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
|
||||||
implementation 'com.google.guava:guava:33.1.0-android'
|
implementation 'com.google.guava:guava:33.1.0-android'
|
||||||
implementation 'com.google.code.gson:gson:2.11.0'
|
implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3'
|
||||||
|
|
||||||
|
|
||||||
def shizuku_version = '13.1.5'
|
def shizuku_version = '13.1.5'
|
||||||
implementation "dev.rikka.shizuku:api:$shizuku_version"
|
implementation "dev.rikka.shizuku:api:$shizuku_version"
|
||||||
|
@ -71,7 +73,7 @@ dependencies {
|
||||||
androidTestImplementation "androidx.room:room-testing:$roomVersion"
|
androidTestImplementation "androidx.room:room-testing:$roomVersion"
|
||||||
|
|
||||||
// Lifecycle components
|
// Lifecycle components
|
||||||
def lifecycleVersion = '2.8.5'
|
def lifecycleVersion = '2.8.6'
|
||||||
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycleVersion"
|
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycleVersion"
|
||||||
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycleVersion"
|
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycleVersion"
|
||||||
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycleVersion"
|
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycleVersion"
|
||||||
|
|
|
@ -3,19 +3,21 @@ package ru.karasevm.privatednstoggle.model
|
||||||
import androidx.room.ColumnInfo
|
import androidx.room.ColumnInfo
|
||||||
import androidx.room.Entity
|
import androidx.room.Entity
|
||||||
import androidx.room.PrimaryKey
|
import androidx.room.PrimaryKey
|
||||||
import com.google.gson.annotations.SerializedName
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
// All fields must have default values for proper deserialization
|
// All fields must have default values for proper deserialization
|
||||||
|
@Serializable
|
||||||
@Entity(tableName = "dns_servers")
|
@Entity(tableName = "dns_servers")
|
||||||
data class DnsServer(
|
data class DnsServer(
|
||||||
@SerializedName("id")
|
@SerialName("id")
|
||||||
@PrimaryKey(autoGenerate = true)
|
@PrimaryKey(autoGenerate = true)
|
||||||
val id: Int = 0,
|
val id: Int = 0,
|
||||||
@SerializedName("server")
|
@SerialName("server")
|
||||||
val server: String = "",
|
val server: String = "",
|
||||||
@SerializedName("label")
|
@SerialName("label")
|
||||||
val label: String = "",
|
val label: String = "",
|
||||||
@SerializedName("enabled")
|
@SerialName("enabled")
|
||||||
@ColumnInfo(defaultValue = "1")
|
@ColumnInfo(defaultValue = "1")
|
||||||
val enabled: Boolean = true,
|
val enabled: Boolean = true,
|
||||||
val sortOrder: Int? = null
|
val sortOrder: Int? = null
|
||||||
|
|
|
@ -27,12 +27,9 @@ import androidx.recyclerview.widget.ItemTouchHelper.DOWN
|
||||||
import androidx.recyclerview.widget.ItemTouchHelper.UP
|
import androidx.recyclerview.widget.ItemTouchHelper.UP
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.google.gson.Gson
|
|
||||||
import com.google.gson.GsonBuilder
|
|
||||||
import com.google.gson.JsonSyntaxException
|
|
||||||
import com.google.gson.ToNumberPolicy
|
|
||||||
import com.google.gson.reflect.TypeToken
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.serialization.encodeToString
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
import org.lsposed.hiddenapibypass.HiddenApiBypass
|
import org.lsposed.hiddenapibypass.HiddenApiBypass
|
||||||
import rikka.shizuku.Shizuku
|
import rikka.shizuku.Shizuku
|
||||||
import rikka.shizuku.ShizukuBinderWrapper
|
import rikka.shizuku.ShizukuBinderWrapper
|
||||||
|
@ -58,7 +55,6 @@ class MainActivity : AppCompatActivity(), AddServerDialogFragment.NoticeDialogLi
|
||||||
private lateinit var sharedPrefs: SharedPreferences
|
private lateinit var sharedPrefs: SharedPreferences
|
||||||
private lateinit var adapter: ServerListRecyclerAdapter
|
private lateinit var adapter: ServerListRecyclerAdapter
|
||||||
private lateinit var clipboard: ClipboardManager
|
private lateinit var clipboard: ClipboardManager
|
||||||
private lateinit var gson: Gson
|
|
||||||
private val dnsServerViewModel: DnsServerViewModel by viewModels { DnsServerViewModelFactory((application as PrivateDNSApp).repository) }
|
private val dnsServerViewModel: DnsServerViewModel by viewModels { DnsServerViewModelFactory((application as PrivateDNSApp).repository) }
|
||||||
|
|
||||||
private val itemTouchHelper by lazy {
|
private val itemTouchHelper by lazy {
|
||||||
|
@ -126,7 +122,7 @@ class MainActivity : AppCompatActivity(), AddServerDialogFragment.NoticeDialogLi
|
||||||
|
|
||||||
private fun importSettings(json: String) {
|
private fun importSettings(json: String) {
|
||||||
runCatching {
|
runCatching {
|
||||||
val data: BackupUtils.Backup = gson.fromJson(json, BackupUtils.Backup::class.java)
|
val data: BackupUtils.Backup = Json.decodeFromString<BackupUtils.Backup>(json)
|
||||||
BackupUtils.import(data, dnsServerViewModel, sharedPrefs)
|
BackupUtils.import(data, dnsServerViewModel, sharedPrefs)
|
||||||
}.onSuccess {
|
}.onSuccess {
|
||||||
Toast.makeText(
|
Toast.makeText(
|
||||||
|
@ -134,28 +130,18 @@ class MainActivity : AppCompatActivity(), AddServerDialogFragment.NoticeDialogLi
|
||||||
).show()
|
).show()
|
||||||
}.onFailure { exception ->
|
}.onFailure { exception ->
|
||||||
runCatching {
|
runCatching {
|
||||||
val objectType = object : TypeToken<Map<String, Any>>() {}.type
|
Log.e("IMPORT", "Malformed json, falling back to legacy", exception)
|
||||||
val data: Map<String, Any> = gson.fromJson(json, objectType)
|
val data = Json.decodeFromString<BackupUtils.LegacyBackup>(json)
|
||||||
BackupUtils.importLegacy(data, dnsServerViewModel, sharedPrefs)
|
BackupUtils.importLegacy(data, dnsServerViewModel, sharedPrefs)
|
||||||
}.onSuccess {
|
}.onSuccess {
|
||||||
Toast.makeText(
|
Toast.makeText(
|
||||||
this, getString(R.string.import_success), Toast.LENGTH_SHORT
|
this, getString(R.string.import_success), Toast.LENGTH_SHORT
|
||||||
).show()
|
).show()
|
||||||
}.onFailure {
|
}.onFailure { exception ->
|
||||||
Log.e("IMPORT", "Import failed", exception)
|
Log.e("IMPORT", "Import failed", exception)
|
||||||
when (exception) {
|
Toast.makeText(
|
||||||
is JsonSyntaxException -> {
|
this, getString(R.string.import_failure), Toast.LENGTH_SHORT
|
||||||
Toast.makeText(
|
).show()
|
||||||
this, getString(R.string.import_failure_json), Toast.LENGTH_SHORT
|
|
||||||
).show()
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> {
|
|
||||||
Toast.makeText(
|
|
||||||
this, getString(R.string.import_failure), Toast.LENGTH_SHORT
|
|
||||||
).show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -193,7 +179,6 @@ class MainActivity : AppCompatActivity(), AddServerDialogFragment.NoticeDialogLi
|
||||||
|
|
||||||
sharedPrefs = PreferenceHelper.defaultPreference(this)
|
sharedPrefs = PreferenceHelper.defaultPreference(this)
|
||||||
clipboard = getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
|
clipboard = getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
|
||||||
gson = GsonBuilder().setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE).create()
|
|
||||||
|
|
||||||
migrateServerList()
|
migrateServerList()
|
||||||
|
|
||||||
|
@ -249,7 +234,7 @@ class MainActivity : AppCompatActivity(), AddServerDialogFragment.NoticeDialogLi
|
||||||
R.id.export_settings_clipboard -> {
|
R.id.export_settings_clipboard -> {
|
||||||
dnsServerViewModel.viewModelScope.launch {
|
dnsServerViewModel.viewModelScope.launch {
|
||||||
val data = BackupUtils.export(dnsServerViewModel, sharedPrefs)
|
val data = BackupUtils.export(dnsServerViewModel, sharedPrefs)
|
||||||
val jsonData = gson.toJson(data)
|
val jsonData = Json.encodeToString(data)
|
||||||
clipboard.setPrimaryClip(ClipData.newPlainText("", jsonData))
|
clipboard.setPrimaryClip(ClipData.newPlainText("", jsonData))
|
||||||
// Only show a toast for Android 12 and lower.
|
// Only show a toast for Android 12 and lower.
|
||||||
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.S_V2) Toast.makeText(
|
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.S_V2) Toast.makeText(
|
||||||
|
@ -263,7 +248,7 @@ class MainActivity : AppCompatActivity(), AddServerDialogFragment.NoticeDialogLi
|
||||||
val activityContext = this
|
val activityContext = this
|
||||||
dnsServerViewModel.viewModelScope.launch {
|
dnsServerViewModel.viewModelScope.launch {
|
||||||
val data = BackupUtils.export(dnsServerViewModel, sharedPrefs)
|
val data = BackupUtils.export(dnsServerViewModel, sharedPrefs)
|
||||||
val jsonData = gson.toJson(data)
|
val jsonData = Json.encodeToString(data)
|
||||||
ShareCompat.IntentBuilder(activityContext).setText(jsonData)
|
ShareCompat.IntentBuilder(activityContext).setText(jsonData)
|
||||||
.setType("text/plain")
|
.setType("text/plain")
|
||||||
.startChooser()
|
.startChooser()
|
||||||
|
@ -319,7 +304,7 @@ class MainActivity : AppCompatActivity(), AddServerDialogFragment.NoticeDialogLi
|
||||||
if (result.resultCode == RESULT_OK) {
|
if (result.resultCode == RESULT_OK) {
|
||||||
val data: Intent? = result.data
|
val data: Intent? = result.data
|
||||||
data?.data?.also { uri ->
|
data?.data?.also { uri ->
|
||||||
val jsonData = gson.toJson(BackupUtils.export(dnsServerViewModel, sharedPrefs))
|
val jsonData = Json.encodeToString(BackupUtils.export(dnsServerViewModel, sharedPrefs))
|
||||||
val contentResolver = applicationContext.contentResolver
|
val contentResolver = applicationContext.contentResolver
|
||||||
runCatching {
|
runCatching {
|
||||||
contentResolver.openOutputStream(uri)?.use { outputStream ->
|
contentResolver.openOutputStream(uri)?.use { outputStream ->
|
||||||
|
|
|
@ -1,20 +1,26 @@
|
||||||
package ru.karasevm.privatednstoggle.util
|
package ru.karasevm.privatednstoggle.util
|
||||||
|
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import com.google.gson.annotations.SerializedName
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
import ru.karasevm.privatednstoggle.data.DnsServerViewModel
|
import ru.karasevm.privatednstoggle.data.DnsServerViewModel
|
||||||
import ru.karasevm.privatednstoggle.model.DnsServer
|
import ru.karasevm.privatednstoggle.model.DnsServer
|
||||||
import ru.karasevm.privatednstoggle.util.PreferenceHelper.AUTO_MODE
|
|
||||||
import ru.karasevm.privatednstoggle.util.PreferenceHelper.DNS_SERVERS
|
|
||||||
import ru.karasevm.privatednstoggle.util.PreferenceHelper.REQUIRE_UNLOCK
|
|
||||||
import ru.karasevm.privatednstoggle.util.PreferenceHelper.autoMode
|
import ru.karasevm.privatednstoggle.util.PreferenceHelper.autoMode
|
||||||
import ru.karasevm.privatednstoggle.util.PreferenceHelper.requireUnlock
|
import ru.karasevm.privatednstoggle.util.PreferenceHelper.requireUnlock
|
||||||
|
|
||||||
object BackupUtils {
|
object BackupUtils {
|
||||||
|
@Serializable
|
||||||
data class Backup(
|
data class Backup(
|
||||||
@SerializedName("dns_servers") val dnsServers: List<DnsServer>,
|
@SerialName("dns_servers") val dnsServers: List<DnsServer>,
|
||||||
@SerializedName("auto_mode") val autoMode: Int?,
|
@SerialName("auto_mode") val autoMode: Int?,
|
||||||
@SerializedName("require_unlock") val requireUnlock: Boolean?,
|
@SerialName("require_unlock") val requireUnlock: Boolean?,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class LegacyBackup(
|
||||||
|
@SerialName("dns_servers") val dnsServers: String,
|
||||||
|
@SerialName("auto_mode") val autoMode: Int?,
|
||||||
|
@SerialName("require_unlock") val requireUnlock: Boolean?,
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -47,17 +53,16 @@ object BackupUtils {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Imports old server list
|
* Imports old server list
|
||||||
* @param map Deserialized backup
|
* @param legacyBackup Deserialized backup
|
||||||
* @param viewModel View model
|
* @param viewModel View model
|
||||||
* @param sharedPreferences Shared preferences
|
* @param sharedPreferences Shared preferences
|
||||||
*/
|
*/
|
||||||
fun importLegacy(
|
fun importLegacy(
|
||||||
map: Map<String, Any>,
|
legacyBackup: LegacyBackup,
|
||||||
viewModel: DnsServerViewModel,
|
viewModel: DnsServerViewModel,
|
||||||
sharedPreferences: SharedPreferences
|
sharedPreferences: SharedPreferences
|
||||||
) {
|
) {
|
||||||
map[DNS_SERVERS]?.let { servers ->
|
legacyBackup.dnsServers.let { servers ->
|
||||||
if (servers is String) {
|
|
||||||
val serverList = servers.split(",")
|
val serverList = servers.split(",")
|
||||||
serverList.forEach { server ->
|
serverList.forEach { server ->
|
||||||
val parts = server.split(" : ")
|
val parts = server.split(" : ")
|
||||||
|
@ -67,9 +72,8 @@ object BackupUtils {
|
||||||
viewModel.insert(DnsServer(0, server, ""))
|
viewModel.insert(DnsServer(0, server, ""))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
sharedPreferences.autoMode = map[AUTO_MODE] as? Int ?: 0
|
sharedPreferences.autoMode = legacyBackup.autoMode?: 0
|
||||||
sharedPreferences.requireUnlock = map[REQUIRE_UNLOCK] as? Boolean ?: false
|
sharedPreferences.requireUnlock = legacyBackup.requireUnlock?: false
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -6,15 +6,16 @@ buildscript {
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:8.5.2'
|
classpath 'com.android.tools.build:gradle:8.5.2'
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.10"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:2.0.20"
|
||||||
|
|
||||||
// NOTE: Do not place your application dependencies here; they belong
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
// in the individual module build.gradle files
|
// in the individual module build.gradle files
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
plugins {
|
plugins {
|
||||||
id 'org.jetbrains.kotlin.android' version '1.9.10' apply false
|
id 'org.jetbrains.kotlin.android' version '2.0.20' apply false
|
||||||
id "com.google.devtools.ksp" version "1.9.10-1.0.13" apply false
|
id 'org.jetbrains.kotlin.plugin.serialization' version '2.0.20'
|
||||||
|
id "com.google.devtools.ksp" version "2.0.20-1.0.25" apply false
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.register('clean', Delete) {
|
tasks.register('clean', Delete) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue