diff --git a/app/build.gradle b/app/build.gradle index 9a116152..b00671e6 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -38,6 +38,10 @@ android { vectorDrawables.useSupportLibrary = true } + sourceSets { + androidTest.assets.srcDirs += files("$projectDir/schemas".toString()) + } + signingConfigs { fastlane { storeFile file(getKey("keystore", "storeFile")) @@ -145,7 +149,7 @@ dependencies { kapt "androidx.room:room-compiler:$roomVersion" implementation "androidx.room:room-ktx:$roomVersion" implementation "androidx.room:room-rxjava2:$roomVersion" - testImplementation "androidx.room:room-testing:$roomVersion" + androidTestImplementation "androidx.room:room-testing:$roomVersion" implementation 'com.sylversky.fontreplacer:fontreplacer:1.0' implementation 'com.yqritc:recyclerview-flexibledivider:1.4.0' diff --git a/app/schemas/ro.code4.monitorizarevot.data.AppDatabase/2.json b/app/schemas/ro.code4.monitorizarevot.data.AppDatabase/2.json new file mode 100644 index 00000000..dff54b12 --- /dev/null +++ b/app/schemas/ro.code4.monitorizarevot.data.AppDatabase/2.json @@ -0,0 +1,637 @@ +{ + "formatVersion": 1, + "database": { + "version": 2, + "identityHash": "f0637c4d16330051d9e5618d5196b1a3", + "entities": [ + { + "tableName": "county", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `code` TEXT NOT NULL, `name` TEXT NOT NULL, `limit` INTEGER NOT NULL, `diaspora` INTEGER, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "code", + "columnName": "code", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "limit", + "columnName": "limit", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaspora", + "columnName": "diaspora", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": false + }, + "indices": [ + { + "name": "index_county_code", + "unique": true, + "columnNames": [ + "code" + ], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_county_code` ON `${TABLE_NAME}` (`code`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "polling_station", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `countyCode` TEXT NOT NULL, `idPollingStation` INTEGER NOT NULL, `urbanArea` INTEGER NOT NULL, `isPollingStationPresidentFemale` INTEGER NOT NULL, `observerArrivalTime` TEXT, `observerLeaveTime` TEXT, `synced` INTEGER NOT NULL, PRIMARY KEY(`id`), FOREIGN KEY(`countyCode`) REFERENCES `county`(`code`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "countyCode", + "columnName": "countyCode", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "idPollingStation", + "columnName": "idPollingStation", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "urbanArea", + "columnName": "urbanArea", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isPollingStationPresidentFemale", + "columnName": "isPollingStationPresidentFemale", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "observerArrivalTime", + "columnName": "observerArrivalTime", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "observerLeaveTime", + "columnName": "observerLeaveTime", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "synced", + "columnName": "synced", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": false + }, + "indices": [ + { + "name": "index_polling_station_countyCode_idPollingStation", + "unique": true, + "columnNames": [ + "countyCode", + "idPollingStation" + ], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_polling_station_countyCode_idPollingStation` ON `${TABLE_NAME}` (`countyCode`, `idPollingStation`)" + } + ], + "foreignKeys": [ + { + "table": "county", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "countyCode" + ], + "referencedColumns": [ + "code" + ] + } + ] + }, + { + "tableName": "form_details", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `code` TEXT NOT NULL, `description` TEXT NOT NULL, `formVersion` INTEGER NOT NULL, `diaspora` INTEGER, `order` INTEGER NOT NULL, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "code", + "columnName": "code", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "formVersion", + "columnName": "formVersion", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaspora", + "columnName": "diaspora", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "order", + "columnName": "order", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "section", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uniqueId` TEXT NOT NULL, `code` TEXT, `description` TEXT, `formId` INTEGER NOT NULL, PRIMARY KEY(`uniqueId`), FOREIGN KEY(`formId`) REFERENCES `form_details`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "uniqueId", + "columnName": "uniqueId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "code", + "columnName": "code", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "formId", + "columnName": "formId", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "uniqueId" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [ + { + "table": "form_details", + "onDelete": "CASCADE", + "onUpdate": "CASCADE", + "columns": [ + "formId" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "question", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `text` TEXT NOT NULL, `code` TEXT NOT NULL, `questionType` INTEGER NOT NULL, `sectionId` TEXT NOT NULL, `hasNotes` INTEGER NOT NULL, PRIMARY KEY(`id`), FOREIGN KEY(`sectionId`) REFERENCES `section`(`uniqueId`) ON UPDATE CASCADE ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "text", + "columnName": "text", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "code", + "columnName": "code", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "questionType", + "columnName": "questionType", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "sectionId", + "columnName": "sectionId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "hasNotes", + "columnName": "hasNotes", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [ + { + "table": "section", + "onDelete": "CASCADE", + "onUpdate": "CASCADE", + "columns": [ + "sectionId" + ], + "referencedColumns": [ + "uniqueId" + ] + } + ] + }, + { + "tableName": "answer", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`idOption` INTEGER NOT NULL, `text` TEXT NOT NULL, `isFreeText` INTEGER NOT NULL, `questionId` INTEGER NOT NULL, PRIMARY KEY(`idOption`), FOREIGN KEY(`questionId`) REFERENCES `question`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "idOption", + "columnName": "idOption", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "text", + "columnName": "text", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "isFreeText", + "columnName": "isFreeText", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "questionId", + "columnName": "questionId", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "idOption" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [ + { + "table": "question", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "questionId" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "answered_question", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `formId` INTEGER NOT NULL, `questionId` INTEGER NOT NULL, `countyCode` TEXT NOT NULL, `pollingStationNumber` INTEGER NOT NULL, `savedLocally` INTEGER NOT NULL, `synced` INTEGER NOT NULL, PRIMARY KEY(`id`), FOREIGN KEY(`formId`) REFERENCES `form_details`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`questionId`) REFERENCES `question`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`countyCode`, `pollingStationNumber`) REFERENCES `polling_station`(`countyCode`, `idPollingStation`) ON UPDATE NO ACTION ON DELETE NO ACTION )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "formId", + "columnName": "formId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "questionId", + "columnName": "questionId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "countyCode", + "columnName": "countyCode", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "pollingStationNumber", + "columnName": "pollingStationNumber", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "savedLocally", + "columnName": "savedLocally", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "synced", + "columnName": "synced", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": false + }, + "indices": [ + { + "name": "index_answered_question_countyCode_pollingStationNumber_id", + "unique": true, + "columnNames": [ + "countyCode", + "pollingStationNumber", + "id" + ], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_answered_question_countyCode_pollingStationNumber_id` ON `${TABLE_NAME}` (`countyCode`, `pollingStationNumber`, `id`)" + } + ], + "foreignKeys": [ + { + "table": "form_details", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "formId" + ], + "referencedColumns": [ + "id" + ] + }, + { + "table": "question", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "questionId" + ], + "referencedColumns": [ + "id" + ] + }, + { + "table": "polling_station", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "countyCode", + "pollingStationNumber" + ], + "referencedColumns": [ + "countyCode", + "idPollingStation" + ] + } + ] + }, + { + "tableName": "selected_answer", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`optionId` INTEGER NOT NULL, `value` TEXT, `countyCode` TEXT NOT NULL, `pollingStationNumber` INTEGER NOT NULL, `questionId` TEXT NOT NULL, PRIMARY KEY(`optionId`, `countyCode`, `pollingStationNumber`), FOREIGN KEY(`optionId`) REFERENCES `answer`(`idOption`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`countyCode`, `pollingStationNumber`, `questionId`) REFERENCES `answered_question`(`countyCode`, `pollingStationNumber`, `id`) ON UPDATE CASCADE ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "optionId", + "columnName": "optionId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "value", + "columnName": "value", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "countyCode", + "columnName": "countyCode", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "pollingStationNumber", + "columnName": "pollingStationNumber", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "questionId", + "columnName": "questionId", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "optionId", + "countyCode", + "pollingStationNumber" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [ + { + "table": "answer", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "optionId" + ], + "referencedColumns": [ + "idOption" + ] + }, + { + "table": "answered_question", + "onDelete": "CASCADE", + "onUpdate": "CASCADE", + "columns": [ + "countyCode", + "pollingStationNumber", + "questionId" + ], + "referencedColumns": [ + "countyCode", + "pollingStationNumber", + "id" + ] + } + ] + }, + { + "tableName": "note", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `uriPath` TEXT, `description` TEXT NOT NULL, `questionId` INTEGER, `date` INTEGER NOT NULL, `countyCode` TEXT NOT NULL, `pollingStationNumber` INTEGER NOT NULL, `synced` INTEGER NOT NULL, FOREIGN KEY(`questionId`) REFERENCES `question`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`countyCode`, `pollingStationNumber`) REFERENCES `polling_station`(`countyCode`, `idPollingStation`) ON UPDATE NO ACTION ON DELETE NO ACTION )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "uriPath", + "columnName": "uriPath", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "questionId", + "columnName": "questionId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "countyCode", + "columnName": "countyCode", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "pollingStationNumber", + "columnName": "pollingStationNumber", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "synced", + "columnName": "synced", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_note_countyCode_pollingStationNumber_questionId", + "unique": false, + "columnNames": [ + "countyCode", + "pollingStationNumber", + "questionId" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_note_countyCode_pollingStationNumber_questionId` ON `${TABLE_NAME}` (`countyCode`, `pollingStationNumber`, `questionId`)" + } + ], + "foreignKeys": [ + { + "table": "question", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "questionId" + ], + "referencedColumns": [ + "id" + ] + }, + { + "table": "polling_station", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "countyCode", + "pollingStationNumber" + ], + "referencedColumns": [ + "countyCode", + "idPollingStation" + ] + } + ] + } + ], + "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, 'f0637c4d16330051d9e5618d5196b1a3')" + ] + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/ro/code4/monitorizarevot/MigrationTest.kt b/app/src/androidTest/java/ro/code4/monitorizarevot/MigrationTest.kt new file mode 100644 index 00000000..a9e8bea7 --- /dev/null +++ b/app/src/androidTest/java/ro/code4/monitorizarevot/MigrationTest.kt @@ -0,0 +1,81 @@ +package ro.code4.monitorizarevot + +import android.content.ContentValues +import android.database.sqlite.SQLiteDatabase +import androidx.room.Room +import androidx.room.testing.MigrationTestHelper +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.platform.app.InstrumentationRegistry +import org.junit.Assert.* +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import ro.code4.monitorizarevot.data.AppDatabase +import ro.code4.monitorizarevot.data.Migrations +import java.io.IOException + +@RunWith(AndroidJUnit4::class) +class MigrationTest { + + @get:Rule + val helper = MigrationTestHelper( + InstrumentationRegistry.getInstrumentation(), + AppDatabase::class.java.canonicalName + ) + + @Test + @Throws(IOException::class) + fun migrate1To2() { + var rowId = -1L + helper.createDatabase(TEST_DB, 1).use { + rowId = it.insert( + "county", + SQLiteDatabase.CONFLICT_REPLACE, + ContentValues().apply { + put("id", 1) + put("code", "AA") + put("name", "TEST") + put("`limit`", 12) + } + ) + } + + helper.runMigrationsAndValidate(TEST_DB, 2, true, Migrations.MIGRATION_1_2).use { db -> + db.query("SELECT * FROM county WHERE rowid = ?", arrayOf(rowId)).use { c -> + assertNotNull(c) + assertTrue(c.moveToFirst()) + // Check new column + assertEquals(null, c.getInt(c.getColumnIndex("diaspora"))) + // Check some old columns + assertEquals(1, c.getInt(c.getColumnIndex("id"))) + assertEquals("AA", c.getString(c.getColumnIndex("code"))) + } + } + + } + + @Test + @Throws(IOException::class) + fun migrateAll() { + // Create earliest version of the database. + helper.createDatabase(TEST_DB, 1).apply { + close() + } + + // Open latest version of the database. Room will validate the schema + // once all migrations execute. + Room.databaseBuilder( + InstrumentationRegistry.getInstrumentation().targetContext, + AppDatabase::class.java, + TEST_DB + ).addMigrations(*Migrations.ALL).build().apply { + openHelper.writableDatabase + close() + } + } + + + companion object { + private const val TEST_DB = "test-db" + } +} \ No newline at end of file diff --git a/app/src/main/java/ro/code4/monitorizarevot/data/AppDatabase.kt b/app/src/main/java/ro/code4/monitorizarevot/data/AppDatabase.kt index df8badc3..46ce76b4 100644 --- a/app/src/main/java/ro/code4/monitorizarevot/data/AppDatabase.kt +++ b/app/src/main/java/ro/code4/monitorizarevot/data/AppDatabase.kt @@ -16,7 +16,7 @@ import ro.code4.monitorizarevot.data.model.answers.SelectedAnswer @Database( entities = [County::class, PollingStation::class, FormDetails::class, Section::class, Question::class, Answer::class, AnsweredQuestion::class, SelectedAnswer::class, Note::class], - version = 1 + version = 2 ) @TypeConverters(DateConverter::class) abstract class AppDatabase : RoomDatabase() { @@ -38,7 +38,7 @@ abstract class AppDatabase : RoomDatabase() { context.applicationContext, AppDatabase::class.java, "database" - ).build() + ).addMigrations(*Migrations.ALL).build() } } } diff --git a/app/src/main/java/ro/code4/monitorizarevot/data/Migrations.kt b/app/src/main/java/ro/code4/monitorizarevot/data/Migrations.kt new file mode 100644 index 00000000..3397077c --- /dev/null +++ b/app/src/main/java/ro/code4/monitorizarevot/data/Migrations.kt @@ -0,0 +1,22 @@ +package ro.code4.monitorizarevot.data + +import androidx.room.migration.Migration +import androidx.sqlite.db.SupportSQLiteDatabase + +object Migrations { + /* + According to https://developer.android.com/reference/android/database/sqlite/package-summary Android has old SQLite. + For example, you can't rename column without recreating table + */ + + // this is an example for migration + val MIGRATION_1_2 = object : Migration(1, 2) { + override fun migrate(database: SupportSQLiteDatabase) { + database.execSQL("ALTER TABLE county ADD COLUMN `diaspora` INTEGER DEFAULT NULL") + database.execSQL("ALTER TABLE form_details ADD COLUMN `diaspora` INTEGER DEFAULT NULL") + database.execSQL("ALTER TABLE form_details ADD COLUMN `order` INTEGER NOT NULL DEFAULT 0") + } + } + + val ALL: Array = arrayOf(MIGRATION_1_2) +} \ No newline at end of file diff --git a/app/src/main/java/ro/code4/monitorizarevot/data/dao/FormsDao.kt b/app/src/main/java/ro/code4/monitorizarevot/data/dao/FormsDao.kt index 007a0494..6df47852 100644 --- a/app/src/main/java/ro/code4/monitorizarevot/data/dao/FormsDao.kt +++ b/app/src/main/java/ro/code4/monitorizarevot/data/dao/FormsDao.kt @@ -67,7 +67,7 @@ interface FormsDao { ): LiveData> - @Query("SELECT * FROM form_details") + @Query("SELECT * FROM form_details ORDER BY `order`") fun getFormsWithSections(): LiveData> @Query("SELECT * FROM section where formId=:formId") diff --git a/app/src/main/java/ro/code4/monitorizarevot/data/model/County.kt b/app/src/main/java/ro/code4/monitorizarevot/data/model/County.kt index d640a2e3..92e1e6ce 100644 --- a/app/src/main/java/ro/code4/monitorizarevot/data/model/County.kt +++ b/app/src/main/java/ro/code4/monitorizarevot/data/model/County.kt @@ -23,6 +23,9 @@ class County { @Expose var limit: Int = 0 + @Expose + var diaspora: Boolean? = null + override fun toString(): String = name override fun equals(other: Any?): Boolean { diff --git a/app/src/main/java/ro/code4/monitorizarevot/data/model/FormDetails.kt b/app/src/main/java/ro/code4/monitorizarevot/data/model/FormDetails.kt index 04d79c76..27dd4012 100644 --- a/app/src/main/java/ro/code4/monitorizarevot/data/model/FormDetails.kt +++ b/app/src/main/java/ro/code4/monitorizarevot/data/model/FormDetails.kt @@ -24,6 +24,12 @@ class FormDetails { @SerializedName("ver") var formVersion: Int = 0 + @Expose + var diaspora: Boolean? = null + + @Expose + var order: Int = 0 + @Ignore lateinit var sections: List
diff --git a/app/src/main/java/ro/code4/monitorizarevot/repositories/Repository.kt b/app/src/main/java/ro/code4/monitorizarevot/repositories/Repository.kt index 6c0c4e4d..7f8989f5 100644 --- a/app/src/main/java/ro/code4/monitorizarevot/repositories/Repository.kt +++ b/app/src/main/java/ro/code4/monitorizarevot/repositories/Repository.kt @@ -29,6 +29,7 @@ import ro.code4.monitorizarevot.helper.createMultipart import ro.code4.monitorizarevot.services.ApiInterface import ro.code4.monitorizarevot.services.LoginInterface import java.io.File +import java.util.* class Repository : KoinComponent { @@ -63,7 +64,10 @@ class Repository : KoinComponent { //todo side effects are recommended in "do" methods, check: https://github.com/Froussios/Intro-To-RxJava/blob/master/Part%203%20-%20Taming%20the%20sequence/1.%20Side%20effects.md if (apiCounties.isNotEmpty() && dbCounties != apiCounties) { // TODO deleteCounties() - db.countyDao().save(*apiCounties.map { it }.toTypedArray()) + db.countyDao().save(*apiCounties.map { + it.name = it.name.toLowerCase(Locale.getDefault()).capitalize() + it + }.toTypedArray()) return@BiFunction apiCounties } dbCounties @@ -166,6 +170,7 @@ class Repository : KoinComponent { return } val apiFormDetails = response.formVersions + apiFormDetails.forEachIndexed { index, formDetails -> formDetails.order = index } if (dbFormDetails == null || dbFormDetails.isEmpty()) { saveFormDetails(apiFormDetails) return diff --git a/app/src/main/java/ro/code4/monitorizarevot/services/ApiInterface.kt b/app/src/main/java/ro/code4/monitorizarevot/services/ApiInterface.kt index 0a11e7ac..620daad9 100644 --- a/app/src/main/java/ro/code4/monitorizarevot/services/ApiInterface.kt +++ b/app/src/main/java/ro/code4/monitorizarevot/services/ApiInterface.kt @@ -13,7 +13,7 @@ import ro.code4.monitorizarevot.data.model.response.VersionResponse interface ApiInterface { @GET("/api/v1/form") - fun getForms(): Observable + fun getForms(@Query("diaspora") diaspora: Boolean? = null): Observable @GET("/api/v1/polling-station") fun getCounties(): Single> diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 201fa336..862806fe 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -159,7 +159,8 @@ 24sp uniform 24sp - 3 + 4 + 12sp bold sans-serif-bold 2sp