From 202f58b17ed64cd8cd3bb2010f9e2144a361552b Mon Sep 17 00:00:00 2001 From: jo-elimu <1451036+jo-elimu@users.noreply.github.com> Date: Mon, 27 Nov 2023 09:59:00 +0700 Subject: [PATCH 1/4] docs: "master" --> "main" --- README.md | 4 ++-- .../java/ai/elimu/content_provider/room/entity/Audio.java | 2 +- .../ai/elimu/content_provider/room/entity/BaseEntity.java | 2 +- .../java/ai/elimu/content_provider/room/entity/Content.java | 2 +- .../java/ai/elimu/content_provider/room/entity/Emoji.java | 2 +- .../ai/elimu/content_provider/room/entity/Emoji_Word.java | 2 +- .../java/ai/elimu/content_provider/room/entity/Image.java | 2 +- .../ai/elimu/content_provider/room/entity/Image_Word.java | 2 +- .../java/ai/elimu/content_provider/room/entity/Letter.java | 2 +- .../java/ai/elimu/content_provider/room/entity/Number.java | 2 +- .../java/ai/elimu/content_provider/room/entity/Sound.java | 2 +- .../java/ai/elimu/content_provider/room/entity/StoryBook.java | 2 +- .../elimu/content_provider/room/entity/StoryBookChapter.java | 2 +- .../content_provider/room/entity/StoryBookParagraph.java | 2 +- .../content_provider/room/entity/StoryBookParagraph_Word.java | 2 +- .../java/ai/elimu/content_provider/room/entity/Video.java | 2 +- .../main/java/ai/elimu/content_provider/room/entity/Word.java | 2 +- 17 files changed, 18 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 158bf31..6b8a974 100644 --- a/README.md +++ b/README.md @@ -5,13 +5,13 @@ device and provides it to other elimu.ai apps. ![](https://user-images.githubusercontent.com/15718174/76617075-6c82d200-6560-11ea-867d-e46385017e03.png) -See software architecture diagram at https://github.com/elimu-ai/model/blob/master/README.md +See software architecture diagram at https://github.com/elimu-ai/model/blob/main/README.md ## Software Architecture [ Software Architecture -](https://github.com/elimu-ai/wiki/blob/master/SOFTWARE_ARCHITECTURE.md) +](https://github.com/elimu-ai/wiki/blob/main/SOFTWARE_ARCHITECTURE.md) ## Utils Library 📦 diff --git a/app/src/main/java/ai/elimu/content_provider/room/entity/Audio.java b/app/src/main/java/ai/elimu/content_provider/room/entity/Audio.java index 9a85769..b914172 100644 --- a/app/src/main/java/ai/elimu/content_provider/room/entity/Audio.java +++ b/app/src/main/java/ai/elimu/content_provider/room/entity/Audio.java @@ -6,7 +6,7 @@ import ai.elimu.model.v2.enums.content.AudioFormat; /** - * For documentation, see https://github.com/elimu-ai/webapp/tree/master/src/main/java/ai/elimu/model + * For documentation, see https://github.com/elimu-ai/webapp/tree/main/src/main/java/ai/elimu/model */ @Entity public class Audio extends Content { diff --git a/app/src/main/java/ai/elimu/content_provider/room/entity/BaseEntity.java b/app/src/main/java/ai/elimu/content_provider/room/entity/BaseEntity.java index 1e3f364..7d4e97e 100644 --- a/app/src/main/java/ai/elimu/content_provider/room/entity/BaseEntity.java +++ b/app/src/main/java/ai/elimu/content_provider/room/entity/BaseEntity.java @@ -3,7 +3,7 @@ import androidx.room.PrimaryKey; /** - * For documentation, see https://github.com/elimu-ai/webapp/tree/master/src/main/java/ai/elimu/model + * For documentation, see https://github.com/elimu-ai/webapp/tree/main/src/main/java/ai/elimu/model */ public class BaseEntity { diff --git a/app/src/main/java/ai/elimu/content_provider/room/entity/Content.java b/app/src/main/java/ai/elimu/content_provider/room/entity/Content.java index cbe4993..c282a1d 100644 --- a/app/src/main/java/ai/elimu/content_provider/room/entity/Content.java +++ b/app/src/main/java/ai/elimu/content_provider/room/entity/Content.java @@ -3,7 +3,7 @@ import androidx.annotation.NonNull; /** - * For documentation, see https://github.com/elimu-ai/webapp/tree/master/src/main/java/ai/elimu/model + * For documentation, see https://github.com/elimu-ai/webapp/tree/main/src/main/java/ai/elimu/model */ public class Content extends BaseEntity { diff --git a/app/src/main/java/ai/elimu/content_provider/room/entity/Emoji.java b/app/src/main/java/ai/elimu/content_provider/room/entity/Emoji.java index 94facd2..df44c79 100644 --- a/app/src/main/java/ai/elimu/content_provider/room/entity/Emoji.java +++ b/app/src/main/java/ai/elimu/content_provider/room/entity/Emoji.java @@ -4,7 +4,7 @@ import androidx.room.Entity; /** - * For documentation, see https://github.com/elimu-ai/webapp/tree/master/src/main/java/ai/elimu/model + * For documentation, see https://github.com/elimu-ai/webapp/tree/main/src/main/java/ai/elimu/model */ @Entity public class Emoji extends Content { diff --git a/app/src/main/java/ai/elimu/content_provider/room/entity/Emoji_Word.java b/app/src/main/java/ai/elimu/content_provider/room/entity/Emoji_Word.java index ce9cbb7..9238618 100644 --- a/app/src/main/java/ai/elimu/content_provider/room/entity/Emoji_Word.java +++ b/app/src/main/java/ai/elimu/content_provider/room/entity/Emoji_Word.java @@ -4,7 +4,7 @@ import androidx.room.Entity; /** - * For documentation, see https://github.com/elimu-ai/webapp/tree/master/src/main/java/ai/elimu/model + * For documentation, see https://github.com/elimu-ai/webapp/tree/main/src/main/java/ai/elimu/model */ @Entity(primaryKeys = {"Emoji_id", "words_id"}) public class Emoji_Word { diff --git a/app/src/main/java/ai/elimu/content_provider/room/entity/Image.java b/app/src/main/java/ai/elimu/content_provider/room/entity/Image.java index 17a84b5..38a3f42 100644 --- a/app/src/main/java/ai/elimu/content_provider/room/entity/Image.java +++ b/app/src/main/java/ai/elimu/content_provider/room/entity/Image.java @@ -6,7 +6,7 @@ import ai.elimu.model.v2.enums.content.ImageFormat; /** - * For documentation, see https://github.com/elimu-ai/webapp/tree/master/src/main/java/ai/elimu/model + * For documentation, see https://github.com/elimu-ai/webapp/tree/main/src/main/java/ai/elimu/model */ @Entity public class Image extends Content { diff --git a/app/src/main/java/ai/elimu/content_provider/room/entity/Image_Word.java b/app/src/main/java/ai/elimu/content_provider/room/entity/Image_Word.java index 0025caf..40728e3 100644 --- a/app/src/main/java/ai/elimu/content_provider/room/entity/Image_Word.java +++ b/app/src/main/java/ai/elimu/content_provider/room/entity/Image_Word.java @@ -4,7 +4,7 @@ import androidx.room.Entity; /** - * For documentation, see https://github.com/elimu-ai/webapp/tree/master/src/main/java/ai/elimu/model + * For documentation, see https://github.com/elimu-ai/webapp/tree/main/src/main/java/ai/elimu/model */ @Entity(primaryKeys = {"Image_id", "words_id"}) public class Image_Word { diff --git a/app/src/main/java/ai/elimu/content_provider/room/entity/Letter.java b/app/src/main/java/ai/elimu/content_provider/room/entity/Letter.java index 7cb168b..3c507d1 100644 --- a/app/src/main/java/ai/elimu/content_provider/room/entity/Letter.java +++ b/app/src/main/java/ai/elimu/content_provider/room/entity/Letter.java @@ -3,7 +3,7 @@ import androidx.room.Entity; /** - * For documentation, see https://github.com/elimu-ai/webapp/tree/master/src/main/java/ai/elimu/model + * For documentation, see https://github.com/elimu-ai/webapp/tree/main/src/main/java/ai/elimu/model */ @Entity public class Letter extends Content { diff --git a/app/src/main/java/ai/elimu/content_provider/room/entity/Number.java b/app/src/main/java/ai/elimu/content_provider/room/entity/Number.java index cbeec33..f47f6eb 100644 --- a/app/src/main/java/ai/elimu/content_provider/room/entity/Number.java +++ b/app/src/main/java/ai/elimu/content_provider/room/entity/Number.java @@ -4,7 +4,7 @@ import androidx.room.Entity; /** - * For documentation, see https://github.com/elimu-ai/webapp/tree/master/src/main/java/ai/elimu/model + * For documentation, see https://github.com/elimu-ai/webapp/tree/main/src/main/java/ai/elimu/model */ @Entity public class Number extends Content { diff --git a/app/src/main/java/ai/elimu/content_provider/room/entity/Sound.java b/app/src/main/java/ai/elimu/content_provider/room/entity/Sound.java index bd5bcd0..1b76836 100644 --- a/app/src/main/java/ai/elimu/content_provider/room/entity/Sound.java +++ b/app/src/main/java/ai/elimu/content_provider/room/entity/Sound.java @@ -3,7 +3,7 @@ import androidx.room.Entity; /** - * For documentation, see https://github.com/elimu-ai/webapp/tree/master/src/main/java/ai/elimu/model + * For documentation, see https://github.com/elimu-ai/webapp/tree/main/src/main/java/ai/elimu/model */ @Entity public class Sound extends Content { diff --git a/app/src/main/java/ai/elimu/content_provider/room/entity/StoryBook.java b/app/src/main/java/ai/elimu/content_provider/room/entity/StoryBook.java index 4ef1ba3..8ad9369 100644 --- a/app/src/main/java/ai/elimu/content_provider/room/entity/StoryBook.java +++ b/app/src/main/java/ai/elimu/content_provider/room/entity/StoryBook.java @@ -6,7 +6,7 @@ import ai.elimu.model.v2.enums.ReadingLevel; /** - * For documentation, see https://github.com/elimu-ai/webapp/tree/master/src/main/java/ai/elimu/model + * For documentation, see https://github.com/elimu-ai/webapp/tree/main/src/main/java/ai/elimu/model */ @Entity public class StoryBook extends Content { diff --git a/app/src/main/java/ai/elimu/content_provider/room/entity/StoryBookChapter.java b/app/src/main/java/ai/elimu/content_provider/room/entity/StoryBookChapter.java index aa5e460..f5147ad 100644 --- a/app/src/main/java/ai/elimu/content_provider/room/entity/StoryBookChapter.java +++ b/app/src/main/java/ai/elimu/content_provider/room/entity/StoryBookChapter.java @@ -4,7 +4,7 @@ import androidx.room.Entity; /** - * For documentation, see https://github.com/elimu-ai/webapp/tree/master/src/main/java/ai/elimu/model + * For documentation, see https://github.com/elimu-ai/webapp/tree/main/src/main/java/ai/elimu/model */ @Entity public class StoryBookChapter extends BaseEntity { diff --git a/app/src/main/java/ai/elimu/content_provider/room/entity/StoryBookParagraph.java b/app/src/main/java/ai/elimu/content_provider/room/entity/StoryBookParagraph.java index c6e4465..ef3a617 100644 --- a/app/src/main/java/ai/elimu/content_provider/room/entity/StoryBookParagraph.java +++ b/app/src/main/java/ai/elimu/content_provider/room/entity/StoryBookParagraph.java @@ -4,7 +4,7 @@ import androidx.room.Entity; /** - * For documentation, see https://github.com/elimu-ai/webapp/tree/master/src/main/java/ai/elimu/model + * For documentation, see https://github.com/elimu-ai/webapp/tree/main/src/main/java/ai/elimu/model */ @Entity public class StoryBookParagraph extends BaseEntity { diff --git a/app/src/main/java/ai/elimu/content_provider/room/entity/StoryBookParagraph_Word.java b/app/src/main/java/ai/elimu/content_provider/room/entity/StoryBookParagraph_Word.java index e49c2d5..7cfeb6e 100644 --- a/app/src/main/java/ai/elimu/content_provider/room/entity/StoryBookParagraph_Word.java +++ b/app/src/main/java/ai/elimu/content_provider/room/entity/StoryBookParagraph_Word.java @@ -4,7 +4,7 @@ import androidx.room.Entity; /** - * For documentation, see https://github.com/elimu-ai/webapp/tree/master/src/main/java/ai/elimu/model + * For documentation, see https://github.com/elimu-ai/webapp/tree/main/src/main/java/ai/elimu/model */ @Entity(primaryKeys = {"StoryBookParagraph_id", "words_ORDER"}) public class StoryBookParagraph_Word { diff --git a/app/src/main/java/ai/elimu/content_provider/room/entity/Video.java b/app/src/main/java/ai/elimu/content_provider/room/entity/Video.java index e2b12ef..3e6ac71 100644 --- a/app/src/main/java/ai/elimu/content_provider/room/entity/Video.java +++ b/app/src/main/java/ai/elimu/content_provider/room/entity/Video.java @@ -6,7 +6,7 @@ import ai.elimu.model.v2.enums.content.VideoFormat; /** - * For documentation, see https://github.com/elimu-ai/webapp/tree/master/src/main/java/ai/elimu/model + * For documentation, see https://github.com/elimu-ai/webapp/tree/main/src/main/java/ai/elimu/model */ @Entity public class Video extends Content { diff --git a/app/src/main/java/ai/elimu/content_provider/room/entity/Word.java b/app/src/main/java/ai/elimu/content_provider/room/entity/Word.java index 6978c89..8d2a697 100644 --- a/app/src/main/java/ai/elimu/content_provider/room/entity/Word.java +++ b/app/src/main/java/ai/elimu/content_provider/room/entity/Word.java @@ -6,7 +6,7 @@ import ai.elimu.model.v2.enums.content.WordType; /** - * For documentation, see https://github.com/elimu-ai/webapp/tree/master/src/main/java/ai/elimu/model + * For documentation, see https://github.com/elimu-ai/webapp/tree/main/src/main/java/ai/elimu/model */ @Entity public class Word extends Content { From 6378398c919b6dbd6b571dd943c5c68323cc6f0a Mon Sep 17 00:00:00 2001 From: jo-elimu <1451036+jo-elimu@users.noreply.github.com> Date: Mon, 27 Nov 2023 10:56:25 +0700 Subject: [PATCH 2/4] feat: Download letter-sounds from REST API close #59 --- .../provider/LetterContentProvider.java | 1 + .../content_provider/rest/LetterSoundsService.java | 13 +++++++++++++ .../content_provider/room/entity/LetterSound.java | 12 ++++++++++++ 3 files changed, 26 insertions(+) create mode 100644 app/src/main/java/ai/elimu/content_provider/rest/LetterSoundsService.java create mode 100644 app/src/main/java/ai/elimu/content_provider/room/entity/LetterSound.java diff --git a/app/src/main/java/ai/elimu/content_provider/provider/LetterContentProvider.java b/app/src/main/java/ai/elimu/content_provider/provider/LetterContentProvider.java index d2c8130..4f1ccf2 100644 --- a/app/src/main/java/ai/elimu/content_provider/provider/LetterContentProvider.java +++ b/app/src/main/java/ai/elimu/content_provider/provider/LetterContentProvider.java @@ -14,6 +14,7 @@ import ai.elimu.content_provider.room.dao.LetterDao; import ai.elimu.content_provider.room.db.RoomDb; +@Deprecated public class LetterContentProvider extends ContentProvider { private static final String AUTHORITY = BuildConfig.APPLICATION_ID + ".provider.letter_provider"; diff --git a/app/src/main/java/ai/elimu/content_provider/rest/LetterSoundsService.java b/app/src/main/java/ai/elimu/content_provider/rest/LetterSoundsService.java new file mode 100644 index 0000000..0dfd3f7 --- /dev/null +++ b/app/src/main/java/ai/elimu/content_provider/rest/LetterSoundsService.java @@ -0,0 +1,13 @@ +package ai.elimu.content_provider.rest; + +import java.util.List; + +import ai.elimu.model.v2.gson.content.LetterSoundGson; +import retrofit2.Call; +import retrofit2.http.GET; + +public interface LetterSoundsService { + + @GET("content/letter-sounds") + Call> listLetterSounds(); +} diff --git a/app/src/main/java/ai/elimu/content_provider/room/entity/LetterSound.java b/app/src/main/java/ai/elimu/content_provider/room/entity/LetterSound.java new file mode 100644 index 0000000..9d292a2 --- /dev/null +++ b/app/src/main/java/ai/elimu/content_provider/room/entity/LetterSound.java @@ -0,0 +1,12 @@ +package ai.elimu.content_provider.room.entity; + +import androidx.room.Entity; + +/** + * For documentation, see https://github.com/elimu-ai/webapp/tree/main/src/main/java/ai/elimu/model + */ +@Entity +public class LetterSound extends Content { + + +} From 9dd35407c7eb20bb2b9fa1d6dec7fe1be4df2feb Mon Sep 17 00:00:00 2001 From: jo-elimu <1451036+jo-elimu@users.noreply.github.com> Date: Mon, 27 Nov 2023 11:52:18 +0700 Subject: [PATCH 3/4] feat: Add LetterSound database entity #59 --- README.md | 32 + .../24.json | 629 ++++++++++++++++++ .../room/dao/LetterSoundDao.java | 13 + .../content_provider/room/db/RoomDb.java | 20 +- 4 files changed, 692 insertions(+), 2 deletions(-) create mode 100644 app/schemas/ai.elimu.content_provider.room.db.RoomDb/24.json create mode 100644 app/src/main/java/ai/elimu/content_provider/room/dao/LetterSoundDao.java diff --git a/README.md b/README.md index 6b8a974..ccf5937 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,38 @@ After that, connect your Android device to the same Wi-Fi network as your comput ./gradlew wrapper --gradle-version x.x.x --distribution-type all ``` +### Database Migration 🔀 + +When adding a new database `@Entity` (or modifying an existing one), you need to prepare a database +migration (SQL script) in +[`app/src/main/java/ai/elimu/content_provider/room/db/RoomDb.java`](app/src/main/java/ai/elimu/content_provider/room/db/RoomDb.java). + +Follow these steps: + +1. Add the new/modified `@Entity` to [`app/src/main/java/ai/elimu/content_provider/room/entity/`](app/src/main/java/ai/elimu/content_provider/room/entity/) +1. Add the entity's DAO interface to [`app/src/main/java/ai/elimu/content_provider/room/dao/`](app/src/main/java/ai/elimu/content_provider/room/dao/) +1. Include the DAO interface in [`app/src/main/java/ai/elimu/content_provider/room/db/RoomDb.java`](app/src/main/java/ai/elimu/content_provider/room/db/RoomDb.java) +1. Include the entity in the `entities` section of the `@Database` in [`app/src/main/java/ai/elimu/content_provider/room/db/RoomDb.java`](app/src/main/java/ai/elimu/content_provider/room/db/RoomDb.java) +1. Bump the `@Database` version in [`app/src/main/java/ai/elimu/content_provider/room/db/RoomDb.java`](app/src/main/java/ai/elimu/content_provider/room/db/RoomDb.java) +1. Build the code with `./gradlew clean build` +1. Open the new database schema generated at `app/schemas/ai.elimu.content_provider.room.db.RoomDb/.json` +- Under `entities`, find the matching `tableName` and copy its SQL script from the `createSql` property. +1. Open `RoomDb.java` and add a new method for the latest migration +- Paste the SQL script from the above JSON schema, and replace `${TABLE_NAME}` with the name of the table you created/modified. +- Include the migration in the `getDatabase` method in `RoomDb.java`. +1. To run the database migration, launch the application on your device. + +**Tip #1:** To verify that your database migration ran successfully, look at the Logcat output and +ensure that there are no RoomDb errors: +``` +2023-11-27 11:46:50.662 6124-13233 ai.elimu.c....RoomDb$18 ai.elimu.content_provider.debug I migrate (23 --> 24) +2023-11-27 11:46:50.663 6124-13233 ai.elimu.c....RoomDb$18 ai.elimu.content_provider.debug I sql: CREATE TABLE IF NOT EXISTS `LetterSound` (`revisionNumber` INTEGER NOT NULL, `usageCount` INTEGER, `id` INTEGER, PRIMARY KEY(`id`)) +``` + +**Tip #2:** You can also use Android Studio's _Database Inspector_ to verify that the database +migration succeeded: + +![](https://github.com/elimu-ai/content-provider/assets/1451036/4c462813-bac0-4d4c-9f62-8c4aa12252d9) ## Release 📦 diff --git a/app/schemas/ai.elimu.content_provider.room.db.RoomDb/24.json b/app/schemas/ai.elimu.content_provider.room.db.RoomDb/24.json new file mode 100644 index 0000000..42b5964 --- /dev/null +++ b/app/schemas/ai.elimu.content_provider.room.db.RoomDb/24.json @@ -0,0 +1,629 @@ +{ + "formatVersion": 1, + "database": { + "version": 24, + "identityHash": "272858d2cd99837310e007914ec3306b", + "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", + "notNull": false + }, + { + "fieldPath": "diacritic", + "columnName": "diacritic", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "revisionNumber", + "columnName": "revisionNumber", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "usageCount", + "columnName": "usageCount", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "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", + "notNull": false + }, + { + "fieldPath": "diacritic", + "columnName": "diacritic", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "revisionNumber", + "columnName": "revisionNumber", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "usageCount", + "columnName": "usageCount", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "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", + "notNull": false + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "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", + "notNull": false + }, + { + "fieldPath": "revisionNumber", + "columnName": "revisionNumber", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "usageCount", + "columnName": "usageCount", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "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", + "notNull": false + }, + { + "fieldPath": "revisionNumber", + "columnName": "revisionNumber", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "usageCount", + "columnName": "usageCount", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "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", + "notNull": false + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "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": { + "columnNames": [ + "Emoji_id", + "words_id" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Image", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`title` TEXT NOT NULL, `imageFormat` 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": "revisionNumber", + "columnName": "revisionNumber", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "usageCount", + "columnName": "usageCount", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "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": { + "columnNames": [ + "Image_id", + "words_id" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Audio", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`title` TEXT NOT NULL, `transcription` TEXT NOT NULL, `audioFormat` TEXT NOT NULL, `revisionNumber` INTEGER NOT NULL, `usageCount` INTEGER, `id` INTEGER, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "transcription", + "columnName": "transcription", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "audioFormat", + "columnName": "audioFormat", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "revisionNumber", + "columnName": "revisionNumber", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "usageCount", + "columnName": "usageCount", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "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", + "notNull": false + }, + { + "fieldPath": "coverImageId", + "columnName": "coverImageId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "readingLevel", + "columnName": "readingLevel", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "revisionNumber", + "columnName": "revisionNumber", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "usageCount", + "columnName": "usageCount", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "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", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "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", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "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": { + "columnNames": [ + "StoryBookParagraph_id", + "words_ORDER" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "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", + "notNull": false + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + } + ], + "views": [], + "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, '272858d2cd99837310e007914ec3306b')" + ] + } +} \ No newline at end of file diff --git a/app/src/main/java/ai/elimu/content_provider/room/dao/LetterSoundDao.java b/app/src/main/java/ai/elimu/content_provider/room/dao/LetterSoundDao.java new file mode 100644 index 0000000..aa4ef33 --- /dev/null +++ b/app/src/main/java/ai/elimu/content_provider/room/dao/LetterSoundDao.java @@ -0,0 +1,13 @@ +package ai.elimu.content_provider.room.dao; + +import androidx.room.Dao; +import androidx.room.Insert; + +import ai.elimu.content_provider.room.entity.LetterSound; + +@Dao +public interface LetterSoundDao { + + @Insert + void insert(LetterSound letterSound); +} 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 1ae30bc..7562f12 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 @@ -13,6 +13,7 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import ai.elimu.content_provider.room.dao.LetterSoundDao; import ai.elimu.content_provider.room.dao.SoundDao; import ai.elimu.content_provider.room.dao.AudioDao; import ai.elimu.content_provider.room.dao.EmojiDao; @@ -27,6 +28,7 @@ import ai.elimu.content_provider.room.dao.StoryBookParagraph_WordDao; import ai.elimu.content_provider.room.dao.VideoDao; import ai.elimu.content_provider.room.dao.WordDao; +import ai.elimu.content_provider.room.entity.LetterSound; import ai.elimu.content_provider.room.entity.Sound; import ai.elimu.content_provider.room.entity.Audio; import ai.elimu.content_provider.room.entity.Emoji; @@ -42,7 +44,7 @@ import ai.elimu.content_provider.room.entity.Video; import ai.elimu.content_provider.room.entity.Word; -@Database(version = 23, entities = {Letter.class, Sound.class, Word.class, Number.class, Emoji.class, Emoji_Word.class, Image.class, Image_Word.class, Audio.class, StoryBook.class, StoryBookChapter.class, StoryBookParagraph.class, StoryBookParagraph_Word.class, Video.class}) +@Database(version = 24, entities = {Letter.class, Sound.class, LetterSound.class, Word.class, Number.class, Emoji.class, Emoji_Word.class, Image.class, Image_Word.class, Audio.class, StoryBook.class, StoryBookChapter.class, StoryBookParagraph.class, StoryBookParagraph_Word.class, Video.class}) @TypeConverters({Converters.class}) public abstract class RoomDb extends RoomDatabase { @@ -50,6 +52,8 @@ public abstract class RoomDb extends RoomDatabase { public abstract SoundDao soundDao(); + public abstract LetterSoundDao letterSoundDao(); + public abstract WordDao wordDao(); public abstract NumberDao numberDao(); @@ -105,7 +109,8 @@ public static RoomDb getDatabase(final Context context) { MIGRATION_19_20, MIGRATION_20_21, MIGRATION_21_22, - MIGRATION_22_23 + MIGRATION_22_23, + MIGRATION_23_24 ) .build(); } @@ -314,4 +319,15 @@ public void migrate(SupportSQLiteDatabase database) { database.execSQL(sql); } }; + + private static final Migration MIGRATION_23_24 = new Migration(23, 24) { + @Override + public void migrate(SupportSQLiteDatabase database) { + Log.i(getClass().getName(), "migrate (23 --> 24)"); + + String sql = "CREATE TABLE IF NOT EXISTS `LetterSound` (`revisionNumber` INTEGER NOT NULL, `usageCount` INTEGER, `id` INTEGER, PRIMARY KEY(`id`))"; + Log.i(getClass().getName(), "sql: " + sql); + database.execSQL(sql); + } + }; } From 14b1fd40fdea99b9bce2dfa0123f9727c90463e3 Mon Sep 17 00:00:00 2001 From: jo-elimu <1451036+jo-elimu@users.noreply.github.com> Date: Mon, 27 Nov 2023 14:07:14 +0700 Subject: [PATCH 4/4] feat: Download letter-sound correspondences from REST API #59 --- .../elimu/content_provider/MainActivity.java | 1 + .../room/GsonToRoomConverter.java | 23 +++ .../room/dao/LetterSoundDao.java | 9 ++ .../ui/letter_sound/LetterSoundsFragment.java | 145 ++++++++++++++++++ .../letter_sound/LetterSoundsViewModel.java | 19 +++ .../res/drawable/ic_menu_emoji_symbols.xml | 11 ++ .../res/layout/fragment_letter_sounds.xml | 29 ++++ .../main/res/menu/activity_main_drawer.xml | 4 + .../main/res/navigation/mobile_navigation.xml | 6 + app/src/main/res/values/strings.xml | 1 + 10 files changed, 248 insertions(+) create mode 100644 app/src/main/java/ai/elimu/content_provider/ui/letter_sound/LetterSoundsFragment.java create mode 100644 app/src/main/java/ai/elimu/content_provider/ui/letter_sound/LetterSoundsViewModel.java create mode 100644 app/src/main/res/drawable/ic_menu_emoji_symbols.xml create mode 100644 app/src/main/res/layout/fragment_letter_sounds.xml diff --git a/app/src/main/java/ai/elimu/content_provider/MainActivity.java b/app/src/main/java/ai/elimu/content_provider/MainActivity.java index c03b7d2..dc94065 100644 --- a/app/src/main/java/ai/elimu/content_provider/MainActivity.java +++ b/app/src/main/java/ai/elimu/content_provider/MainActivity.java @@ -53,6 +53,7 @@ protected void onCreate(Bundle savedInstanceState) { R.id.nav_home, R.id.nav_letters, R.id.nav_sounds, + R.id.nav_letter_sounds, R.id.nav_words, R.id.nav_numbers, R.id.nav_emojis, diff --git a/app/src/main/java/ai/elimu/content_provider/room/GsonToRoomConverter.java b/app/src/main/java/ai/elimu/content_provider/room/GsonToRoomConverter.java index 99bf374..2bf8edf 100644 --- a/app/src/main/java/ai/elimu/content_provider/room/GsonToRoomConverter.java +++ b/app/src/main/java/ai/elimu/content_provider/room/GsonToRoomConverter.java @@ -1,5 +1,6 @@ package ai.elimu.content_provider.room; +import ai.elimu.content_provider.room.entity.LetterSound; import ai.elimu.content_provider.room.entity.Sound; import ai.elimu.content_provider.room.entity.Audio; import ai.elimu.content_provider.room.entity.Emoji; @@ -11,6 +12,7 @@ import ai.elimu.content_provider.room.entity.StoryBookParagraph; import ai.elimu.content_provider.room.entity.Video; import ai.elimu.content_provider.room.entity.Word; +import ai.elimu.model.v2.gson.content.LetterSoundGson; import ai.elimu.model.v2.gson.content.SoundGson; import ai.elimu.model.v2.gson.content.AudioGson; import ai.elimu.model.v2.gson.content.EmojiGson; @@ -67,6 +69,27 @@ public static Sound getSound(SoundGson soundGson) { } } + public static LetterSound getLetterSound(LetterSoundGson letterSoundGson) { + if (letterSoundGson == null) { + return null; + } else { + LetterSound letterSound = new LetterSound(); + + // BaseEntity + letterSound.setId(letterSoundGson.getId()); + + // Content + letterSound.setRevisionNumber(letterSoundGson.getRevisionNumber()); + letterSound.setUsageCount(letterSoundGson.getUsageCount()); + + // LetterSound + // TODO: letters + // TODO: sounds + + return letterSound; + } + } + public static Word getWord(WordGson wordGson) { if (wordGson == null) { return null; diff --git a/app/src/main/java/ai/elimu/content_provider/room/dao/LetterSoundDao.java b/app/src/main/java/ai/elimu/content_provider/room/dao/LetterSoundDao.java index aa4ef33..b37c1d0 100644 --- a/app/src/main/java/ai/elimu/content_provider/room/dao/LetterSoundDao.java +++ b/app/src/main/java/ai/elimu/content_provider/room/dao/LetterSoundDao.java @@ -2,6 +2,9 @@ import androidx.room.Dao; import androidx.room.Insert; +import androidx.room.Query; + +import java.util.List; import ai.elimu.content_provider.room.entity.LetterSound; @@ -10,4 +13,10 @@ public interface LetterSoundDao { @Insert void insert(LetterSound letterSound); + + @Query("SELECT * FROM LetterSound") + List loadAll(); + + @Query("DELETE FROM LetterSound") + void deleteAll(); } diff --git a/app/src/main/java/ai/elimu/content_provider/ui/letter_sound/LetterSoundsFragment.java b/app/src/main/java/ai/elimu/content_provider/ui/letter_sound/LetterSoundsFragment.java new file mode 100644 index 0000000..8412b85 --- /dev/null +++ b/app/src/main/java/ai/elimu/content_provider/ui/letter_sound/LetterSoundsFragment.java @@ -0,0 +1,145 @@ +package ai.elimu.content_provider.ui.letter_sound; + +import android.os.Bundle; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ProgressBar; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.lifecycle.Observer; +import androidx.lifecycle.ViewModelProvider; + +import com.google.android.material.snackbar.Snackbar; + +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import ai.elimu.content_provider.BaseApplication; +import ai.elimu.content_provider.R; +import ai.elimu.content_provider.rest.LetterSoundsService; +import ai.elimu.content_provider.room.GsonToRoomConverter; +import ai.elimu.content_provider.room.dao.LetterSoundDao; +import ai.elimu.content_provider.room.db.RoomDb; +import ai.elimu.content_provider.room.entity.LetterSound; +import ai.elimu.model.v2.gson.content.LetterSoundGson; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; +import retrofit2.Retrofit; + +public class LetterSoundsFragment extends Fragment { + + private LetterSoundsViewModel letterSoundsViewModel; + + private ProgressBar progressBar; + + private TextView textView; + + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + Log.i(getClass().getName(), "onCreateView"); + + letterSoundsViewModel = new ViewModelProvider(this).get(LetterSoundsViewModel.class); + View root = inflater.inflate(R.layout.fragment_letter_sounds, container, false); + progressBar = root.findViewById(R.id.progress_bar_letter_sounds); + textView = root.findViewById(R.id.text_letter_sounds); + letterSoundsViewModel.getText().observe(getViewLifecycleOwner(), new Observer() { + @Override + public void onChanged(@Nullable String s) { + Log.i(getClass().getName(), "onChanged"); + textView.setText(s); + } + }); + return root; + } + + @Override + public void onStart() { + Log.i(getClass().getName(), "onStart"); + super.onStart(); + + // Download LetterSounds from REST API, and store them in the database + BaseApplication baseApplication = (BaseApplication) getActivity().getApplication(); + Retrofit retrofit = baseApplication.getRetrofit(); + LetterSoundsService letterSoundsService = retrofit.create(LetterSoundsService.class); + Call> letterSoundGsonsCall = letterSoundsService.listLetterSounds(); + Log.i(getClass().getName(), "letterSoundGsonsCall.request(): " + letterSoundGsonsCall.request()); + letterSoundGsonsCall.enqueue(new Callback>() { + + @Override + public void onResponse(Call> call, Response> response) { + Log.i(getClass().getName(), "onResponse"); + + Log.i(getClass().getName(), "response: " + response); + if (response.isSuccessful()) { + List letterSoundGsons = response.body(); + Log.i(getClass().getName(), "letterSoundGsons.size(): " + letterSoundGsons.size()); + + if (letterSoundGsons.size() > 0) { + processResponseBody(letterSoundGsons); + } + } else { + // Handle error + Snackbar.make(textView, response.toString(), Snackbar.LENGTH_LONG) + .setBackgroundTint(getResources().getColor(R.color.deep_orange_darken_4)) + .show(); + progressBar.setVisibility(View.GONE); + } + } + + @Override + public void onFailure(Call> call, Throwable t) { + Log.e(getClass().getName(), "onFailure", t); + + Log.e(getClass().getName(), "t.getCause():", t.getCause()); + + // Handle error + Snackbar.make(textView, t.getCause().toString(), Snackbar.LENGTH_LONG) + .setBackgroundTint(getResources().getColor(R.color.deep_orange_darken_4)) + .show(); + progressBar.setVisibility(View.GONE); + } + }); + } + + private void processResponseBody(List letterSoundGsons) { + Log.i(getClass().getName(), "processResponseBody"); + + ExecutorService executorService = Executors.newSingleThreadExecutor(); + executorService.execute(new Runnable() { + @Override + public void run() { + Log.i(getClass().getName(), "run"); + + RoomDb roomDb = RoomDb.getDatabase(getContext()); + LetterSoundDao letterSoundDao = roomDb.letterSoundDao(); + + // Empty the database table before downloading up-to-date content + letterSoundDao.deleteAll(); + + for (LetterSoundGson letterSoundGson : letterSoundGsons) { + Log.i(getClass().getName(), "letterSoundGson.getId(): " + letterSoundGson.getId()); + + // Store the LetterSound in the database + LetterSound letterSound = GsonToRoomConverter.getLetterSound(letterSoundGson); + letterSoundDao.insert(letterSound); + Log.i(getClass().getName(), "Stored LetterSound in database with ID " + letterSound.getId()); + } + + // Update the UI + List letterSounds = letterSoundDao.loadAll(); + Log.i(getClass().getName(), "letterSounds.size(): " + letterSounds.size()); + getActivity().runOnUiThread(() -> { + textView.setText("letterSounds.size(): " + letterSounds.size()); + Snackbar.make(textView, "letterSounds.size(): " + letterSounds.size(), Snackbar.LENGTH_LONG).show(); + progressBar.setVisibility(View.GONE); + }); + } + }); + } +} diff --git a/app/src/main/java/ai/elimu/content_provider/ui/letter_sound/LetterSoundsViewModel.java b/app/src/main/java/ai/elimu/content_provider/ui/letter_sound/LetterSoundsViewModel.java new file mode 100644 index 0000000..40e0f9b --- /dev/null +++ b/app/src/main/java/ai/elimu/content_provider/ui/letter_sound/LetterSoundsViewModel.java @@ -0,0 +1,19 @@ +package ai.elimu.content_provider.ui.letter_sound; + +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; +import androidx.lifecycle.ViewModel; + +public class LetterSoundsViewModel extends ViewModel { + + private MutableLiveData text; + + public LetterSoundsViewModel() { + text = new MutableLiveData<>(); + text.setValue("LetterSoundsViewModel"); + } + + public LiveData getText() { + return text; + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_menu_emoji_symbols.xml b/app/src/main/res/drawable/ic_menu_emoji_symbols.xml new file mode 100644 index 0000000..21bc0b7 --- /dev/null +++ b/app/src/main/res/drawable/ic_menu_emoji_symbols.xml @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_letter_sounds.xml b/app/src/main/res/layout/fragment_letter_sounds.xml new file mode 100644 index 0000000..65c9187 --- /dev/null +++ b/app/src/main/res/layout/fragment_letter_sounds.xml @@ -0,0 +1,29 @@ + + + + + + + diff --git a/app/src/main/res/menu/activity_main_drawer.xml b/app/src/main/res/menu/activity_main_drawer.xml index 5ce4299..0a429f4 100644 --- a/app/src/main/res/menu/activity_main_drawer.xml +++ b/app/src/main/res/menu/activity_main_drawer.xml @@ -21,6 +21,10 @@ android:id="@+id/nav_sounds" android:icon="@drawable/ic_menu_music_note" android:title="@string/menu_sounds" /> + + + Home Letters + Letter-Sounds Sounds Words Numbers