diff --git a/app/schemas/ai.elimu.content_provider.room.db.RoomDb/30.json b/app/schemas/ai.elimu.content_provider.room.db.RoomDb/30.json new file mode 100644 index 00000000..430b2e78 --- /dev/null +++ b/app/schemas/ai.elimu.content_provider.room.db.RoomDb/30.json @@ -0,0 +1,590 @@ +{ + "formatVersion": 1, + "database": { + "version": 30, + "identityHash": "0ce90877430c0d369ba13cc370af5cf3", + "entities": [ + { + "tableName": "Letter", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`text` TEXT, `diacritic` INTEGER, `revisionNumber` INTEGER NOT NULL, `usageCount` INTEGER, `id` INTEGER, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "text", + "columnName": "text", + "affinity": "TEXT" + }, + { + "fieldPath": "diacritic", + "columnName": "diacritic", + "affinity": "INTEGER" + }, + { + "fieldPath": "revisionNumber", + "columnName": "revisionNumber", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "usageCount", + "columnName": "usageCount", + "affinity": "INTEGER" + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + } + }, + { + "tableName": "Sound", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`valueIpa` TEXT, `diacritic` INTEGER, `revisionNumber` INTEGER NOT NULL, `usageCount` INTEGER, `id` INTEGER, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "valueIpa", + "columnName": "valueIpa", + "affinity": "TEXT" + }, + { + "fieldPath": "diacritic", + "columnName": "diacritic", + "affinity": "INTEGER" + }, + { + "fieldPath": "revisionNumber", + "columnName": "revisionNumber", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "usageCount", + "columnName": "usageCount", + "affinity": "INTEGER" + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + } + }, + { + "tableName": "LetterSound", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`revisionNumber` INTEGER NOT NULL, `usageCount` INTEGER, `id` INTEGER, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "revisionNumber", + "columnName": "revisionNumber", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "usageCount", + "columnName": "usageCount", + "affinity": "INTEGER" + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + } + }, + { + "tableName": "LetterSound_Letter", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`LetterSound_id` INTEGER NOT NULL, `letters_id` INTEGER NOT NULL, `letters_ORDER` INTEGER NOT NULL, PRIMARY KEY(`LetterSound_id`, `letters_ORDER`))", + "fields": [ + { + "fieldPath": "LetterSound_id", + "columnName": "LetterSound_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "letters_id", + "columnName": "letters_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "letters_ORDER", + "columnName": "letters_ORDER", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "LetterSound_id", + "letters_ORDER" + ] + } + }, + { + "tableName": "LetterSound_Sound", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`LetterSound_id` INTEGER NOT NULL, `sounds_id` INTEGER NOT NULL, `sounds_ORDER` INTEGER NOT NULL, PRIMARY KEY(`LetterSound_id`, `sounds_ORDER`))", + "fields": [ + { + "fieldPath": "LetterSound_id", + "columnName": "LetterSound_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "sounds_id", + "columnName": "sounds_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "sounds_ORDER", + "columnName": "sounds_ORDER", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "LetterSound_id", + "sounds_ORDER" + ] + } + }, + { + "tableName": "Word", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`text` TEXT NOT NULL, `wordType` TEXT, `revisionNumber` INTEGER NOT NULL, `usageCount` INTEGER, `id` INTEGER, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "text", + "columnName": "text", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "wordType", + "columnName": "wordType", + "affinity": "TEXT" + }, + { + "fieldPath": "revisionNumber", + "columnName": "revisionNumber", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "usageCount", + "columnName": "usageCount", + "affinity": "INTEGER" + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + } + }, + { + "tableName": "Number", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`value` INTEGER NOT NULL, `symbol` TEXT, `revisionNumber` INTEGER NOT NULL, `usageCount` INTEGER, `id` INTEGER, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "value", + "columnName": "value", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "symbol", + "columnName": "symbol", + "affinity": "TEXT" + }, + { + "fieldPath": "revisionNumber", + "columnName": "revisionNumber", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "usageCount", + "columnName": "usageCount", + "affinity": "INTEGER" + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + } + }, + { + "tableName": "Emoji", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`glyph` TEXT NOT NULL, `unicodeVersion` REAL NOT NULL, `unicodeEmojiVersion` REAL NOT NULL, `revisionNumber` INTEGER NOT NULL, `usageCount` INTEGER, `id` INTEGER, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "glyph", + "columnName": "glyph", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "unicodeVersion", + "columnName": "unicodeVersion", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "unicodeEmojiVersion", + "columnName": "unicodeEmojiVersion", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "revisionNumber", + "columnName": "revisionNumber", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "usageCount", + "columnName": "usageCount", + "affinity": "INTEGER" + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + } + }, + { + "tableName": "Emoji_Word", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`Emoji_id` INTEGER NOT NULL, `words_id` INTEGER NOT NULL, PRIMARY KEY(`Emoji_id`, `words_id`))", + "fields": [ + { + "fieldPath": "Emoji_id", + "columnName": "Emoji_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "words_id", + "columnName": "words_id", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "Emoji_id", + "words_id" + ] + } + }, + { + "tableName": "Image", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`title` TEXT NOT NULL, `imageFormat` TEXT NOT NULL, `checksumMd5` TEXT NOT NULL, `revisionNumber` INTEGER NOT NULL, `usageCount` INTEGER, `id` INTEGER, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "imageFormat", + "columnName": "imageFormat", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "checksumMd5", + "columnName": "checksumMd5", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "revisionNumber", + "columnName": "revisionNumber", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "usageCount", + "columnName": "usageCount", + "affinity": "INTEGER" + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + } + }, + { + "tableName": "Image_Word", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`Image_id` INTEGER NOT NULL, `words_id` INTEGER NOT NULL, PRIMARY KEY(`Image_id`, `words_id`))", + "fields": [ + { + "fieldPath": "Image_id", + "columnName": "Image_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "words_id", + "columnName": "words_id", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "Image_id", + "words_id" + ] + } + }, + { + "tableName": "StoryBook", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`title` TEXT NOT NULL, `description` TEXT, `coverImageId` INTEGER NOT NULL, `readingLevel` TEXT, `revisionNumber` INTEGER NOT NULL, `usageCount` INTEGER, `id` INTEGER, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT" + }, + { + "fieldPath": "coverImageId", + "columnName": "coverImageId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "readingLevel", + "columnName": "readingLevel", + "affinity": "TEXT" + }, + { + "fieldPath": "revisionNumber", + "columnName": "revisionNumber", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "usageCount", + "columnName": "usageCount", + "affinity": "INTEGER" + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + } + }, + { + "tableName": "StoryBookChapter", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`storyBookId` INTEGER NOT NULL, `sortOrder` INTEGER NOT NULL, `imageId` INTEGER NOT NULL, `id` INTEGER, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "storyBookId", + "columnName": "storyBookId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "sortOrder", + "columnName": "sortOrder", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "imageId", + "columnName": "imageId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + } + }, + { + "tableName": "StoryBookParagraph", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`storyBookChapterId` INTEGER NOT NULL, `sortOrder` INTEGER NOT NULL, `originalText` TEXT NOT NULL, `id` INTEGER, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "storyBookChapterId", + "columnName": "storyBookChapterId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "sortOrder", + "columnName": "sortOrder", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "originalText", + "columnName": "originalText", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + } + }, + { + "tableName": "StoryBookParagraph_Word", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`StoryBookParagraph_id` INTEGER NOT NULL, `words_id` INTEGER NOT NULL, `words_ORDER` INTEGER NOT NULL, PRIMARY KEY(`StoryBookParagraph_id`, `words_ORDER`))", + "fields": [ + { + "fieldPath": "StoryBookParagraph_id", + "columnName": "StoryBookParagraph_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "words_id", + "columnName": "words_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "words_ORDER", + "columnName": "words_ORDER", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "StoryBookParagraph_id", + "words_ORDER" + ] + } + }, + { + "tableName": "Video", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`title` TEXT NOT NULL, `videoFormat` TEXT NOT NULL, `revisionNumber` INTEGER NOT NULL, `usageCount` INTEGER, `id` INTEGER, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "videoFormat", + "columnName": "videoFormat", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "revisionNumber", + "columnName": "revisionNumber", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "usageCount", + "columnName": "usageCount", + "affinity": "INTEGER" + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + } + } + ], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '0ce90877430c0d369ba13cc370af5cf3')" + ] + } +} \ No newline at end of file diff --git a/app/src/main/java/ai/elimu/content_provider/room/GsonToRoomConverter.kt b/app/src/main/java/ai/elimu/content_provider/room/GsonToRoomConverter.kt index 363c6edd..7d31498a 100644 --- a/app/src/main/java/ai/elimu/content_provider/room/GsonToRoomConverter.kt +++ b/app/src/main/java/ai/elimu/content_provider/room/GsonToRoomConverter.kt @@ -160,6 +160,7 @@ object GsonToRoomConverter { // Image image.title = imageGson.title image.imageFormat = imageGson.imageFormat + image.checksumMd5 = imageGson.checksumMd5 // Note: words are stored separately in Image_Word (see ImagesFragment.java) return image diff --git a/app/src/main/java/ai/elimu/content_provider/room/db/RoomDb.java b/app/src/main/java/ai/elimu/content_provider/room/db/RoomDb.java index 933d32da..98b954c2 100644 --- a/app/src/main/java/ai/elimu/content_provider/room/db/RoomDb.java +++ b/app/src/main/java/ai/elimu/content_provider/room/db/RoomDb.java @@ -43,7 +43,7 @@ import ai.elimu.content_provider.room.entity.Video; import ai.elimu.content_provider.room.entity.Word; -@Database(version = 29, entities = {Letter.class, Sound.class, LetterSound.class, LetterSound_Letter.class, LetterSound_Sound.class, Word.class, Number.class, Emoji.class, Emoji_Word.class, Image.class, Image_Word.class, StoryBook.class, StoryBookChapter.class, StoryBookParagraph.class, StoryBookParagraph_Word.class, Video.class}) +@Database(version = 30, entities = {Letter.class, Sound.class, LetterSound.class, LetterSound_Letter.class, LetterSound_Sound.class, Word.class, Number.class, Emoji.class, Emoji_Word.class, Image.class, Image_Word.class, StoryBook.class, StoryBookChapter.class, StoryBookParagraph.class, StoryBookParagraph_Word.class, Video.class}) @TypeConverters({Converters.class}) public abstract class RoomDb extends RoomDatabase { @@ -114,7 +114,8 @@ public static RoomDb getDatabase(final Context context) { MIGRATION_25_26, MIGRATION_26_27, MIGRATION_27_28, - MIGRATION_28_29 + MIGRATION_28_29, + MIGRATION_29_30 ) .build(); } @@ -397,4 +398,15 @@ public void migrate(SupportSQLiteDatabase database) { database.execSQL(sql); } }; + + private static final Migration MIGRATION_29_30 = new Migration(29, 30) { + @Override + public void migrate(SupportSQLiteDatabase database) { + Log.i(getClass().getName(), "migrate (29 --> 30)"); + + String sql = "ALTER TABLE Image ADD COLUMN `checksumMd5` TEXT NOT NULL DEFAULT ''"; + Log.i("migrate sql: %s", sql); + database.execSQL(sql); + } + }; } diff --git a/app/src/main/java/ai/elimu/content_provider/room/entity/Image.kt b/app/src/main/java/ai/elimu/content_provider/room/entity/Image.kt index 55323149..3d6cce22 100644 --- a/app/src/main/java/ai/elimu/content_provider/room/entity/Image.kt +++ b/app/src/main/java/ai/elimu/content_provider/room/entity/Image.kt @@ -11,4 +11,5 @@ class Image : Content() { lateinit var title: String lateinit var imageFormat: ImageFormat + lateinit var checksumMd5: String } diff --git a/app/src/main/java/ai/elimu/content_provider/util/FileHelper.kt b/app/src/main/java/ai/elimu/content_provider/util/FileHelper.kt index 3ab232ca..738f43a5 100644 --- a/app/src/main/java/ai/elimu/content_provider/util/FileHelper.kt +++ b/app/src/main/java/ai/elimu/content_provider/util/FileHelper.kt @@ -36,8 +36,7 @@ object FileHelper { } val imagesDirectory = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES) return File( - imagesDirectory, (imageGson.id - .toString() + "_r" + imageGson.revisionNumber + "." + imagesDirectory, (imageGson.checksumMd5 + "." + imageGson.imageFormat.toString().lowercase(Locale.getDefault())) ) }