updated proguard-rules.pro
This commit is contained in:
Vendored
+21
-1
@@ -21,4 +21,24 @@
|
||||
#-renamesourcefileattribute SourceFile
|
||||
|
||||
# Suppress Guava J2ObjC annotation missing classes
|
||||
-dontwarn com.google.j2objc.annotations.**
|
||||
-dontwarn com.google.j2objc.annotations.**
|
||||
|
||||
# Keep kotlinx.serialization generated serializers
|
||||
-keepclassmembers class **$$serializer { *; }
|
||||
|
||||
# Keep Serializable classes
|
||||
-keep @kotlinx.serialization.Serializable class * { *; }
|
||||
|
||||
# Keep sealed subclasses of RecurrenceRule
|
||||
-keep class com.flux.data.model.RecurrenceRule** { *; }
|
||||
|
||||
# Keep enum constants
|
||||
-keepclassmembers enum * {
|
||||
*;
|
||||
}
|
||||
|
||||
# Keep polymorphic serialization metadata
|
||||
-keepattributes *Annotation*
|
||||
|
||||
# Keep Kotlin metadata (critical)
|
||||
-keep class kotlin.Metadata { *; }
|
||||
|
||||
@@ -30,10 +30,11 @@ import com.google.gson.Gson
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.vladsch.flexmark.html2md.converter.FlexmarkHtmlConverter
|
||||
import kotlinx.serialization.json.Json
|
||||
import java.util.UUID
|
||||
|
||||
@Database(
|
||||
entities = [EventModel::class, LabelModel::class, EventInstanceModel::class, SettingsModel::class, NotesModel::class, HabitModel::class, HabitInstanceModel::class, WorkspaceModel::class, TodoModel::class, JournalModel::class],
|
||||
version = 9,
|
||||
version = 4,
|
||||
exportSchema = false
|
||||
)
|
||||
@TypeConverters(Converter::class)
|
||||
@@ -64,48 +65,56 @@ val MIGRATION_2_3 = object : Migration(2, 3) {
|
||||
db.execSQL("ALTER TABLE EventModel ADD COLUMN endDateTime INTEGER NOT NULL DEFAULT -1")
|
||||
}
|
||||
}
|
||||
|
||||
val MIGRATION_3_4 = object : Migration(3, 4) {
|
||||
|
||||
override fun migrate(db: SupportSQLiteDatabase) {
|
||||
|
||||
// Add temp column
|
||||
/* ============================================================
|
||||
1. WorkspaceModel — selectedSpaces normalization (CRASH FIX)
|
||||
============================================================ */
|
||||
|
||||
db.execSQL("""
|
||||
ALTER TABLE WorkspaceModel
|
||||
ADD COLUMN selectedSpaces_new TEXT NOT NULL DEFAULT '[]'
|
||||
ADD COLUMN selectedSpaces_new TEXT NOT NULL DEFAULT ''
|
||||
""")
|
||||
|
||||
val cursor = db.query(
|
||||
val wsCursor = db.query(
|
||||
"SELECT workspaceId, selectedSpaces FROM WorkspaceModel"
|
||||
)
|
||||
|
||||
while (cursor.moveToNext()) {
|
||||
val id = cursor.getString(0)
|
||||
val raw = cursor.getString(1)
|
||||
while (wsCursor.moveToNext()) {
|
||||
|
||||
val spaces = Json.decodeFromString<List<Int>>(raw)
|
||||
.toMutableSet()
|
||||
val id = wsCursor.getString(0)
|
||||
val raw = wsCursor.getString(1) ?: ""
|
||||
|
||||
// 1. Merge Calendar (4) → Events (3)
|
||||
if (spaces.remove(4)) {
|
||||
spaces.add(3)
|
||||
// ---- SAFE PARSE (CSV + JSON tolerant) ----
|
||||
val spaces = try {
|
||||
Json.decodeFromString<List<Int>>(raw).toMutableSet()
|
||||
} catch (_: Exception) {
|
||||
raw.split(",")
|
||||
.mapNotNull { it.trim().toIntOrNull() }
|
||||
.toMutableSet()
|
||||
}
|
||||
|
||||
// 2. Downgrade IDs above 4
|
||||
// Merge Calendar (4) → Events (3)
|
||||
if (spaces.remove(4)) spaces.add(3)
|
||||
|
||||
// Shift IDs > 4
|
||||
val normalized = spaces.map {
|
||||
if (it > 4) it - 1 else it
|
||||
}.toSet()
|
||||
|
||||
val newJson = Json.encodeToString(normalized.toList())
|
||||
// Store as CSV (since converter still CSV)
|
||||
val newCsv = normalized.joinToString(",")
|
||||
|
||||
db.execSQL(
|
||||
"UPDATE WorkspaceModel SET selectedSpaces_new = ? WHERE workspaceId = ?",
|
||||
arrayOf(newJson, id)
|
||||
arrayOf(newCsv, id)
|
||||
)
|
||||
}
|
||||
|
||||
cursor.close()
|
||||
wsCursor.close()
|
||||
|
||||
// Recreate table (SQLite cannot drop columns)
|
||||
db.execSQL("""
|
||||
CREATE TABLE WorkspaceModel_new (
|
||||
workspaceId TEXT NOT NULL PRIMARY KEY,
|
||||
@@ -130,109 +139,86 @@ val MIGRATION_3_4 = object : Migration(3, 4) {
|
||||
|
||||
db.execSQL("DROP TABLE WorkspaceModel")
|
||||
db.execSQL("ALTER TABLE WorkspaceModel_new RENAME TO WorkspaceModel")
|
||||
}
|
||||
}
|
||||
|
||||
val MIGRATION_4_5 = object : Migration(4, 5) {
|
||||
override fun migrate(db: SupportSQLiteDatabase) {
|
||||
// Add storageRootUri column with default value null
|
||||
db.execSQL("ALTER TABLE SettingsModel ADD COLUMN storageRootUri TEXT")
|
||||
}
|
||||
}
|
||||
|
||||
val MIGRATION_5_6 = object : Migration(5, 6) {
|
||||
override fun migrate(db: SupportSQLiteDatabase) {
|
||||
/* ============================================================
|
||||
2. SettingsModel columns (4→6)
|
||||
============================================================ */
|
||||
|
||||
db.execSQL(
|
||||
"""
|
||||
"ALTER TABLE SettingsModel ADD COLUMN storageRootUri TEXT"
|
||||
)
|
||||
|
||||
db.execSQL("""
|
||||
ALTER TABLE SettingsModel
|
||||
ADD COLUMN startWithReadView INTEGER NOT NULL DEFAULT 0
|
||||
""".trimIndent()
|
||||
)
|
||||
""")
|
||||
|
||||
db.execSQL(
|
||||
"""
|
||||
db.execSQL("""
|
||||
ALTER TABLE SettingsModel
|
||||
ADD COLUMN isLineNumbersVisible INTEGER NOT NULL DEFAULT 0
|
||||
""".trimIndent()
|
||||
)
|
||||
""")
|
||||
|
||||
db.execSQL(
|
||||
"""
|
||||
db.execSQL("""
|
||||
ALTER TABLE SettingsModel
|
||||
ADD COLUMN isLintValid INTEGER NOT NULL DEFAULT 0
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
}
|
||||
""")
|
||||
|
||||
val MIGRATION_6_7 = object : Migration(6, 7) {
|
||||
override fun migrate(db: SupportSQLiteDatabase) {
|
||||
// Migration to add 'id' field to TodoItem objects within the items JSON array
|
||||
// Since TodoItem is stored as JSON in the 'items' column of TodoModel,
|
||||
// we need to parse, update, and re-save the JSON data
|
||||
|
||||
val cursor = db.query("SELECT id, items FROM TodoModel")
|
||||
/* ============================================================
|
||||
3. TodoItem ID migration (6→7)
|
||||
============================================================ */
|
||||
|
||||
val todoCursor = db.query("SELECT id, items FROM TodoModel")
|
||||
val gson = Gson()
|
||||
|
||||
while (cursor.moveToNext()) {
|
||||
val todoId = cursor.getString(0)
|
||||
val itemsJson = cursor.getString(1)
|
||||
while (todoCursor.moveToNext()) {
|
||||
|
||||
val todoId = todoCursor.getString(0)
|
||||
val itemsJson = todoCursor.getString(1)
|
||||
|
||||
try {
|
||||
// Define a temporary class to represent old TodoItem without id
|
||||
data class OldTodoItem(
|
||||
val value: String,
|
||||
val isChecked: Boolean
|
||||
)
|
||||
|
||||
// Define new TodoItem with id field
|
||||
data class NewTodoItem(
|
||||
val id: String,
|
||||
val value: String,
|
||||
val isChecked: Boolean
|
||||
)
|
||||
|
||||
// Parse old format
|
||||
val oldItemsType = object : TypeToken<List<OldTodoItem>>() {}.type
|
||||
val oldItems: List<OldTodoItem> = try {
|
||||
gson.fromJson(itemsJson, oldItemsType)
|
||||
} catch (_: Exception) {
|
||||
// If it already has the new format, skip
|
||||
continue
|
||||
}
|
||||
val type = object : TypeToken<List<OldTodoItem>>() {}.type
|
||||
|
||||
// Convert to new format with generated IDs
|
||||
val newItems = oldItems.map { oldItem ->
|
||||
val oldItems: List<OldTodoItem> =
|
||||
gson.fromJson(itemsJson, type) ?: continue
|
||||
|
||||
val newItems = oldItems.map {
|
||||
NewTodoItem(
|
||||
id = java.util.UUID.randomUUID().toString(),
|
||||
value = oldItem.value,
|
||||
isChecked = oldItem.isChecked
|
||||
id = UUID.randomUUID().toString(),
|
||||
value = it.value,
|
||||
isChecked = it.isChecked
|
||||
)
|
||||
}
|
||||
|
||||
// Serialize back to JSON
|
||||
val newItemsJson = gson.toJson(newItems)
|
||||
|
||||
// Update the database
|
||||
db.execSQL(
|
||||
"UPDATE TodoModel SET items = ? WHERE id = ?",
|
||||
arrayOf(newItemsJson, todoId)
|
||||
arrayOf(gson.toJson(newItems), todoId)
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
// If migration fails for this record, log or skip
|
||||
// The TypeConverter will handle it at runtime as fallback
|
||||
e.printStackTrace()
|
||||
|
||||
} catch (_: Exception) {
|
||||
// Skip malformed rows
|
||||
}
|
||||
}
|
||||
|
||||
cursor.close()
|
||||
}
|
||||
}
|
||||
todoCursor.close()
|
||||
|
||||
val MIGRATION_7_8 = object : Migration(7, 8) {
|
||||
override fun migrate(db: SupportSQLiteDatabase) {
|
||||
|
||||
// 1. Create new table without `images`
|
||||
/* ============================================================
|
||||
4. Journal + Notes table rebuild (7→8)
|
||||
============================================================ */
|
||||
|
||||
db.execSQL("""
|
||||
CREATE TABLE journalmodel_new (
|
||||
journalId TEXT NOT NULL,
|
||||
@@ -241,23 +227,21 @@ val MIGRATION_7_8 = object : Migration(7, 8) {
|
||||
dateTime INTEGER NOT NULL,
|
||||
PRIMARY KEY(journalId)
|
||||
)
|
||||
""".trimIndent())
|
||||
""")
|
||||
|
||||
// 2. Copy data (ignore `images`)
|
||||
db.execSQL("""
|
||||
INSERT INTO journalmodel_new (journalId, workspaceId, text, dateTime)
|
||||
INSERT INTO journalmodel_new
|
||||
SELECT journalId, workspaceId, text, dateTime
|
||||
FROM JournalModel
|
||||
""".trimIndent())
|
||||
""")
|
||||
|
||||
// 3. Drop old table
|
||||
db.execSQL("DROP TABLE JournalModel")
|
||||
|
||||
// 4. Rename new table
|
||||
db.execSQL("ALTER TABLE journalmodel_new RENAME TO JournalModel")
|
||||
|
||||
db.execSQL(
|
||||
"""
|
||||
"ALTER TABLE journalmodel_new RENAME TO JournalModel"
|
||||
)
|
||||
|
||||
|
||||
db.execSQL("""
|
||||
CREATE TABLE NotesModel_new (
|
||||
notesId TEXT NOT NULL,
|
||||
workspaceId TEXT NOT NULL,
|
||||
@@ -268,21 +252,10 @@ val MIGRATION_7_8 = object : Migration(7, 8) {
|
||||
lastEdited INTEGER NOT NULL,
|
||||
PRIMARY KEY(notesId)
|
||||
)
|
||||
""".trimIndent()
|
||||
)
|
||||
""")
|
||||
|
||||
// 2. Copy data (skip `images`)
|
||||
db.execSQL(
|
||||
"""
|
||||
INSERT INTO NotesModel_new (
|
||||
notesId,
|
||||
workspaceId,
|
||||
title,
|
||||
description,
|
||||
isPinned,
|
||||
labels,
|
||||
lastEdited
|
||||
)
|
||||
db.execSQL("""
|
||||
INSERT INTO NotesModel_new
|
||||
SELECT
|
||||
notesId,
|
||||
workspaceId,
|
||||
@@ -292,25 +265,20 @@ val MIGRATION_7_8 = object : Migration(7, 8) {
|
||||
labels,
|
||||
lastEdited
|
||||
FROM NotesModel
|
||||
""".trimIndent()
|
||||
""")
|
||||
|
||||
db.execSQL("DROP TABLE NotesModel")
|
||||
db.execSQL(
|
||||
"ALTER TABLE NotesModel_new RENAME TO NotesModel"
|
||||
)
|
||||
|
||||
// 3. Drop old table
|
||||
db.execSQL("DROP TABLE NotesModel")
|
||||
|
||||
// 4. Rename new table
|
||||
db.execSQL("ALTER TABLE NotesModel_new RENAME TO NotesModel")
|
||||
}
|
||||
}
|
||||
|
||||
val Migration_8_9 = object : Migration(8, 9) {
|
||||
|
||||
override fun migrate(db: SupportSQLiteDatabase) {
|
||||
/* ============================================================
|
||||
5. HTML → Markdown migration (8→9)
|
||||
============================================================ */
|
||||
|
||||
val converter = FlexmarkHtmlConverter.builder().build()
|
||||
|
||||
/* ---------------- Notes Migration ---------------- */
|
||||
|
||||
db.query(
|
||||
"SELECT notesId, description FROM NotesModel"
|
||||
).use { cursor ->
|
||||
@@ -325,19 +293,13 @@ val Migration_8_9 = object : Migration(8, 9) {
|
||||
val markdown = converter.convert(html)
|
||||
|
||||
db.execSQL(
|
||||
"""
|
||||
UPDATE NotesModel
|
||||
SET description = ?
|
||||
WHERE notesId = ?
|
||||
""".trimIndent(),
|
||||
"UPDATE NotesModel SET description = ? WHERE notesId = ?",
|
||||
arrayOf(markdown, id)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------------- Journals Migration ---------------- */
|
||||
|
||||
db.query(
|
||||
"SELECT journalId, text FROM JournalModel"
|
||||
).use { cursor ->
|
||||
@@ -352,11 +314,7 @@ val Migration_8_9 = object : Migration(8, 9) {
|
||||
val markdown = converter.convert(html)
|
||||
|
||||
db.execSQL(
|
||||
"""
|
||||
UPDATE JournalModel
|
||||
SET text = ?
|
||||
WHERE journalId = ?
|
||||
""".trimIndent(),
|
||||
"UPDATE JournalModel SET text = ? WHERE journalId = ?",
|
||||
arrayOf(markdown, id)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -16,11 +16,6 @@ import com.flux.data.database.FluxDatabase
|
||||
import com.flux.data.database.MIGRATION_1_2
|
||||
import com.flux.data.database.MIGRATION_2_3
|
||||
import com.flux.data.database.MIGRATION_3_4
|
||||
import com.flux.data.database.MIGRATION_4_5
|
||||
import com.flux.data.database.MIGRATION_5_6
|
||||
import com.flux.data.database.MIGRATION_6_7
|
||||
import com.flux.data.database.MIGRATION_7_8
|
||||
import com.flux.data.database.Migration_8_9
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
@@ -40,7 +35,7 @@ object DataModule {
|
||||
FluxDatabase::class.java,
|
||||
"FluxDatabase"
|
||||
)
|
||||
.addMigrations(MIGRATION_1_2, MIGRATION_2_3, MIGRATION_3_4, MIGRATION_4_5, MIGRATION_5_6, MIGRATION_6_7, MIGRATION_7_8, Migration_8_9)
|
||||
.addMigrations(MIGRATION_1_2, MIGRATION_2_3, MIGRATION_3_4)
|
||||
.build()
|
||||
|
||||
@Singleton
|
||||
|
||||
Reference in New Issue
Block a user