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
[
-](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