Switch from gson to kotlinx.serialization

Kotlin offers better null and type safety compared to gson

Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
This commit is contained in:
Aayush Gupta
2025-05-16 16:05:45 +08:00
parent e39bc3b8a5
commit eda01a6ec0
24 changed files with 96 additions and 85 deletions

View File

@@ -145,7 +145,6 @@ dependencies {
//Google's Goodies //Google's Goodies
implementation(libs.google.android.material) implementation(libs.google.android.material)
implementation(libs.google.gson)
implementation(libs.google.protobuf.javalite) implementation(libs.google.protobuf.javalite)
//AndroidX //AndroidX

View File

@@ -19,6 +19,9 @@
package com.aurora.store.data.model package com.aurora.store.data.model
import kotlinx.serialization.Serializable
@Serializable
data class Auth( data class Auth(
val email: String, val email: String,
val auth: String val auth: String

View File

@@ -21,12 +21,16 @@ package com.aurora.store.data.model
import android.os.Parcelable import android.os.Parcelable
import kotlinx.parcelize.Parcelize import kotlinx.parcelize.Parcelize
import kotlinx.serialization.Serializable
@Serializable
data class ExodusReport( data class ExodusReport(
val creator: String = String(), val creator: String = String(),
val name: String = String(), val name: String = String(),
val reports: List<Report> = listOf() val reports: List<Report> = listOf()
) )
@Serializable
@Parcelize @Parcelize
data class Report( data class Report(
val id: Int = 0, val id: Int = 0,
@@ -38,6 +42,7 @@ data class Report(
val trackers: List<Int> = listOf() val trackers: List<Int> = listOf()
) : Parcelable ) : Parcelable
@Serializable
data class ExodusTracker( data class ExodusTracker(
val id: Int = 0, val id: Int = 0,
val name: String = String(), val name: String = String(),

View File

@@ -19,6 +19,9 @@
package com.aurora.store.data.model package com.aurora.store.data.model
import kotlinx.serialization.Serializable
@Serializable
data class Filter( data class Filter(
val appsWithAds: Boolean = true, val appsWithAds: Boolean = true,
val appsWithIAP: Boolean = true, val appsWithIAP: Boolean = true,

View File

@@ -2,27 +2,32 @@ package com.aurora.store.data.model
import androidx.annotation.StringRes import androidx.annotation.StringRes
import com.aurora.store.R import com.aurora.store.R
import com.google.gson.annotations.SerializedName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
data class PlexusReport( data class PlexusReport(
@SerializedName("data") @SerialName("data")
val report: Data? val report: Data?
) )
@Serializable
data class Data( data class Data(
val name: String, val name: String,
val scores: Scores, val scores: Scores,
@SerializedName("updated_at") @SerialName("updated_at")
val updatedAt: String val updatedAt: String
) )
@Serializable
data class Scores( data class Scores(
@SerializedName("micro_g") @SerialName("micro_g")
val microG: Rating, val microG: Rating,
@SerializedName("native") @SerialName("native")
val aosp: Rating val aosp: Rating
) )
@Serializable
data class Rating( data class Rating(
val denominator: Float, val denominator: Float,
val numerator: Float, val numerator: Float,

View File

@@ -27,14 +27,16 @@ import com.aurora.gplayapi.data.models.PlayFile
import com.aurora.store.BuildConfig import com.aurora.store.BuildConfig
import com.aurora.store.R import com.aurora.store.R
import com.aurora.store.util.CertUtil import com.aurora.store.util.CertUtil
import com.google.gson.annotations.SerializedName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
data class SelfUpdate( data class SelfUpdate(
@SerializedName("version_name") var versionName: String = String(), @SerialName("version_name") var versionName: String = String(),
@SerializedName("version_code") var versionCode: Long = 0, @SerialName("version_code") var versionCode: Long = 0,
@SerializedName("aurora_build") var auroraBuild: String = String(), @SerialName("aurora_build") var auroraBuild: String = String(),
@SerializedName("fdroid_build") var fdroidBuild: String = String(), @SerialName("fdroid_build") var fdroidBuild: String = String(),
@SerializedName("updated_on") var updatedOn: String = String(), @SerialName("updated_on") var updatedOn: String = String(),
val changelog: String = String(), val changelog: String = String(),
val size: Long = 0L, val size: Long = 0L,
val timestamp: Long = 0L val timestamp: Long = 0L

View File

@@ -28,12 +28,12 @@ import com.aurora.store.data.model.Algorithm
import com.aurora.store.data.model.ProxyInfo import com.aurora.store.data.model.ProxyInfo
import com.aurora.store.util.Preferences import com.aurora.store.util.Preferences
import com.aurora.store.util.Preferences.PREFERENCE_PROXY_INFO import com.aurora.store.util.Preferences.PREFERENCE_PROXY_INFO
import com.google.gson.Gson
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides
import dagger.hilt.InstallIn import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent import dagger.hilt.components.SingletonComponent
import kotlinx.serialization.json.Json
import okhttp3.CertificatePinner import okhttp3.CertificatePinner
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import java.io.ByteArrayInputStream import java.io.ByteArrayInputStream
@@ -95,10 +95,10 @@ object OkHttpClientModule {
@Provides @Provides
@Singleton @Singleton
fun providesProxyInstance(@ApplicationContext context: Context, gson: Gson): Proxy? { fun providesProxyInstance(@ApplicationContext context: Context, json: Json): Proxy? {
val proxyInfoString = Preferences.getString(context, PREFERENCE_PROXY_INFO) val proxyInfoString = Preferences.getString(context, PREFERENCE_PROXY_INFO)
if (proxyInfoString.isNotBlank() && proxyInfoString != "{}") { if (proxyInfoString.isNotBlank() && proxyInfoString != "{}") {
val proxyInfo = gson.fromJson(proxyInfoString, ProxyInfo::class.java) val proxyInfo = json.decodeFromString<ProxyInfo>(proxyInfoString)
val proxy = Proxy( val proxy = Proxy(
if (proxyInfo.protocol.removeSuffix("5") == "SOCKS") Proxy.Type.SOCKS else Proxy.Type.HTTP, if (proxyInfo.protocol.removeSuffix("5") == "SOCKS") Proxy.Type.SOCKS else Proxy.Type.HTTP,

View File

@@ -23,7 +23,6 @@ import android.content.Context
import android.util.Log import android.util.Log
import com.aurora.gplayapi.data.models.AuthData import com.aurora.gplayapi.data.models.AuthData
import com.aurora.gplayapi.data.models.PlayResponse import com.aurora.gplayapi.data.models.PlayResponse
import com.aurora.gplayapi.helpers.AppDetailsHelper
import com.aurora.gplayapi.helpers.AuthHelper import com.aurora.gplayapi.helpers.AuthHelper
import com.aurora.gplayapi.network.IHttpClient import com.aurora.gplayapi.network.IHttpClient
import com.aurora.store.R import com.aurora.store.R
@@ -32,17 +31,17 @@ import com.aurora.store.data.model.Auth
import com.aurora.store.util.Preferences import com.aurora.store.util.Preferences
import com.aurora.store.util.Preferences.PREFERENCE_AUTH_DATA import com.aurora.store.util.Preferences.PREFERENCE_AUTH_DATA
import com.aurora.store.util.Preferences.PREFERENCE_DISPENSER_URLS import com.aurora.store.util.Preferences.PREFERENCE_DISPENSER_URLS
import com.google.gson.Gson
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import kotlinx.serialization.json.Json
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@Singleton @Singleton
class AuthProvider @Inject constructor( class AuthProvider @Inject constructor(
@ApplicationContext private val context: Context, @ApplicationContext private val context: Context,
private val gson: Gson, private val json: Json,
private val spoofProvider: SpoofProvider, private val spoofProvider: SpoofProvider,
private val httpClient: IHttpClient private val httpClient: IHttpClient
) { ) {
@@ -60,7 +59,7 @@ class AuthProvider @Inject constructor(
Log.i(TAG, "Loading saved AuthData") Log.i(TAG, "Loading saved AuthData")
val rawAuth: String = Preferences.getString(context, PREFERENCE_AUTH_DATA) val rawAuth: String = Preferences.getString(context, PREFERENCE_AUTH_DATA)
return if (rawAuth.isNotBlank()) { return if (rawAuth.isNotBlank()) {
gson.fromJson(rawAuth, AuthData::class.java) json.decodeFromString<AuthData>(rawAuth)
} else { } else {
null null
} }
@@ -117,7 +116,7 @@ class AuthProvider @Inject constructor(
if (!it.isSuccessful) throwError(it, context) if (!it.isSuccessful) throwError(it, context)
} }
val auth = gson.fromJson(String(playResponse.responseBytes), Auth::class.java) val auth = json.decodeFromString<Auth>(String(playResponse.responseBytes))
return@withContext Result.success( return@withContext Result.success(
AuthHelper.build( AuthHelper.build(
email = auth.email, email = auth.email,
@@ -139,7 +138,7 @@ class AuthProvider @Inject constructor(
* Saves given [AuthData] * Saves given [AuthData]
*/ */
fun saveAuthData(authData: AuthData) { fun saveAuthData(authData: AuthData) {
Preferences.putString(context, PREFERENCE_AUTH_DATA, gson.toJson(authData)) Preferences.putString(context, PREFERENCE_AUTH_DATA, json.encodeToString(authData))
} }
/** /**

View File

@@ -24,23 +24,22 @@ import android.content.SharedPreferences
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import com.aurora.extensions.isNAndAbove import com.aurora.extensions.isNAndAbove
import com.aurora.store.util.Preferences import com.aurora.store.util.Preferences
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.serialization.json.Json
import java.io.File import java.io.File
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@Singleton @Singleton
class BlacklistProvider @Inject constructor( class BlacklistProvider @Inject constructor(
private val gson: Gson, private val json: Json,
@ApplicationContext val context: Context, @ApplicationContext val context: Context,
) { ) {
private val PREFERENCE_BLACKLIST = "PREFERENCE_BLACKLIST" private val PREFERENCE_BLACKLIST = "PREFERENCE_BLACKLIST"
var blacklist: MutableSet<String> var blacklist: MutableSet<String>
set(value) = Preferences.putString(context, PREFERENCE_BLACKLIST, gson.toJson(value)) set(value) = Preferences.putString(context, PREFERENCE_BLACKLIST, json.encodeToString(value))
get() { get() {
return try { return try {
val rawBlacklist = if (isNAndAbove) { val rawBlacklist = if (isNAndAbove) {
@@ -66,7 +65,7 @@ class BlacklistProvider @Inject constructor(
if (rawBlacklist!!.isEmpty()) if (rawBlacklist!!.isEmpty())
mutableSetOf() mutableSetOf()
else else
gson.fromJson(rawBlacklist, object : TypeToken<Set<String?>?>() {}.type) json.decodeFromString<MutableSet<String>>(rawBlacklist)
} catch (e: Exception) { } catch (e: Exception) {
mutableSetOf() mutableSetOf()
} }

View File

@@ -23,14 +23,14 @@ import android.content.Context
import com.aurora.store.data.model.Filter import com.aurora.store.data.model.Filter
import com.aurora.store.util.Preferences import com.aurora.store.util.Preferences
import com.aurora.store.util.remove import com.aurora.store.util.remove
import com.google.gson.Gson
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.serialization.json.Json
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@Singleton @Singleton
class FilterProvider @Inject constructor( class FilterProvider @Inject constructor(
private val gson: Gson, private val json: Json,
@ApplicationContext private val context: Context @ApplicationContext private val context: Context
) { ) {
@@ -45,10 +45,10 @@ class FilterProvider @Inject constructor(
fun getSavedFilter(): Filter { fun getSavedFilter(): Filter {
val rawFilter = Preferences.getString(context, PREFERENCE_FILTER) val rawFilter = Preferences.getString(context, PREFERENCE_FILTER)
return gson.fromJson(rawFilter.ifEmpty { "{}" }, Filter::class.java) return json.decodeFromString<Filter>(rawFilter.ifEmpty { "{}" })
} }
fun saveFilter(filter: Filter) { fun saveFilter(filter: Filter) {
Preferences.putString(context, PREFERENCE_FILTER, gson.toJson(filter)) Preferences.putString(context, PREFERENCE_FILTER, json.encodeToString(filter))
} }
} }

View File

@@ -23,8 +23,8 @@ import android.content.Context
import com.aurora.store.R import com.aurora.store.R
import com.aurora.store.util.Preferences import com.aurora.store.util.Preferences
import com.aurora.store.util.Preferences.PREFERENCE_VENDING_VERSION import com.aurora.store.util.Preferences.PREFERENCE_VENDING_VERSION
import com.google.gson.Gson
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.serialization.json.Json
import java.util.Locale import java.util.Locale
import java.util.Properties import java.util.Properties
import javax.inject.Inject import javax.inject.Inject
@@ -35,7 +35,7 @@ import javax.inject.Singleton
*/ */
@Singleton @Singleton
class SpoofProvider @Inject constructor( class SpoofProvider @Inject constructor(
private val gson: Gson, private val json: Json,
@ApplicationContext val context: Context, @ApplicationContext val context: Context,
) : SpoofDeviceProvider(context) { ) : SpoofDeviceProvider(context) {
@@ -85,9 +85,8 @@ class SpoofProvider @Inject constructor(
.build() .build()
private val spoofDeviceProperties: Properties private val spoofDeviceProperties: Properties
get() = gson.fromJson( get() = json.decodeFromString<Properties>(
Preferences.getString(context, DEVICE_SPOOF_PROPERTIES), Preferences.getString(context, DEVICE_SPOOF_PROPERTIES)
Properties::class.java
) )
fun setSpoofLocale(locale: Locale) { fun setSpoofLocale(locale: Locale) {
@@ -98,7 +97,7 @@ class SpoofProvider @Inject constructor(
fun setSpoofDeviceProperties(properties: Properties) { fun setSpoofDeviceProperties(properties: Properties) {
Preferences.putBoolean(context, DEVICE_SPOOF_ENABLED, true) Preferences.putBoolean(context, DEVICE_SPOOF_ENABLED, true)
Preferences.putString(context, DEVICE_SPOOF_PROPERTIES, gson.toJson(properties)) Preferences.putString(context, DEVICE_SPOOF_PROPERTIES, json.encodeToString(properties))
} }
fun removeSpoofLocale() { fun removeSpoofLocale() {

View File

@@ -3,34 +3,31 @@ package com.aurora.store.data.room.download
import androidx.room.ProvidedTypeConverter import androidx.room.ProvidedTypeConverter
import androidx.room.TypeConverter import androidx.room.TypeConverter
import com.aurora.gplayapi.data.models.PlayFile import com.aurora.gplayapi.data.models.PlayFile
import com.google.gson.Gson import kotlinx.serialization.json.Json
import com.google.gson.reflect.TypeToken
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@Singleton @Singleton
@ProvidedTypeConverter @ProvidedTypeConverter
class DownloadConverter @Inject constructor(private val gson: Gson) { class DownloadConverter @Inject constructor(private val json: Json) {
@TypeConverter @TypeConverter
fun toSharedLibList(string: String): List<SharedLib> { fun toSharedLibList(string: String): List<SharedLib> {
val listType = object : TypeToken<List<SharedLib>>() {}.type return json.decodeFromString<List<SharedLib>>(string)
return gson.fromJson(string, listType)
} }
@TypeConverter @TypeConverter
fun fromSharedLibList(list: List<SharedLib>): String { fun fromSharedLibList(list: List<SharedLib>): String {
return gson.toJson(list) return json.encodeToString(list)
} }
@TypeConverter @TypeConverter
fun toGPlayFileList(string: String): List<PlayFile> { fun toGPlayFileList(string: String): List<PlayFile> {
val listType = object : TypeToken<List<PlayFile>>() {}.type return json.decodeFromString<List<PlayFile>>(string)
return gson.fromJson(string, listType)
} }
@TypeConverter @TypeConverter
fun fromGPlayFileList(list: List<PlayFile>): String { fun fromGPlayFileList(list: List<PlayFile>): String {
return gson.toJson(list) return json.encodeToString(list)
} }
} }

View File

@@ -4,7 +4,9 @@ import android.os.Parcelable
import com.aurora.gplayapi.data.models.App import com.aurora.gplayapi.data.models.App
import com.aurora.gplayapi.data.models.PlayFile import com.aurora.gplayapi.data.models.PlayFile
import kotlinx.parcelize.Parcelize import kotlinx.parcelize.Parcelize
import kotlinx.serialization.Serializable
@Serializable
@Parcelize @Parcelize
data class SharedLib( data class SharedLib(
val packageName: String, val packageName: String,

View File

@@ -6,7 +6,9 @@ import androidx.room.PrimaryKey
import com.aurora.gplayapi.data.models.App import com.aurora.gplayapi.data.models.App
import com.aurora.gplayapi.data.models.Artwork import com.aurora.gplayapi.data.models.Artwork
import kotlinx.parcelize.Parcelize import kotlinx.parcelize.Parcelize
import kotlinx.serialization.Serializable
@Serializable
@Parcelize @Parcelize
@Entity(tableName = "favourite") @Entity(tableName = "favourite")
data class Favourite( data class Favourite(

View File

@@ -1,7 +1,9 @@
package com.aurora.store.data.room.favourite package com.aurora.store.data.room.favourite
import com.aurora.store.BuildConfig import com.aurora.store.BuildConfig
import kotlinx.serialization.Serializable
@Serializable
data class ImportExport( data class ImportExport(
val favourites: List<Favourite>, val favourites: List<Favourite>,
val auroraStoreVersion: Int = BuildConfig.VERSION_CODE, val auroraStoreVersion: Int = BuildConfig.VERSION_CODE,

View File

@@ -29,11 +29,11 @@ import com.aurora.store.util.NotificationUtil
import com.aurora.store.util.PackageUtil import com.aurora.store.util.PackageUtil
import com.aurora.store.util.Preferences import com.aurora.store.util.Preferences
import com.aurora.store.util.Preferences.PREFERENCE_UPDATES_AUTO import com.aurora.store.util.Preferences.PREFERENCE_UPDATES_AUTO
import com.google.gson.Gson
import dagger.assisted.Assisted import dagger.assisted.Assisted
import dagger.assisted.AssistedInject import dagger.assisted.AssistedInject
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import kotlinx.serialization.json.Json
import java.util.Locale import java.util.Locale
/** /**
@@ -46,7 +46,7 @@ import java.util.Locale
*/ */
@HiltWorker @HiltWorker
class UpdateWorker @AssistedInject constructor( class UpdateWorker @AssistedInject constructor(
private val gson: Gson, private val json: Json,
private val blacklistProvider: BlacklistProvider, private val blacklistProvider: BlacklistProvider,
private val httpClient: IHttpClient, private val httpClient: IHttpClient,
private val updateDao: UpdateDao, private val updateDao: UpdateDao,
@@ -187,10 +187,7 @@ class UpdateWorker @AssistedInject constructor(
try { try {
val response = httpClient.get(updateUrl, mapOf()) val response = httpClient.get(updateUrl, mapOf())
val selfUpdate = gson.fromJson( val selfUpdate = json.decodeFromString<SelfUpdate>(String(response.responseBytes))
String(response.responseBytes),
SelfUpdate::class.java
)
val isUpdate = when (BuildType.CURRENT) { val isUpdate = when (BuildType.CURRENT) {
BuildType.NIGHTLY, BuildType.NIGHTLY,

View File

@@ -1,11 +1,10 @@
package com.aurora.store.module package com.aurora.store.module
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides
import dagger.hilt.InstallIn import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent import dagger.hilt.components.SingletonComponent
import kotlinx.serialization.json.Json
import javax.inject.Singleton import javax.inject.Singleton
@Module @Module
@@ -14,9 +13,11 @@ object CommonModule {
@Singleton @Singleton
@Provides @Provides
fun providesGsonInstance(): Gson { fun providesJsonInstance(): Json {
return GsonBuilder() return Json {
.setPrettyPrinting() prettyPrint = true
.create() ignoreUnknownKeys = true
coerceInputValues = true
}
} }
} }

View File

@@ -79,7 +79,7 @@ class ProxyURLDialog: DialogFragment() {
val proxyInfo = CommonUtil.parseProxyUrl(url) val proxyInfo = CommonUtil.parseProxyUrl(url)
if (proxyInfo != null) { if (proxyInfo != null) {
save(PREFERENCE_PROXY_URL, url) save(PREFERENCE_PROXY_URL, url)
save(PREFERENCE_PROXY_INFO, viewModel.gson.toJson(proxyInfo)) save(PREFERENCE_PROXY_INFO, viewModel.json.encodeToString(proxyInfo))
toast(R.string.toast_proxy_success) toast(R.string.toast_proxy_success)
findNavController().navigate(R.id.forceRestartDialog) findNavController().navigate(R.id.forceRestartDialog)
return return

View File

@@ -33,19 +33,18 @@ import com.aurora.store.data.providers.BlacklistProvider
import com.aurora.store.util.CertUtil import com.aurora.store.util.CertUtil
import com.aurora.store.util.PackageUtil import com.aurora.store.util.PackageUtil
import com.aurora.store.util.Preferences import com.aurora.store.util.Preferences
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.serialization.json.Json
import javax.inject.Inject import javax.inject.Inject
@HiltViewModel @HiltViewModel
class BlacklistViewModel @Inject constructor( class BlacklistViewModel @Inject constructor(
private val gson: Gson, private val json: Json,
private val updateHelper: UpdateHelper, private val updateHelper: UpdateHelper,
private val blacklistProvider: BlacklistProvider, private val blacklistProvider: BlacklistProvider,
@ApplicationContext private val context: Context @ApplicationContext private val context: Context
@@ -132,9 +131,8 @@ class BlacklistViewModel @Inject constructor(
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(Dispatchers.IO) {
try { try {
context.contentResolver.openInputStream(uri)?.use { context.contentResolver.openInputStream(uri)?.use {
val importedSet: MutableSet<String> = gson.fromJson( val importedSet = json.decodeFromString<MutableSet<String>>(
it.bufferedReader().readText(), it.bufferedReader().readText()
object : TypeToken<MutableSet<String?>?>() {}.type
) )
val validImportedSet = importedSet val validImportedSet = importedSet
@@ -155,7 +153,7 @@ class BlacklistViewModel @Inject constructor(
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(Dispatchers.IO) {
try { try {
context.contentResolver.openOutputStream(uri)?.use { context.contentResolver.openOutputStream(uri)?.use {
it.write(gson.toJson(blacklistProvider.blacklist).encodeToByteArray()) it.write(json.encodeToString(blacklistProvider.blacklist).encodeToByteArray())
} }
} catch (exception: Exception) { } catch (exception: Exception) {
Log.e(TAG, "Failed to export blacklist", exception) Log.e(TAG, "Failed to export blacklist", exception)

View File

@@ -27,18 +27,18 @@ import androidx.lifecycle.viewModelScope
import com.aurora.store.data.room.favourite.Favourite import com.aurora.store.data.room.favourite.Favourite
import com.aurora.store.data.room.favourite.FavouriteDao import com.aurora.store.data.room.favourite.FavouriteDao
import com.aurora.store.data.room.favourite.ImportExport import com.aurora.store.data.room.favourite.ImportExport
import com.google.gson.Gson
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.serialization.json.Json
import javax.inject.Inject import javax.inject.Inject
@HiltViewModel @HiltViewModel
class FavouriteViewModel @Inject constructor( class FavouriteViewModel @Inject constructor(
private val favouriteDao: FavouriteDao, private val favouriteDao: FavouriteDao,
private val gson: Gson private val json: Json
) : ViewModel() { ) : ViewModel() {
private val TAG = FavouriteViewModel::class.java.simpleName private val TAG = FavouriteViewModel::class.java.simpleName
@@ -49,9 +49,8 @@ class FavouriteViewModel @Inject constructor(
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(Dispatchers.IO) {
try { try {
context.contentResolver.openInputStream(uri)?.use { context.contentResolver.openInputStream(uri)?.use {
val importExport = gson.fromJson( val importExport = json.decodeFromString<ImportExport>(
it.bufferedReader().readText(), it.bufferedReader().readText()
ImportExport::class.java
) )
favouriteDao.insertAll( favouriteDao.insertAll(
@@ -68,7 +67,10 @@ class FavouriteViewModel @Inject constructor(
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(Dispatchers.IO) {
try { try {
context.contentResolver.openOutputStream(uri)?.use { context.contentResolver.openOutputStream(uri)?.use {
it.write(gson.toJson(ImportExport(favouritesList.value!!)).encodeToByteArray()) it.write(
json.encodeToString(ImportExport(favouritesList.value!!))
.encodeToByteArray()
)
} }
} catch (exception: Exception) { } catch (exception: Exception) {
Log.e(TAG, "Failed to export favourites", exception) Log.e(TAG, "Failed to export favourites", exception)

View File

@@ -30,20 +30,20 @@ import com.aurora.store.data.providers.BlacklistProvider
import com.aurora.store.data.room.favourite.Favourite import com.aurora.store.data.room.favourite.Favourite
import com.aurora.store.data.room.favourite.ImportExport import com.aurora.store.data.room.favourite.ImportExport
import com.aurora.store.util.PackageUtil import com.aurora.store.util.PackageUtil
import com.google.gson.Gson
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.serialization.json.Json
import javax.inject.Inject import javax.inject.Inject
@HiltViewModel @HiltViewModel
class InstalledViewModel @Inject constructor( class InstalledViewModel @Inject constructor(
@ApplicationContext private val context: Context, @ApplicationContext private val context: Context,
private val blacklistProvider: BlacklistProvider, private val blacklistProvider: BlacklistProvider,
private val gson: Gson, private val json: Json,
private val webAppDetailsHelper: WebAppDetailsHelper private val webAppDetailsHelper: WebAppDetailsHelper
) : ViewModel() { ) : ViewModel() {
@@ -83,7 +83,7 @@ class InstalledViewModel @Inject constructor(
Favourite.fromApp(app, Favourite.Mode.IMPORT) Favourite.fromApp(app, Favourite.Mode.IMPORT)
} }
context.contentResolver.openOutputStream(uri)?.use { context.contentResolver.openOutputStream(uri)?.use {
it.write(gson.toJson(ImportExport(favourites)).encodeToByteArray()) it.write(json.encodeToString(ImportExport(favourites)).encodeToByteArray())
} }
} catch (exception: Exception) { } catch (exception: Exception) {
Log.e(TAG, "Failed to installed apps", exception) Log.e(TAG, "Failed to installed apps", exception)

View File

@@ -23,7 +23,6 @@ import com.aurora.store.data.providers.AuthProvider
import com.aurora.store.data.room.favourite.Favourite import com.aurora.store.data.room.favourite.Favourite
import com.aurora.store.data.room.favourite.FavouriteDao import com.aurora.store.data.room.favourite.FavouriteDao
import com.aurora.store.util.PackageUtil import com.aurora.store.util.PackageUtil
import com.google.gson.Gson
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@@ -35,6 +34,7 @@ import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.serialization.json.Json
import org.json.JSONObject import org.json.JSONObject
import javax.inject.Inject import javax.inject.Inject
import com.aurora.gplayapi.data.models.datasafety.Report as DataSafetyReport import com.aurora.gplayapi.data.models.datasafety.Report as DataSafetyReport
@@ -49,7 +49,7 @@ class AppDetailsViewModel @Inject constructor(
private val downloadHelper: DownloadHelper, private val downloadHelper: DownloadHelper,
private val favouriteDao: FavouriteDao, private val favouriteDao: FavouriteDao,
private val httpClient: IHttpClient, private val httpClient: IHttpClient,
private val gson: Gson private val json: Json
) : ViewModel() { ) : ViewModel() {
private val TAG = AppDetailsViewModel::class.java.simpleName private val TAG = AppDetailsViewModel::class.java.simpleName
@@ -159,7 +159,7 @@ class AppDetailsViewModel @Inject constructor(
val plexusReport = plexusReportStash.getOrPut(packageName) { val plexusReport = plexusReportStash.getOrPut(packageName) {
val url = "${Constants.PLEXUS_API_URL}/${packageName}/?scores=true" val url = "${Constants.PLEXUS_API_URL}/${packageName}/?scores=true"
val playResponse = httpClient.get(url, emptyMap()) val playResponse = httpClient.get(url, emptyMap())
gson.fromJson(String(playResponse.responseBytes), PlexusReport::class.java) json.decodeFromString<PlexusReport>(String(playResponse.responseBytes))
} }
_plexusReport.emit(plexusReport) _plexusReport.emit(plexusReport)
@@ -284,9 +284,7 @@ class AppDetailsViewModel @Inject constructor(
try { try {
val jsonObject = JSONObject(response) val jsonObject = JSONObject(response)
val exodusObject = jsonObject.getJSONObject(packageName) val exodusObject = jsonObject.getJSONObject(packageName)
val exodusReport: ExodusReport = gson.fromJson( val exodusReport = json.decodeFromString<ExodusReport>(exodusObject.toString())
exodusObject.toString(), ExodusReport::class.java
)
return exodusReport.reports return exodusReport.reports
} catch (e: Exception) { } catch (e: Exception) {

View File

@@ -6,9 +6,9 @@
package com.aurora.store.viewmodel.preferences package com.aurora.store.viewmodel.preferences
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import com.google.gson.Gson
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.serialization.json.Json
import javax.inject.Inject import javax.inject.Inject
@HiltViewModel @HiltViewModel
class ProxyURLViewModel @Inject constructor(val gson: Gson) : ViewModel() class ProxyURLViewModel @Inject constructor(val json: Json) : ViewModel()

View File

@@ -9,8 +9,7 @@ composeBom = "2025.05.00"
core = "1.16.0" core = "1.16.0"
epoxy = "5.1.4" epoxy = "5.1.4"
espresso = "3.6.1" espresso = "3.6.1"
gplayapi = "3.5.0" gplayapi = "3.5.2"
gson = "2.13.1"
hiddenapibypass = "6.1" hiddenapibypass = "6.1"
hilt = "2.56.2" hilt = "2.56.2"
hiltWork = "1.2.0" hiltWork = "1.2.0"
@@ -74,7 +73,6 @@ coil-network = { module = "io.coil-kt.coil3:coil-network-okhttp", version.ref =
facebook-shimmer = { module = "com.facebook.shimmer:shimmer", version.ref = "shimmer" } facebook-shimmer = { module = "com.facebook.shimmer:shimmer", version.ref = "shimmer" }
github-topjohnwu-libsu = { module = "com.github.topjohnwu.libsu:core", version.ref = "libsu" } github-topjohnwu-libsu = { module = "com.github.topjohnwu.libsu:core", version.ref = "libsu" }
google-android-material = { module = "com.google.android.material:material", version.ref = "material" } google-android-material = { module = "com.google.android.material:material", version.ref = "material" }
google-gson = { module = "com.google.code.gson:gson", version.ref = "gson" }
google-protobuf-javalite = { module = "com.google.protobuf:protobuf-javalite", version.ref = "protobufJavalite" } google-protobuf-javalite = { module = "com.google.protobuf:protobuf-javalite", version.ref = "protobufJavalite" }
google-truth = { module = "com.google.truth:truth", version.ref = "truth" } google-truth = { module = "com.google.truth:truth", version.ref = "truth" }
hilt-android-compiler = { module = "com.google.dagger:hilt-android-compiler", version.ref = "hilt" } hilt-android-compiler = { module = "com.google.dagger:hilt-android-compiler", version.ref = "hilt" }