From f3e456ac2806d86034929cff69fbae13b715b685 Mon Sep 17 00:00:00 2001 From: Billy Brawner Date: Thu, 1 Nov 2018 19:12:03 -0600 Subject: [PATCH] Update database structure to match server --- app/build.gradle | 8 +- .../1.json | 63 +++++++++ .../3.json | 125 ++++++++++++++++++ .../com/wbrawner/budget/MigrationTests.java | 109 +++++++++++++++ app/src/main/AndroidManifest.xml | 8 +- .../wbrawner/budget/AllowanceApplication.kt | 2 + .../wbrawner/budget/data/BudgetDatabase.kt | 6 +- .../budget/data/CategoryRepository.kt | 4 +- .../budget/data/TransactionRepository.kt | 8 +- .../wbrawner/budget/data/TransactionType.kt | 29 ---- .../wbrawner/budget/data/TypeConverters.kt | 8 -- .../wbrawner/budget/data/dao/CategoryDao.kt | 8 +- .../budget/data/dao/TransactionDao.kt | 10 +- .../budget/data/migrations/MIGRATION_1_2.kt | 7 +- .../budget/data/migrations/MIGRATION_2_3.kt | 20 +++ .../wbrawner/budget/data/model/Category.kt | 5 +- .../wbrawner/budget/data/model/Transaction.kt | 10 +- .../MainActivity.kt} | 31 ++--- .../categories/AddEditCategoryActivity.kt | 9 +- .../{ => ui}/categories/CategoryAdapter.kt | 16 ++- .../categories/CategoryListFragment.kt | 4 +- .../{ => ui}/categories/CategoryViewModel.kt | 4 +- .../{ => ui}/overview/OverviewFragment.kt | 12 +- .../AddEditTransactionActivity.kt | 36 +++-- .../transactions/TransactionAdapter.kt | 15 +-- .../transactions/TransactionListFragment.kt | 20 +-- .../transactions/TransactionViewModel.kt | 10 +- .../res/layout/activity_add_edit_category.xml | 7 +- .../layout/activity_add_edit_transaction.xml | 31 +++-- .../res/layout/activity_transaction_list.xml | 4 +- .../main/res/layout/list_item_category.xml | 2 +- app/src/main/res/menu/main_navigation.xml | 10 +- app/src/main/res/values/strings.xml | 15 +-- app/src/main/res/xml/shortcuts.xml | 26 +--- build.gradle | 1 + 35 files changed, 474 insertions(+), 209 deletions(-) create mode 100644 app/schemas/com.wbrawner.budget.data.BudgetDatabase/1.json create mode 100644 app/schemas/com.wbrawner.budget.data.BudgetDatabase/3.json create mode 100644 app/src/androidTest/java/com/wbrawner/budget/MigrationTests.java delete mode 100644 app/src/main/java/com/wbrawner/budget/data/TransactionType.kt create mode 100644 app/src/main/java/com/wbrawner/budget/data/migrations/MIGRATION_2_3.kt rename app/src/main/java/com/wbrawner/budget/{transactions/TransactionListActivity.kt => ui/MainActivity.kt} (65%) rename app/src/main/java/com/wbrawner/budget/{ => ui}/categories/AddEditCategoryActivity.kt (93%) rename app/src/main/java/com/wbrawner/budget/{ => ui}/categories/CategoryAdapter.kt (80%) rename app/src/main/java/com/wbrawner/budget/{ => ui}/categories/CategoryListFragment.kt (95%) rename app/src/main/java/com/wbrawner/budget/{ => ui}/categories/CategoryViewModel.kt (95%) rename app/src/main/java/com/wbrawner/budget/{ => ui}/overview/OverviewFragment.kt (87%) rename app/src/main/java/com/wbrawner/budget/{ => ui}/transactions/AddEditTransactionActivity.kt (83%) rename app/src/main/java/com/wbrawner/budget/{ => ui}/transactions/TransactionAdapter.kt (85%) rename app/src/main/java/com/wbrawner/budget/{ => ui}/transactions/TransactionListFragment.kt (80%) rename app/src/main/java/com/wbrawner/budget/{ => ui}/transactions/TransactionViewModel.kt (79%) diff --git a/app/build.gradle b/app/build.gradle index 3d11e8a..2e99d06 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,9 +1,6 @@ apply plugin: 'com.android.application' - apply plugin: 'kotlin-kapt' - apply plugin: 'kotlin-android' - apply plugin: 'kotlin-android-extensions' @@ -50,16 +47,17 @@ dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation 'com.android.support:appcompat-v7:27.1.1' - implementation 'com.android.support.constraint:constraint-layout:1.1.2' + implementation 'com.android.support.constraint:constraint-layout:1.1.3' implementation 'com.android.support:design:27.1.1' implementation "com.android.support:support-emoji-bundled:27.1.1" + implementation 'com.github.BlacKCaT27:CurrencyEditText:2.0.2' def room_version = "1.1.1" def lifecycle_version = "1.1.1" // ViewModel and LiveData implementation "android.arch.lifecycle:extensions:$lifecycle_version" implementation "android.arch.persistence.room:runtime:$room_version" kapt "android.arch.persistence.room:compiler:$room_version" - testImplementation "android.arch.persistence.room:testing:$room_version" + androidTestImplementation "android.arch.persistence.room:testing:$room_version" testImplementation 'junit:junit:4.12' // ACRA Crash reporting diff --git a/app/schemas/com.wbrawner.budget.data.BudgetDatabase/1.json b/app/schemas/com.wbrawner.budget.data.BudgetDatabase/1.json new file mode 100644 index 0000000..d9d2880 --- /dev/null +++ b/app/schemas/com.wbrawner.budget.data.BudgetDatabase/1.json @@ -0,0 +1,63 @@ +{ + "formatVersion": 1, + "database": { + "version": 1, + "identityHash": "da32c301dc558cb73099ff325bb88fb7", + "entities": [ + { + "tableName": "Transaction", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER, `title` TEXT NOT NULL, `date` TEXT NOT NULL, `description` TEXT NOT NULL, `amount` REAL NOT NULL, `type` TEXT NOT NULL, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "amount", + "columnName": "amount", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + } + ], + "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, \"da32c301dc558cb73099ff325bb88fb7\")" + ] + } +} \ No newline at end of file diff --git a/app/schemas/com.wbrawner.budget.data.BudgetDatabase/3.json b/app/schemas/com.wbrawner.budget.data.BudgetDatabase/3.json new file mode 100644 index 0000000..396b1d7 --- /dev/null +++ b/app/schemas/com.wbrawner.budget.data.BudgetDatabase/3.json @@ -0,0 +1,125 @@ +{ + "formatVersion": 1, + "database": { + "version": 3, + "identityHash": "68f2dbe4273bb745930a348dc280ae96", + "entities": [ + { + "tableName": "Transaction", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER, `remoteId` TEXT, `name` TEXT NOT NULL, `date` TEXT NOT NULL, `description` TEXT NOT NULL, `amount` INTEGER NOT NULL, `categoryId` INTEGER, `isExpense` INTEGER NOT NULL, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "remoteId", + "columnName": "remoteId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "amount", + "columnName": "amount", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "categoryId", + "columnName": "categoryId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "isExpense", + "columnName": "isExpense", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Category", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER, `remoteId` TEXT, `name` TEXT NOT NULL, `amount` INTEGER NOT NULL, `repeat` TEXT, `color` INTEGER NOT NULL, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "remoteId", + "columnName": "remoteId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "amount", + "columnName": "amount", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "repeat", + "columnName": "repeat", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "color", + "columnName": "color", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + } + ], + "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, \"68f2dbe4273bb745930a348dc280ae96\")" + ] + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/com/wbrawner/budget/MigrationTests.java b/app/src/androidTest/java/com/wbrawner/budget/MigrationTests.java new file mode 100644 index 0000000..2734f14 --- /dev/null +++ b/app/src/androidTest/java/com/wbrawner/budget/MigrationTests.java @@ -0,0 +1,109 @@ +package com.wbrawner.budget; + +import android.arch.persistence.db.SupportSQLiteDatabase; +import android.arch.persistence.db.framework.FrameworkSQLiteOpenHelperFactory; +import android.arch.persistence.room.testing.MigrationTestHelper; +import android.database.Cursor; +import android.support.test.InstrumentationRegistry; +import android.support.test.runner.AndroidJUnit4; + +import com.wbrawner.budget.data.BudgetDatabase; +import com.wbrawner.budget.data.migrations.MIGRATION_1_2; +import com.wbrawner.budget.data.migrations.MIGRATION_2_3; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.IOException; + +import static junit.framework.Assert.assertNull; +import static junit.framework.TestCase.assertEquals; +import static junit.framework.TestCase.assertTrue; + +@RunWith(AndroidJUnit4.class) +public class MigrationTests { + private static final String TEST_DB = "migration-test"; + + @Rule + public MigrationTestHelper migrationHelper; + + public MigrationTests() { + this.migrationHelper = new MigrationTestHelper( + InstrumentationRegistry.getInstrumentation(), + BudgetDatabase.class.getCanonicalName(), + new FrameworkSQLiteOpenHelperFactory() + ); + } + + @Test + public void migrate1to2() throws IOException { + SupportSQLiteDatabase db = migrationHelper.createDatabase(TEST_DB, 1); + db.execSQL("INSERT INTO `Transaction` (id,title,date,description,amount,type) " + + "VALUES (1,'An expense','2018-10-31','Spent some money',12.34,'EXPENSE')"); + db.close(); + db = migrationHelper.runMigrationsAndValidate( + TEST_DB, + 2, + true, + new MIGRATION_1_2() + ); + Cursor cursor = db.query("SELECT * FROM 'Transaction'"); + assertEquals(1, cursor.getCount()); + cursor.moveToFirst(); + assertEquals(1, cursor.getInt(cursor.getColumnIndex("id"))); + assertEquals("An expense", cursor.getString(cursor.getColumnIndex("title"))); + assertEquals("2018-10-31", cursor.getString(cursor.getColumnIndex("date"))); + assertEquals("Spent some money", cursor.getString(cursor.getColumnIndex("description"))); + assertEquals(12.34, cursor.getDouble(cursor.getColumnIndex("amount"))); + assertEquals(0, cursor.getInt(cursor.getColumnIndex("categoryId"))); + assertEquals("EXPENSE", cursor.getString(cursor.getColumnIndex("type"))); + } + + @Test + public void migrate2to3() throws IOException { + SupportSQLiteDatabase db = migrationHelper.createDatabase(TEST_DB, 2); + db.execSQL("INSERT INTO `Transaction` (id,title,date,description,amount,categoryId,type) " + + "VALUES (1,'An expense','2018-10-31','Spent some money',12.34,1,'EXPENSE')"); + db.execSQL("INSERT INTO `Transaction` (id,title,date,description,amount,categoryId,type) " + + "VALUES (2,'Some income','2018-01-02','Made some money',42.65,0,'INCOME')"); + db.execSQL("INSERT INTO `Category` (id,name,amount,repeat,color) " + + "VALUES (1,'Groceries',1234.56,'monthly',987)"); + db.close(); + db = migrationHelper.runMigrationsAndValidate( + TEST_DB, + 3, + true, + new MIGRATION_2_3() + ); + Cursor cursor = db.query("SELECT * FROM 'Transaction'"); + assertEquals(2, cursor.getCount()); + assertTrue(cursor.moveToFirst()); + assertEquals(1, cursor.getInt(cursor.getColumnIndex("id"))); + assertNull(cursor.getString(cursor.getColumnIndex("remoteId"))); + assertEquals("An expense", cursor.getString(cursor.getColumnIndex("name"))); + assertEquals("2018-10-31", cursor.getString(cursor.getColumnIndex("date"))); + assertEquals("Spent some money", cursor.getString(cursor.getColumnIndex("description"))); + assertEquals(1234, cursor.getInt(cursor.getColumnIndex("amount"))); + assertEquals(1, cursor.getInt(cursor.getColumnIndex("categoryId"))); + assertEquals(1, cursor.getInt(cursor.getColumnIndex("isExpense"))); + assertTrue(cursor.moveToNext()); + assertEquals(2, cursor.getInt(cursor.getColumnIndex("id"))); + assertNull(cursor.getString(cursor.getColumnIndex("remoteId"))); + assertEquals("Some income", cursor.getString(cursor.getColumnIndex("name"))); + assertEquals("2018-01-02", cursor.getString(cursor.getColumnIndex("date"))); + assertEquals("Made some money", cursor.getString(cursor.getColumnIndex("description"))); + assertEquals(4265, cursor.getInt(cursor.getColumnIndex("amount"))); + assertEquals(0, cursor.getInt(cursor.getColumnIndex("categoryId"))); + assertEquals(0, cursor.getInt(cursor.getColumnIndex("isExpense"))); + cursor = db.query("SELECT * FROM 'Category'"); + assertEquals(1, cursor.getCount()); + assertTrue(cursor.moveToFirst()); + assertEquals(1, cursor.getInt(cursor.getColumnIndex("id"))); + assertNull(cursor.getString(cursor.getColumnIndex("remoteId"))); + assertEquals("Groceries", cursor.getString(cursor.getColumnIndex("name"))); + assertEquals(123456, cursor.getInt(cursor.getColumnIndex("amount"))); + assertEquals("monthly", cursor.getString(cursor.getColumnIndex("repeat"))); + assertEquals(987, cursor.getInt(cursor.getColumnIndex("color"))); + } +} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 36c5963..b16d5dc 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -10,7 +10,7 @@ android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> - + @@ -20,8 +20,8 @@ android:name="android.app.shortcuts" android:resource="@xml/shortcuts" /> - - + + - \ No newline at end of file + diff --git a/app/src/main/java/com/wbrawner/budget/AllowanceApplication.kt b/app/src/main/java/com/wbrawner/budget/AllowanceApplication.kt index 30efa53..801dbd0 100644 --- a/app/src/main/java/com/wbrawner/budget/AllowanceApplication.kt +++ b/app/src/main/java/com/wbrawner/budget/AllowanceApplication.kt @@ -7,6 +7,7 @@ import com.wbrawner.budget.data.dao.TransactionDao import com.wbrawner.budget.data.BudgetDatabase import com.wbrawner.budget.data.dao.CategoryDao import com.wbrawner.budget.data.migrations.MIGRATION_1_2 +import com.wbrawner.budget.data.migrations.MIGRATION_2_3 import org.acra.ACRA import org.acra.annotation.AcraCore import org.acra.annotation.AcraHttpSender @@ -33,6 +34,7 @@ class AllowanceApplication: Application() { database = Room.databaseBuilder(applicationContext, BudgetDatabase::class.java, "transactions") .addMigrations(MIGRATION_1_2()) + .addMigrations(MIGRATION_2_3()) .build() transactionDao = database.transactionDao() categoryDao = database.categoryDao() diff --git a/app/src/main/java/com/wbrawner/budget/data/BudgetDatabase.kt b/app/src/main/java/com/wbrawner/budget/data/BudgetDatabase.kt index 004a6b3..a48f4a5 100644 --- a/app/src/main/java/com/wbrawner/budget/data/BudgetDatabase.kt +++ b/app/src/main/java/com/wbrawner/budget/data/BudgetDatabase.kt @@ -8,9 +8,9 @@ import com.wbrawner.budget.data.dao.TransactionDao import com.wbrawner.budget.data.model.Category import com.wbrawner.budget.data.model.Transaction -@Database(entities = [(Transaction::class), (Category::class)], version = 2) -@TypeConverters(DateTypeConverter::class, TransactionTypeTypeConverter::class) +@Database(entities = [(Transaction::class), (Category::class)], version = 3) +@TypeConverters(DateTypeConverter::class) abstract class BudgetDatabase: RoomDatabase() { abstract fun transactionDao(): TransactionDao abstract fun categoryDao(): CategoryDao -} \ No newline at end of file +} diff --git a/app/src/main/java/com/wbrawner/budget/data/CategoryRepository.kt b/app/src/main/java/com/wbrawner/budget/data/CategoryRepository.kt index 51168f8..d521722 100644 --- a/app/src/main/java/com/wbrawner/budget/data/CategoryRepository.kt +++ b/app/src/main/java/com/wbrawner/budget/data/CategoryRepository.kt @@ -37,8 +37,8 @@ class CategoryRepository(private val dao: CategoryDao) { } - fun getCurrentBalance(id: Int): LiveData = dao.getBalanceForCategory(id) + fun getCurrentBalance(id: Int): LiveData = dao.getBalanceForCategory(id) fun getTransactions(id: Int): LiveData> = dao.getTransactions(id) -} \ No newline at end of file +} diff --git a/app/src/main/java/com/wbrawner/budget/data/TransactionRepository.kt b/app/src/main/java/com/wbrawner/budget/data/TransactionRepository.kt index 8691d7a..f6440d3 100644 --- a/app/src/main/java/com/wbrawner/budget/data/TransactionRepository.kt +++ b/app/src/main/java/com/wbrawner/budget/data/TransactionRepository.kt @@ -17,8 +17,8 @@ class TransactionRepository(private val dao: TransactionDao) { handler = Handler(thread.looper) } - fun getTransactionsByType(count: Int, type: TransactionType): LiveData> = - dao.loadMultipleByType(count, type) +// fun getTransactionsByType(count: Int, type: TransactionType): LiveData> = +// dao.loadMultipleByType(count, type) fun getTransactions(count: Int): LiveData> = dao.loadMultiple(count) @@ -41,7 +41,7 @@ class TransactionRepository(private val dao: TransactionDao) { } - fun getCurrentBalance(): LiveData = dao.getBalance() + fun getCurrentBalance(): LiveData = dao.getBalance() fun getCategories(): LiveData> = dao.loadCategories() -} \ No newline at end of file +} diff --git a/app/src/main/java/com/wbrawner/budget/data/TransactionType.kt b/app/src/main/java/com/wbrawner/budget/data/TransactionType.kt deleted file mode 100644 index ccc543b..0000000 --- a/app/src/main/java/com/wbrawner/budget/data/TransactionType.kt +++ /dev/null @@ -1,29 +0,0 @@ -package com.wbrawner.budget.data - -import android.support.annotation.ColorRes -import android.support.annotation.StringRes -import com.wbrawner.budget.R -import java.io.Serializable - -enum class TransactionType( - @StringRes val title: Int, - @StringRes val addTitle: Int, - @StringRes val editTitle: Int, - @StringRes val noDataText: Int, - @ColorRes val textColor: Int -) : Serializable { - INCOME( - R.string.title_income, - R.string.title_add_income, - R.string.title_edit_income, - R.string.income_no_data, - R.color.colorTextGreen - ), - EXPENSE( - R.string.title_expenses, - R.string.title_add_expense, - R.string.title_edit_expense, - R.string.expenses_no_data, - R.color.colorTextRed - ); -} diff --git a/app/src/main/java/com/wbrawner/budget/data/TypeConverters.kt b/app/src/main/java/com/wbrawner/budget/data/TypeConverters.kt index 603d6bf..f7c33f5 100644 --- a/app/src/main/java/com/wbrawner/budget/data/TypeConverters.kt +++ b/app/src/main/java/com/wbrawner/budget/data/TypeConverters.kt @@ -4,14 +4,6 @@ import android.arch.persistence.room.TypeConverter import java.text.SimpleDateFormat import java.util.* -class TransactionTypeTypeConverter { - @android.arch.persistence.room.TypeConverter - fun toTransactionType(value: String): TransactionType? = TransactionType.valueOf(value) - - @android.arch.persistence.room.TypeConverter - fun toString(type: TransactionType?): String? = type?.name -} - class DateTypeConverter { @android.arch.persistence.room.TypeConverter fun toDate(value: String): Date? = dateFormat.parse(value) diff --git a/app/src/main/java/com/wbrawner/budget/data/dao/CategoryDao.kt b/app/src/main/java/com/wbrawner/budget/data/dao/CategoryDao.kt index e1617c0..e5ad742 100644 --- a/app/src/main/java/com/wbrawner/budget/data/dao/CategoryDao.kt +++ b/app/src/main/java/com/wbrawner/budget/data/dao/CategoryDao.kt @@ -21,9 +21,9 @@ interface CategoryDao { fun loadMultiple(): LiveData> @Query("SELECT " + - "(SELECT TOTAL(amount) from `Transaction` WHERE type = 'INCOME' AND categoryId = :categoryId) " + - "- (SELECT TOTAL(amount) from `Transaction` WHERE type = 'EXPENSE' AND categoryId = :categoryId)") - fun getBalanceForCategory(categoryId: Int): LiveData + "(SELECT TOTAL(amount) from `Transaction` WHERE isExpense = 0 AND categoryId = :categoryId) " + + "- (SELECT TOTAL(amount) from `Transaction` WHERE isExpense = 1 AND categoryId = :categoryId)") + fun getBalanceForCategory(categoryId: Int): LiveData @Delete fun delete(category: Category) @@ -34,4 +34,4 @@ interface CategoryDao { @Query("SELECT * FROM `Transaction` WHERE categoryId = :id") fun getTransactions(id: Int): LiveData> -} \ No newline at end of file +} diff --git a/app/src/main/java/com/wbrawner/budget/data/dao/TransactionDao.kt b/app/src/main/java/com/wbrawner/budget/data/dao/TransactionDao.kt index 4f20470..5c6de25 100644 --- a/app/src/main/java/com/wbrawner/budget/data/dao/TransactionDao.kt +++ b/app/src/main/java/com/wbrawner/budget/data/dao/TransactionDao.kt @@ -8,7 +8,6 @@ import android.arch.persistence.room.OnConflictStrategy.REPLACE import android.arch.persistence.room.Query import com.wbrawner.budget.data.model.Transaction import com.wbrawner.budget.data.model.TransactionCategory -import com.wbrawner.budget.data.TransactionType import com.wbrawner.budget.data.model.TransactionWithCategory @Dao @@ -22,11 +21,8 @@ interface TransactionDao { @Query("SELECT * FROM `Transaction` LIMIT :count") fun loadMultiple(count: Int): LiveData> - @Query("SELECT * FROM `Transaction` WHERE type = :type LIMIT :count") - fun loadMultipleByType(count: Int, type: TransactionType): LiveData> - - @Query("SELECT (SELECT TOTAL(amount) from `Transaction` WHERE type = 'INCOME') - (SELECT TOTAL(amount) from `Transaction` WHERE type = 'EXPENSE')") - fun getBalance(): LiveData + @Query("SELECT (SELECT TOTAL(amount) from `Transaction` WHERE isExpense = 0) - (SELECT TOTAL(amount) from `Transaction` WHERE isExpense = 1)") + fun getBalance(): LiveData @Delete fun delete(transaction: Transaction) @@ -36,4 +32,4 @@ interface TransactionDao { @Query("SELECT id,name from `Category`") fun loadCategories(): LiveData> -} \ No newline at end of file +} diff --git a/app/src/main/java/com/wbrawner/budget/data/migrations/MIGRATION_1_2.kt b/app/src/main/java/com/wbrawner/budget/data/migrations/MIGRATION_1_2.kt index ac73356..ee3c193 100644 --- a/app/src/main/java/com/wbrawner/budget/data/migrations/MIGRATION_1_2.kt +++ b/app/src/main/java/com/wbrawner/budget/data/migrations/MIGRATION_1_2.kt @@ -5,9 +5,8 @@ import android.arch.persistence.room.migration.Migration class MIGRATION_1_2: Migration(1, 2) { override fun migrate(database: SupportSQLiteDatabase) { - database.execSQL("CREATE TABLE `Category` (`id` INTEGER, `name` TEXT, `amount` REAL, " + - "`repeat` TEXT, `color` INTEGER PRIMARY KEY (`id`))") - database.execSQL("ALTER TABLE `Transaction` ADD COLUMN categoryId") + database.execSQL("CREATE TABLE `Category` (`id` INTEGER, `name` TEXT NOT NULL, `amount` REAL NOT NULL, `repeat` TEXT, `color` INTEGER NOT NULL DEFAULT 0, PRIMARY KEY (`id`))") + database.execSQL("ALTER TABLE `Transaction` ADD COLUMN categoryId INTEGER") } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/wbrawner/budget/data/migrations/MIGRATION_2_3.kt b/app/src/main/java/com/wbrawner/budget/data/migrations/MIGRATION_2_3.kt new file mode 100644 index 0000000..bb32f25 --- /dev/null +++ b/app/src/main/java/com/wbrawner/budget/data/migrations/MIGRATION_2_3.kt @@ -0,0 +1,20 @@ +package com.wbrawner.budget.data.migrations + +import android.arch.persistence.db.SupportSQLiteDatabase +import android.arch.persistence.room.migration.Migration + +class MIGRATION_2_3: Migration(2, 3) { + override fun migrate(database: SupportSQLiteDatabase) { + database.execSQL("ALTER TABLE `Transaction` RENAME TO `TransactionOld`") + database.execSQL("CREATE TABLE `Transaction` (`id` INTEGER,`remoteId` TEXT,`name` TEXT NOT NULL,`date` TEXT NOT NULL, `description` TEXT NOT NULL, `amount` INTEGER NOT NULL,`isExpense` INTEGER NOT NULL DEFAULT 1,`categoryId` INTEGER,PRIMARY KEY (`id`))") + database.execSQL("INSERT INTO `Transaction` ( id, name, date, description, amount, categoryId ) SELECT id,title,date,description,amount * 100,categoryId FROM `TransactionOld`") + database.execSQL("UPDATE `Transaction` SET isExpense = 1 WHERE id IN (SELECT id FROM `TransactionOld` WHERE `TransactionOld`.type = 'EXPENSE')") + database.execSQL("UPDATE `Transaction` SET isExpense = 0 WHERE id IN (SELECT id FROM `TransactionOld` WHERE `TransactionOld`.type = 'INCOME')") + database.execSQL("DROP TABLE `TransactionOld`") + + database.execSQL("ALTER TABLE `Category` RENAME TO `CategoryOld`") + database.execSQL("CREATE TABLE `Category` (`id` INTEGER,`remoteId` TEXT,`name` TEXT NOT NULL, `amount` INTEGER NOT NULL, `repeat` TEXT, `color` INTEGER NOT NULL DEFAULT 0,PRIMARY KEY (`id`))") + database.execSQL("INSERT INTO `Category` ( id, name, amount, repeat, color ) SELECT id,name,amount * 100,repeat,color FROM `CategoryOld`") + database.execSQL("DROP TABLE `CategoryOld`") + } +} diff --git a/app/src/main/java/com/wbrawner/budget/data/model/Category.kt b/app/src/main/java/com/wbrawner/budget/data/model/Category.kt index 40cb2f2..87c0b5a 100644 --- a/app/src/main/java/com/wbrawner/budget/data/model/Category.kt +++ b/app/src/main/java/com/wbrawner/budget/data/model/Category.kt @@ -8,8 +8,9 @@ import android.support.annotation.ColorInt class Category( @PrimaryKey val id: Int?, + val remoteId: String?, val name: String, - val amount: Double, + val amount: Int, val repeat: String?, @ColorInt val color: Int -) \ No newline at end of file +) diff --git a/app/src/main/java/com/wbrawner/budget/data/model/Transaction.kt b/app/src/main/java/com/wbrawner/budget/data/model/Transaction.kt index b62a19a..a0e7fca 100644 --- a/app/src/main/java/com/wbrawner/budget/data/model/Transaction.kt +++ b/app/src/main/java/com/wbrawner/budget/data/model/Transaction.kt @@ -2,17 +2,17 @@ package com.wbrawner.budget.data.model import android.arch.persistence.room.Entity import android.arch.persistence.room.PrimaryKey -import com.wbrawner.budget.data.TransactionType import java.util.* @Entity class Transaction( @PrimaryKey val id: Int?, - val title: String, + val remoteId: String?, + val name: String, val date: Date, val description: String, - val amount: Double, + val amount: Int, val categoryId: Int?, - val type: TransactionType -) \ No newline at end of file + val isExpense: Boolean +) diff --git a/app/src/main/java/com/wbrawner/budget/transactions/TransactionListActivity.kt b/app/src/main/java/com/wbrawner/budget/ui/MainActivity.kt similarity index 65% rename from app/src/main/java/com/wbrawner/budget/transactions/TransactionListActivity.kt rename to app/src/main/java/com/wbrawner/budget/ui/MainActivity.kt index f25d21f..09b368b 100644 --- a/app/src/main/java/com/wbrawner/budget/transactions/TransactionListActivity.kt +++ b/app/src/main/java/com/wbrawner/budget/ui/MainActivity.kt @@ -1,4 +1,4 @@ -package com.wbrawner.budget.transactions +package com.wbrawner.budget.ui import android.os.Bundle import android.support.annotation.StringRes @@ -6,12 +6,12 @@ import android.support.text.emoji.EmojiCompat import android.support.text.emoji.bundled.BundledEmojiCompatConfig import android.support.v7.app.AppCompatActivity import com.wbrawner.budget.R -import com.wbrawner.budget.categories.CategoryListFragment -import com.wbrawner.budget.data.TransactionType -import com.wbrawner.budget.overview.OverviewFragment +import com.wbrawner.budget.ui.categories.CategoryListFragment +import com.wbrawner.budget.ui.overview.OverviewFragment +import com.wbrawner.budget.ui.transactions.TransactionListFragment import kotlinx.android.synthetic.main.activity_transaction_list.* -class TransactionListActivity : AppCompatActivity() { +class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) EmojiCompat.init(BundledEmojiCompatConfig(this)) @@ -20,9 +20,14 @@ class TransactionListActivity : AppCompatActivity() { menu_main.setOnNavigationItemSelectedListener { item -> when (item.itemId) { - R.id.action_expenses -> updateFragment(TransactionType.EXPENSE) - R.id.action_income -> updateFragment(TransactionType.INCOME) - R.id.action_categories -> updateFragment(CategoryListFragment.TAG_FRAGMENT, CategoryListFragment.TITLE_FRAGMENT) + R.id.action_transactions -> updateFragment( + TransactionListFragment.TAG_FRAGMENT, + TransactionListFragment.TITLE_FRAGMENT + ) + R.id.action_categories -> updateFragment( + CategoryListFragment.TAG_FRAGMENT, + CategoryListFragment.TITLE_FRAGMENT + ) else -> updateFragment(OverviewFragment.TAG_FRAGMENT, OverviewFragment.TITLE_FRAGMENT) } @@ -31,10 +36,6 @@ class TransactionListActivity : AppCompatActivity() { menu_main.selectedItemId = R.id.action_overview } - private fun updateFragment(type: TransactionType) { - updateFragment(type.name, type.title) - } - private fun updateFragment(tag: String, @StringRes title: Int) { setTitle(title) var fragment = supportFragmentManager.findFragmentByTag(tag) @@ -44,11 +45,7 @@ class TransactionListActivity : AppCompatActivity() { OverviewFragment.TAG_FRAGMENT -> OverviewFragment() CategoryListFragment.TAG_FRAGMENT -> CategoryListFragment() else -> { - TransactionListFragment().apply { - arguments = Bundle().apply { - putSerializable(TransactionListFragment.ARG_TYPE, TransactionType.valueOf(tag)) - } - } + TransactionListFragment() } } ft.add(R.id.content_container, fragment, tag) diff --git a/app/src/main/java/com/wbrawner/budget/categories/AddEditCategoryActivity.kt b/app/src/main/java/com/wbrawner/budget/ui/categories/AddEditCategoryActivity.kt similarity index 93% rename from app/src/main/java/com/wbrawner/budget/categories/AddEditCategoryActivity.kt rename to app/src/main/java/com/wbrawner/budget/ui/categories/AddEditCategoryActivity.kt index 29cf14e..0bb26c6 100644 --- a/app/src/main/java/com/wbrawner/budget/categories/AddEditCategoryActivity.kt +++ b/app/src/main/java/com/wbrawner/budget/ui/categories/AddEditCategoryActivity.kt @@ -1,4 +1,4 @@ -package com.wbrawner.budget.categories +package com.wbrawner.budget.ui.categories import android.arch.lifecycle.Observer import android.arch.lifecycle.ViewModelProviders @@ -7,6 +7,7 @@ import android.os.Bundle import android.support.v7.app.AppCompatActivity import android.view.Menu import android.view.MenuItem +import android.view.View import com.wbrawner.budget.R import com.wbrawner.budget.data.model.Category import kotlinx.android.synthetic.main.activity_add_edit_category.* @@ -28,6 +29,7 @@ class AddEditCategoryActivity : AppCompatActivity() { return } + viewModel.getCategory(intent!!.extras!!.getInt(EXTRA_CATEGORY_ID)) .observe(this, Observer { category -> if (category == null) { @@ -38,7 +40,7 @@ class AddEditCategoryActivity : AppCompatActivity() { setTitle(R.string.title_edit_category) menu?.findItem(R.id.action_delete)?.isVisible = true edit_category_name.setText(category.name) - edit_category_amount.setText(String.format("%.02f", category.amount)) + edit_category_amount.setText(String.format("%.02f", category.amount / 100.0f)) }) } @@ -58,8 +60,9 @@ class AddEditCategoryActivity : AppCompatActivity() { if (!validateFields()) return true viewModel.saveCategory(Category( id = id, + remoteId = null, name = edit_category_name.text.toString(), - amount = edit_category_amount.text.toString().toDouble(), + amount = edit_category_amount.rawValue.toInt(), color = Color.parseColor("#FF0000"), repeat = "never" )) diff --git a/app/src/main/java/com/wbrawner/budget/categories/CategoryAdapter.kt b/app/src/main/java/com/wbrawner/budget/ui/categories/CategoryAdapter.kt similarity index 80% rename from app/src/main/java/com/wbrawner/budget/categories/CategoryAdapter.kt rename to app/src/main/java/com/wbrawner/budget/ui/categories/CategoryAdapter.kt index 07d8005..33b8e8a 100644 --- a/app/src/main/java/com/wbrawner/budget/categories/CategoryAdapter.kt +++ b/app/src/main/java/com/wbrawner/budget/ui/categories/CategoryAdapter.kt @@ -1,4 +1,4 @@ -package com.wbrawner.budget.categories +package com.wbrawner.budget.ui.categories import android.arch.lifecycle.LifecycleOwner import android.arch.lifecycle.Observer @@ -11,7 +11,7 @@ import android.view.ViewGroup import android.widget.ProgressBar import android.widget.TextView import com.wbrawner.budget.R -import com.wbrawner.budget.categories.AddEditCategoryActivity.Companion.EXTRA_CATEGORY_ID +import com.wbrawner.budget.ui.categories.AddEditCategoryActivity.Companion.EXTRA_CATEGORY_ID import com.wbrawner.budget.data.model.Category class CategoryAdapter( @@ -30,18 +30,22 @@ class CategoryAdapter( override fun onBindViewHolder(holder: ViewHolder, position: Int) { val category = data[position] holder.title?.text = category.name - holder.amount?.text = String.format("${'$'}%.02f", category.amount) + holder.amount?.text = String.format("${'$'}%.02f", category.amount / 100.0f) viewModel.getCurrentBalance(category.id!!) - .observe(lifecycleOwner, Observer { balance -> + .observe(lifecycleOwner, Observer { balance -> holder.progress?.isIndeterminate = false if (balance == null) { holder.progress?.progress = 0 } else { - holder.progress?.max = category.amount.toInt() + holder.progress?.max = category.amount holder.progress?.setProgress( - Math.abs(balance).toInt(), + -1 * balance, true ) + holder.amount?.text = holder.itemView.context.getString( + R.string.balance_remaning, + (category.amount + balance) / 100.0f + ) } }) holder.itemView.setOnClickListener { diff --git a/app/src/main/java/com/wbrawner/budget/categories/CategoryListFragment.kt b/app/src/main/java/com/wbrawner/budget/ui/categories/CategoryListFragment.kt similarity index 95% rename from app/src/main/java/com/wbrawner/budget/categories/CategoryListFragment.kt rename to app/src/main/java/com/wbrawner/budget/ui/categories/CategoryListFragment.kt index 0878b4e..b4557c8 100644 --- a/app/src/main/java/com/wbrawner/budget/categories/CategoryListFragment.kt +++ b/app/src/main/java/com/wbrawner/budget/ui/categories/CategoryListFragment.kt @@ -1,4 +1,4 @@ -package com.wbrawner.budget.categories +package com.wbrawner.budget.ui.categories import android.arch.lifecycle.Observer import android.arch.lifecycle.ViewModelProviders @@ -41,7 +41,7 @@ class CategoryListFragment : Fragment() { val noDataView = view.findViewById(R.id.transaction_list_no_data) if (data == null || data.isEmpty()) { recyclerView.adapter = null - noDataView?.setText("No data FIX ME") + noDataView?.setText(R.string.categories_no_data) recyclerView?.visibility = View.GONE noDataView?.visibility = View.VISIBLE } else { diff --git a/app/src/main/java/com/wbrawner/budget/categories/CategoryViewModel.kt b/app/src/main/java/com/wbrawner/budget/ui/categories/CategoryViewModel.kt similarity index 95% rename from app/src/main/java/com/wbrawner/budget/categories/CategoryViewModel.kt rename to app/src/main/java/com/wbrawner/budget/ui/categories/CategoryViewModel.kt index 3f351b7..eadb54e 100644 --- a/app/src/main/java/com/wbrawner/budget/categories/CategoryViewModel.kt +++ b/app/src/main/java/com/wbrawner/budget/ui/categories/CategoryViewModel.kt @@ -1,4 +1,4 @@ -package com.wbrawner.budget.categories +package com.wbrawner.budget.ui.categories import android.app.Application import android.arch.lifecycle.AndroidViewModel @@ -23,4 +23,4 @@ class CategoryViewModel(application: Application): AndroidViewModel(application) fun getCurrentBalance(id: Int) = categoryRepo.getCurrentBalance(id) fun getTransactions(id: Int) = categoryRepo.getTransactions(id) -} \ No newline at end of file +} diff --git a/app/src/main/java/com/wbrawner/budget/overview/OverviewFragment.kt b/app/src/main/java/com/wbrawner/budget/ui/overview/OverviewFragment.kt similarity index 87% rename from app/src/main/java/com/wbrawner/budget/overview/OverviewFragment.kt rename to app/src/main/java/com/wbrawner/budget/ui/overview/OverviewFragment.kt index 19f5f3d..9aad43f 100644 --- a/app/src/main/java/com/wbrawner/budget/overview/OverviewFragment.kt +++ b/app/src/main/java/com/wbrawner/budget/ui/overview/OverviewFragment.kt @@ -1,4 +1,4 @@ -package com.wbrawner.budget.overview +package com.wbrawner.budget.ui.overview import android.arch.lifecycle.Observer import android.arch.lifecycle.ViewModelProviders @@ -9,7 +9,7 @@ import android.view.View import android.view.ViewGroup import android.widget.TextView import com.wbrawner.budget.R -import com.wbrawner.budget.transactions.TransactionViewModel +import com.wbrawner.budget.ui.transactions.TransactionViewModel class OverviewFragment : Fragment() { lateinit var viewModel: TransactionViewModel @@ -32,15 +32,15 @@ class OverviewFragment : Fragment() { } viewModel.getCurrentBalance().observe(this, Observer { balance -> - val safeBalance: Double = balance?: 0.0 + val safeBalance: Int = balance?: 0 val balanceView = view.findViewById(R.id.overview_current_balance) val color = when { - safeBalance > 0.0 -> R.color.colorTextGreen - safeBalance == 0.0 -> R.color.colorTextPrimary + safeBalance > 0 -> R.color.colorTextGreen + safeBalance == 0 -> R.color.colorTextPrimary else -> R.color.colorTextRed } balanceView.setTextColor(resources.getColor(color, activity!!.theme)) - balanceView.text = String.format("${'$'}%.02f", safeBalance) + balanceView.text = String.format("${'$'}%.02f", safeBalance / 100.0f) }) showData(view, true) }) diff --git a/app/src/main/java/com/wbrawner/budget/transactions/AddEditTransactionActivity.kt b/app/src/main/java/com/wbrawner/budget/ui/transactions/AddEditTransactionActivity.kt similarity index 83% rename from app/src/main/java/com/wbrawner/budget/transactions/AddEditTransactionActivity.kt rename to app/src/main/java/com/wbrawner/budget/ui/transactions/AddEditTransactionActivity.kt index 4ad04b0..e6c2887 100644 --- a/app/src/main/java/com/wbrawner/budget/transactions/AddEditTransactionActivity.kt +++ b/app/src/main/java/com/wbrawner/budget/ui/transactions/AddEditTransactionActivity.kt @@ -1,4 +1,4 @@ -package com.wbrawner.budget.transactions +package com.wbrawner.budget.ui.transactions import android.arch.lifecycle.Observer import android.arch.lifecycle.ViewModelProviders @@ -10,14 +10,12 @@ import android.widget.ArrayAdapter import com.wbrawner.budget.R import com.wbrawner.budget.data.model.Transaction import com.wbrawner.budget.data.model.TransactionCategory -import com.wbrawner.budget.data.TransactionType import com.wbrawner.budget.data.model.TransactionWithCategory import kotlinx.android.synthetic.main.activity_add_edit_transaction.* import java.util.* class AddEditTransactionActivity : AppCompatActivity() { lateinit var viewModel: TransactionViewModel - lateinit var type: TransactionType var id: Int? = null var date: Date = Date() var menu: Menu? = null @@ -27,6 +25,8 @@ class AddEditTransactionActivity : AppCompatActivity() { setContentView(R.layout.activity_add_edit_transaction) setSupportActionBar(action_bar) supportActionBar?.setDisplayHomeAsUpEnabled(true) + setTitle(R.string.title_add_transaction) + edit_transaction_type_expense.isChecked = true viewModel = ViewModelProviders.of(this).get(TransactionViewModel::class.java) viewModel.getCategories() .observe(this, Observer> { categories -> @@ -44,13 +44,8 @@ class AddEditTransactionActivity : AppCompatActivity() { adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) edit_transaction_category.adapter = adapter }) - if (intent?.hasExtra(EXTRA_TYPE) == true) { - type = TransactionType.valueOf(intent?.extras?.getString(EXTRA_TYPE, "EXPENSE") - ?: "EXPENSE") - setTitle(type.addTitle) - return - } else if (intent?.hasExtra(EXTRA_TRANSACTION_ID) != true) { - finish() + + if (intent?.hasExtra(EXTRA_TRANSACTION_ID) != true) { return } @@ -62,12 +57,15 @@ class AddEditTransactionActivity : AppCompatActivity() { } val transaction = transactionWithCategory.transaction id = transaction.id - type = transaction.type - setTitle(type.editTitle) menu?.findItem(R.id.action_delete)?.isVisible = true - edit_transaction_title.setText(transaction.title) + edit_transaction_title.setText(transaction.name) edit_transaction_description.setText(transaction.description) - edit_transaction_amount.setText(String.format("%.02f", transaction.amount)) + edit_transaction_amount.setText(String.format("%.02f", transaction.amount / 100.0f)) + if (transaction.isExpense) { + edit_transaction_type_expense.isChecked = true + } else { + edit_transaction_type_income.isChecked = true + } val field = Calendar.getInstance() field.time = transaction.date val year = field.get(Calendar.YEAR) @@ -105,12 +103,13 @@ class AddEditTransactionActivity : AppCompatActivity() { viewModel.saveTransaction(Transaction( id = id, - title = edit_transaction_title.text.toString(), + name = edit_transaction_title.text.toString(), date = cal.time, description = edit_transaction_description.text.toString(), - amount = edit_transaction_amount.text.toString().toDouble(), - type = type, - categoryId = (edit_transaction_category.selectedItem as TransactionCategory).id + amount = edit_transaction_amount.rawValue.toInt(), + isExpense = edit_transaction_type_expense.isChecked, + categoryId = (edit_transaction_category.selectedItem as TransactionCategory).id, + remoteId = null )) finish() } @@ -124,7 +123,6 @@ class AddEditTransactionActivity : AppCompatActivity() { companion object { - const val EXTRA_TYPE = "EXTRA_TRANSACTION_TYPE" const val EXTRA_TRANSACTION_ID = "EXTRA_TRANSACTION_ID" } } diff --git a/app/src/main/java/com/wbrawner/budget/transactions/TransactionAdapter.kt b/app/src/main/java/com/wbrawner/budget/ui/transactions/TransactionAdapter.kt similarity index 85% rename from app/src/main/java/com/wbrawner/budget/transactions/TransactionAdapter.kt rename to app/src/main/java/com/wbrawner/budget/ui/transactions/TransactionAdapter.kt index 6c05a20..b3d18ef 100644 --- a/app/src/main/java/com/wbrawner/budget/transactions/TransactionAdapter.kt +++ b/app/src/main/java/com/wbrawner/budget/ui/transactions/TransactionAdapter.kt @@ -1,4 +1,4 @@ -package com.wbrawner.budget.transactions +package com.wbrawner.budget.ui.transactions import android.content.Intent import android.support.v4.content.ContextCompat.startActivity @@ -8,7 +8,7 @@ import android.view.View import android.view.ViewGroup import android.widget.TextView import com.wbrawner.budget.R -import com.wbrawner.budget.transactions.AddEditTransactionActivity.Companion.EXTRA_TRANSACTION_ID +import com.wbrawner.budget.ui.transactions.AddEditTransactionActivity.Companion.EXTRA_TRANSACTION_ID import com.wbrawner.budget.data.model.Transaction import com.wbrawner.budget.data.model.TransactionWithCategory import java.text.SimpleDateFormat @@ -29,13 +29,12 @@ class TransactionAdapter() : RecyclerView.Adapter val transaction: Transaction = if (listType == TransactionWithCategory::class.java) (data[position] as TransactionWithCategory).transaction else data[position] as Transaction - holder.title.text = transaction.title + holder.title.text = transaction.name holder.date.text = SimpleDateFormat.getDateInstance(SimpleDateFormat.SHORT).format(transaction.date) - holder.amount.text = String.format("${'$'}%.02f", transaction.amount) + holder.amount.text = String.format("${'$'}%.02f", transaction.amount / 100.0f) val context = holder.itemView.context - holder.amount.setTextColor( - context.resources.getColor(transaction.type.textColor, context.theme) - ) + val color = if (transaction.isExpense) R.color.colorTextRed else R.color.colorTextGreen + holder.amount.setTextColor(context.resources.getColor(color, context.theme)) holder.itemView.setOnClickListener { startActivity( it.context.applicationContext, @@ -62,4 +61,4 @@ class TransactionAdapter() : RecyclerView.Adapter val date = itemView.findViewById(R.id.transaction_date) val amount = itemView.findViewById(R.id.transaction_amount) } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/wbrawner/budget/transactions/TransactionListFragment.kt b/app/src/main/java/com/wbrawner/budget/ui/transactions/TransactionListFragment.kt similarity index 80% rename from app/src/main/java/com/wbrawner/budget/transactions/TransactionListFragment.kt rename to app/src/main/java/com/wbrawner/budget/ui/transactions/TransactionListFragment.kt index 555d6e4..813bbff 100644 --- a/app/src/main/java/com/wbrawner/budget/transactions/TransactionListFragment.kt +++ b/app/src/main/java/com/wbrawner/budget/ui/transactions/TransactionListFragment.kt @@ -1,4 +1,4 @@ -package com.wbrawner.budget.transactions +package com.wbrawner.budget.ui.transactions import android.arch.lifecycle.Observer import android.arch.lifecycle.ViewModelProviders @@ -13,13 +13,10 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import com.wbrawner.budget.R -import com.wbrawner.budget.transactions.AddEditTransactionActivity.Companion.EXTRA_TYPE -import com.wbrawner.budget.data.TransactionType import com.wbrawner.budget.data.model.TransactionWithCategory class TransactionListFragment : Fragment() { lateinit var viewModel: TransactionViewModel - lateinit var type: TransactionType override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -31,8 +28,6 @@ class TransactionListFragment : Fragment() { return } - type = arguments?.getSerializable(ARG_TYPE) as? TransactionType ?: TransactionType.EXPENSE - viewModel = ViewModelProviders.of(activity!!).get(TransactionViewModel::class.java) } @@ -41,12 +36,12 @@ class TransactionListFragment : Fragment() { val recyclerView = view.findViewById(R.id.list_transactions) val fab = view.findViewById(R.id.fab_add_transaction) recyclerView.layoutManager = LinearLayoutManager(activity) - viewModel.getTransactionsByType(20, type) + viewModel.getTransactions(20) .observe(this, Observer> { data -> val noDataView = view.findViewById(R.id.transaction_list_no_data) if (data == null || data.isEmpty()) { recyclerView.adapter = null - noDataView?.setText(type.noDataText) + noDataView?.setText(R.string.transactions_no_data) recyclerView?.visibility = View.GONE noDataView?.visibility = View.VISIBLE } else { @@ -62,9 +57,7 @@ class TransactionListFragment : Fragment() { }) fab.setOnClickListener { startActivity( - Intent(activity, AddEditTransactionActivity::class.java).apply { - this.putExtra(EXTRA_TYPE, this@TransactionListFragment.type.name) - } + Intent(activity, AddEditTransactionActivity::class.java) ) } @@ -72,6 +65,7 @@ class TransactionListFragment : Fragment() { } companion object { - const val ARG_TYPE = "TRANSACTION_TYPE" + const val TAG_FRAGMENT = "transactions" + const val TITLE_FRAGMENT = R.string.title_transactions } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/wbrawner/budget/transactions/TransactionViewModel.kt b/app/src/main/java/com/wbrawner/budget/ui/transactions/TransactionViewModel.kt similarity index 79% rename from app/src/main/java/com/wbrawner/budget/transactions/TransactionViewModel.kt rename to app/src/main/java/com/wbrawner/budget/ui/transactions/TransactionViewModel.kt index ea1dcb5..6569016 100644 --- a/app/src/main/java/com/wbrawner/budget/transactions/TransactionViewModel.kt +++ b/app/src/main/java/com/wbrawner/budget/ui/transactions/TransactionViewModel.kt @@ -1,4 +1,4 @@ -package com.wbrawner.budget.transactions +package com.wbrawner.budget.ui.transactions import android.app.Application import android.arch.lifecycle.AndroidViewModel @@ -16,10 +16,10 @@ class TransactionViewModel(application: Application): AndroidViewModel(applicati fun getTransactions(count: Int): LiveData> = transactionRepo.getTransactions(count) - fun getTransactionsByType(count: Int, type: TransactionType): LiveData> - = transactionRepo.getTransactionsByType(count, type) +// fun getTransactionsByType(count: Int, type: TransactionType): LiveData> +// = transactionRepo.getTransactionsByType(count, type) - fun getCurrentBalance(): LiveData = transactionRepo.getCurrentBalance() + fun getCurrentBalance(): LiveData = transactionRepo.getCurrentBalance() fun getCategories(): LiveData> = transactionRepo.getCategories() @@ -28,4 +28,4 @@ class TransactionViewModel(application: Application): AndroidViewModel(applicati fun deleteTransaction(transaction: Transaction) = transactionRepo.delete(transaction) fun deleteTransactionById(id: Int) = transactionRepo.deleteById(id) -} \ No newline at end of file +} diff --git a/app/src/main/res/layout/activity_add_edit_category.xml b/app/src/main/res/layout/activity_add_edit_category.xml index 3312118..314cc3b 100644 --- a/app/src/main/res/layout/activity_add_edit_category.xml +++ b/app/src/main/res/layout/activity_add_edit_category.xml @@ -1,6 +1,7 @@ @@ -51,10 +52,12 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/container_edit_category_name"> - + android:text="0.00" + android:inputType="number" + tools:ignore="HardcodedText" /> diff --git a/app/src/main/res/layout/activity_add_edit_transaction.xml b/app/src/main/res/layout/activity_add_edit_transaction.xml index 1f4a08a..b798785 100644 --- a/app/src/main/res/layout/activity_add_edit_transaction.xml +++ b/app/src/main/res/layout/activity_add_edit_transaction.xml @@ -31,7 +31,6 @@ android:id="@+id/container_edit_transaction_title" style="@style/AppTheme.EditText.Container" android:hint="@string/prompt_transaction_title" - app:layout_constraintBottom_toTopOf="@+id/container_edit_transaction_description" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent"> @@ -46,7 +45,6 @@ android:id="@+id/container_edit_transaction_description" style="@style/AppTheme.EditText.Container" android:hint="@string/prompt_transaction_description" - app:layout_constraintBottom_toTopOf="@+id/container_edit_transaction_amount" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/container_edit_transaction_title"> @@ -62,17 +60,36 @@ android:id="@+id/container_edit_transaction_amount" style="@style/AppTheme.EditText.Container" android:hint="@string/prompt_transaction_amount" - app:layout_constraintBottom_toTopOf="@+id/container_edit_transaction_date" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/container_edit_transaction_description"> - + + + + + + app:layout_constraintTop_toBottomOf="@+id/container_edit_transaction_type" /> @@ -100,7 +115,6 @@ android:layout_height="wrap_content" android:layout_marginStart="4dp" android:text="@string/prompt_transaction_category" - app:layout_constraintBottom_toTopOf="@+id/edit_transaction_category" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/edit_transaction_date" /> @@ -109,7 +123,6 @@ android:id="@+id/edit_transaction_category" android:layout_width="match_parent" android:layout_height="wrap_content" - app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/container_edit_transaction_category" /> diff --git a/app/src/main/res/layout/activity_transaction_list.xml b/app/src/main/res/layout/activity_transaction_list.xml index 1d6b5ef..e5fd6e8 100644 --- a/app/src/main/res/layout/activity_transaction_list.xml +++ b/app/src/main/res/layout/activity_transaction_list.xml @@ -4,7 +4,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - tools:context="com.wbrawner.budget.transactions.TransactionListActivity"> + tools:context=".ui.MainActivity"> - \ No newline at end of file + diff --git a/app/src/main/res/layout/list_item_category.xml b/app/src/main/res/layout/list_item_category.xml index 6f2d1c5..6ea9039 100644 --- a/app/src/main/res/layout/list_item_category.xml +++ b/app/src/main/res/layout/list_item_category.xml @@ -22,7 +22,7 @@ android:id="@+id/category_amount" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:textSize="18sp" + style="?android:attr/textAppearanceSmall" app:layout_constraintHorizontal_chainStyle="spread_inside" app:layout_constraintBottom_toTopOf="@id/barrier" app:layout_constraintStart_toEndOf="@+id/category_title" diff --git a/app/src/main/res/menu/main_navigation.xml b/app/src/main/res/menu/main_navigation.xml index c498d0c..6c29117 100644 --- a/app/src/main/res/menu/main_navigation.xml +++ b/app/src/main/res/menu/main_navigation.xml @@ -5,15 +5,11 @@ android:icon="@drawable/ic_baseline_dashboard_24dp" android:title="@string/title_dashboard" /> - + android:title="@string/title_transactions" /> - \ No newline at end of file + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 09ece57..adb630a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -2,23 +2,20 @@ My Allowance Allowance Title - Add Income - Add Expense Add Transaction Description Date Amount - Expenses - Income + Expense + Income Dashboard Current Balance 📈\nAdd some transactions to see an overview of your spending here Save Delete - Edit Income - Edit Expense - 🌳\nGet to work! Money doesn\'t grow on trees after all - 🤔\nAre you sure you haven\'t spent any money? + Edit Transaction + 🌳\nGet to work! Money doesn\'t grow on trees after all + 🤔\nAre you sure you haven\'t spent any money? Categories Edit Category Amount @@ -28,4 +25,6 @@ Category Name is a required field Amount is a required field + Transactions + \$%1$.02f remaining diff --git a/app/src/main/res/xml/shortcuts.xml b/app/src/main/res/xml/shortcuts.xml index 320c19b..443c583 100644 --- a/app/src/main/res/xml/shortcuts.xml +++ b/app/src/main/res/xml/shortcuts.xml @@ -2,33 +2,15 @@ - - - - - - + android:targetClass="com.wbrawner.budget.ui.transactions.AddEditTransactionActivity"> - \ No newline at end of file + diff --git a/build.gradle b/build.gradle index ff630b8..21459da 100644 --- a/build.gradle +++ b/build.gradle @@ -19,6 +19,7 @@ allprojects { repositories { google() jcenter() + maven { url "https://jitpack.io" } } }