Update database structure to match server

This commit is contained in:
William Brawner 2018-11-01 19:12:03 -06:00
parent 85a91d0af0
commit f3e456ac28
35 changed files with 474 additions and 209 deletions

View file

@ -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

View file

@ -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\")"
]
}
}

View file

@ -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\")"
]
}
}

View file

@ -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")));
}
}

View file

@ -10,7 +10,7 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name="com.wbrawner.budget.transactions.TransactionListActivity">
<activity android:name="com.wbrawner.budget.ui.MainActivity">
<intent-filter android:label="@string/app_name_short">
<action android:name="android.intent.action.MAIN" />
@ -20,8 +20,8 @@
android:name="android.app.shortcuts"
android:resource="@xml/shortcuts" />
</activity>
<activity android:name="com.wbrawner.budget.transactions.AddEditTransactionActivity" />
<activity android:name="com.wbrawner.budget.categories.AddEditCategoryActivity" />
<activity android:name="com.wbrawner.budget.ui.transactions.AddEditTransactionActivity" />
<activity android:name="com.wbrawner.budget.ui.categories.AddEditCategoryActivity" />
</application>
</manifest>
</manifest>

View file

@ -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()

View file

@ -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
}
}

View file

@ -37,8 +37,8 @@ class CategoryRepository(private val dao: CategoryDao) {
}
fun getCurrentBalance(id: Int): LiveData<Double> = dao.getBalanceForCategory(id)
fun getCurrentBalance(id: Int): LiveData<Int> = dao.getBalanceForCategory(id)
fun getTransactions(id: Int): LiveData<List<Transaction>> = dao.getTransactions(id)
}
}

View file

@ -17,8 +17,8 @@ class TransactionRepository(private val dao: TransactionDao) {
handler = Handler(thread.looper)
}
fun getTransactionsByType(count: Int, type: TransactionType): LiveData<List<TransactionWithCategory>> =
dao.loadMultipleByType(count, type)
// fun getTransactionsByType(count: Int, type: TransactionType): LiveData<List<TransactionWithCategory>> =
// dao.loadMultipleByType(count, type)
fun getTransactions(count: Int): LiveData<List<TransactionWithCategory>> = dao.loadMultiple(count)
@ -41,7 +41,7 @@ class TransactionRepository(private val dao: TransactionDao) {
}
fun getCurrentBalance(): LiveData<Double> = dao.getBalance()
fun getCurrentBalance(): LiveData<Int> = dao.getBalance()
fun getCategories(): LiveData<List<TransactionCategory>> = dao.loadCategories()
}
}

View file

@ -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
);
}

View file

@ -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)

View file

@ -21,9 +21,9 @@ interface CategoryDao {
fun loadMultiple(): LiveData<List<Category>>
@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<Double>
"(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<Int>
@Delete
fun delete(category: Category)
@ -34,4 +34,4 @@ interface CategoryDao {
@Query("SELECT * FROM `Transaction` WHERE categoryId = :id")
fun getTransactions(id: Int): LiveData<List<Transaction>>
}
}

View file

@ -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<List<TransactionWithCategory>>
@Query("SELECT * FROM `Transaction` WHERE type = :type LIMIT :count")
fun loadMultipleByType(count: Int, type: TransactionType): LiveData<List<TransactionWithCategory>>
@Query("SELECT (SELECT TOTAL(amount) from `Transaction` WHERE type = 'INCOME') - (SELECT TOTAL(amount) from `Transaction` WHERE type = 'EXPENSE')")
fun getBalance(): LiveData<Double>
@Query("SELECT (SELECT TOTAL(amount) from `Transaction` WHERE isExpense = 0) - (SELECT TOTAL(amount) from `Transaction` WHERE isExpense = 1)")
fun getBalance(): LiveData<Int>
@Delete
fun delete(transaction: Transaction)
@ -36,4 +32,4 @@ interface TransactionDao {
@Query("SELECT id,name from `Category`")
fun loadCategories(): LiveData<List<TransactionCategory>>
}
}

View file

@ -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")
}
}
}

View file

@ -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`")
}
}

View file

@ -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
)
)

View file

@ -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
)
val isExpense: Boolean
)

View file

@ -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)

View file

@ -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> { 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"
))

View file

@ -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<Double> { balance ->
.observe(lifecycleOwner, Observer<Int> { 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 {

View file

@ -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<EmojiTextView>(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 {

View file

@ -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)
}
}

View file

@ -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<TextView>(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)
})

View file

@ -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<List<TransactionCategory>> { 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"
}
}

View file

@ -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<TransactionAdapter.ViewHolder>
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<TransactionAdapter.ViewHolder>
val date = itemView.findViewById<TextView>(R.id.transaction_date)
val amount = itemView.findViewById<TextView>(R.id.transaction_amount)
}
}
}

View file

@ -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<RecyclerView>(R.id.list_transactions)
val fab = view.findViewById<FloatingActionButton>(R.id.fab_add_transaction)
recyclerView.layoutManager = LinearLayoutManager(activity)
viewModel.getTransactionsByType(20, type)
viewModel.getTransactions(20)
.observe(this, Observer<List<TransactionWithCategory>> { data ->
val noDataView = view.findViewById<EmojiTextView>(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
}
}
}

View file

@ -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<List<TransactionWithCategory>> = transactionRepo.getTransactions(count)
fun getTransactionsByType(count: Int, type: TransactionType): LiveData<List<TransactionWithCategory>>
= transactionRepo.getTransactionsByType(count, type)
// fun getTransactionsByType(count: Int, type: TransactionType): LiveData<List<TransactionWithCategory>>
// = transactionRepo.getTransactionsByType(count, type)
fun getCurrentBalance(): LiveData<Double> = transactionRepo.getCurrentBalance()
fun getCurrentBalance(): LiveData<Int> = transactionRepo.getCurrentBalance()
fun getCategories(): LiveData<List<TransactionCategory>> = 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)
}
}

View file

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
@ -51,10 +52,12 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/container_edit_category_name">
<android.support.design.widget.TextInputEditText
<com.blackcat.currencyedittext.CurrencyEditText
android:id="@+id/edit_category_amount"
style="@style/AppTheme.EditText"
android:inputType="numberDecimal" />
android:text="0.00"
android:inputType="number"
tools:ignore="HardcodedText" />
</android.support.design.widget.TextInputLayout>
<!--<TextView-->

View file

@ -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">
<android.support.design.widget.TextInputEditText
<com.blackcat.currencyedittext.CurrencyEditText
android:id="@+id/edit_transaction_amount"
style="@style/AppTheme.EditText"
android:inputType="numberDecimal" />
</android.support.design.widget.TextInputLayout>
<RadioGroup
android:id="@+id/container_edit_transaction_type"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:orientation="horizontal"
app:layout_constraintTop_toBottomOf="@+id/container_edit_transaction_amount">
<RadioButton
android:id="@+id/edit_transaction_type_expense"
android:text="@string/type_expense"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<RadioButton
android:id="@+id/edit_transaction_type_income"
android:text="@string/type_income"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RadioGroup>
<TextView
android:id="@+id/container_edit_transaction_date"
style="@style/AppTheme.EditText.Hint"
@ -80,15 +97,13 @@
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:text="@string/prompt_transaction_date"
app:layout_constraintBottom_toTopOf="@+id/edit_transaction_date"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/container_edit_transaction_amount" />
app:layout_constraintTop_toBottomOf="@+id/container_edit_transaction_type" />
<DatePicker
android:id="@+id/edit_transaction_date"
style="@style/AppTheme.DatePicker"
app:layout_constraintBottom_toTopOf="@+id/container_edit_transaction_category"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/container_edit_transaction_date" />
@ -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" />

View file

@ -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">
<android.support.v7.widget.Toolbar
android:id="@+id/action_bar"
@ -33,4 +33,4 @@
app:layout_constraintRight_toRightOf="parent"
app:menu="@menu/main_navigation" />
</android.support.constraint.ConstraintLayout>
</android.support.constraint.ConstraintLayout>

View file

@ -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"

View file

@ -5,15 +5,11 @@
android:icon="@drawable/ic_baseline_dashboard_24dp"
android:title="@string/title_dashboard" />
<item
android:id="@+id/action_expenses"
android:icon="@drawable/ic_money_off_black_24dp"
android:title="@string/title_expenses" />
<item
android:id="@+id/action_income"
android:id="@+id/action_transactions"
android:icon="@drawable/ic_attach_money_black_24dp"
android:title="@string/title_income" />
android:title="@string/title_transactions" />
<item
android:id="@+id/action_categories"
android:icon="@drawable/ic_baseline_category_24px"
android:title="@string/title_categories" />
</menu>
</menu>

View file

@ -2,23 +2,20 @@
<string name="app_name">My Allowance</string>
<string name="app_name_short">Allowance</string>
<string name="prompt_transaction_title">Title</string>
<string name="title_add_income">Add Income</string>
<string name="title_add_expense">Add Expense</string>
<string name="title_add_transaction">Add Transaction</string>
<string name="prompt_transaction_description">Description</string>
<string name="prompt_transaction_date">Date</string>
<string name="prompt_transaction_amount">Amount</string>
<string name="title_expenses">Expenses</string>
<string name="title_income">Income</string>
<string name="type_expense">Expense</string>
<string name="type_income">Income</string>
<string name="title_dashboard">Dashboard</string>
<string name="label_current_balance">Current Balance</string>
<string name="overview_no_data">&#x1F4C8;\nAdd some transactions to see an overview of your spending here</string>
<string name="action_save">Save</string>
<string name="action_delete">Delete</string>
<string name="title_edit_income">Edit Income</string>
<string name="title_edit_expense">Edit Expense</string>
<string name="income_no_data">&#x1F333;\nGet to work! Money doesn\'t grow on trees after all</string>
<string name="expenses_no_data">&#x1F914;\nAre you sure you haven\'t spent any money?</string>
<string name="title_edit_transaction">Edit Transaction</string>
<string name="categories_no_data">&#x1F333;\nGet to work! Money doesn\'t grow on trees after all</string>
<string name="transactions_no_data">&#x1F914;\nAre you sure you haven\'t spent any money?</string>
<string name="title_categories">Categories</string>
<string name="title_edit_category">Edit Category</string>
<string name="prompt_category_amount">Amount</string>
@ -28,4 +25,6 @@
<string name="prompt_transaction_category">Category</string>
<string name="required_field_name">Name is a required field</string>
<string name="required_field_amount">Amount is a required field</string>
<string name="title_transactions">Transactions</string>
<string name="balance_remaning">\$%1$.02f remaining</string>
</resources>

View file

@ -2,33 +2,15 @@
<shortcuts xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android">
<shortcut
android:shortcutId="expense"
android:enabled="true"
android:icon="@drawable/ic_shortcut_money_off"
android:shortcutShortLabel="@string/title_add_expense"
tools:ignore="UnusedAttribute">
<intent
android:action="android.intent.action.VIEW"
android:targetPackage="com.wbrawner.budget"
android:targetClass="com.wbrawner.budget.transactions.AddEditTransactionActivity">
<extra
android:name="EXTRA_TRANSACTION_TYPE"
android:value="EXPENSE" />
</intent>
</shortcut>
<shortcut
android:shortcutId="income"
android:shortcutId="transaction"
android:enabled="true"
android:icon="@drawable/ic_shortcut_attach_money"
android:shortcutShortLabel="@string/title_add_income"
android:shortcutShortLabel="@string/title_add_transaction"
tools:ignore="UnusedAttribute">
<intent
android:action="android.intent.action.VIEW"
android:targetPackage="com.wbrawner.budget"
android:targetClass="com.wbrawner.budget.transactions.AddEditTransactionActivity">
<extra
android:name="EXTRA_TRANSACTION_TYPE"
android:value="INCOME" />
android:targetClass="com.wbrawner.budget.ui.transactions.AddEditTransactionActivity">
</intent>
</shortcut>
</shortcuts>
</shortcuts>

View file

@ -19,6 +19,7 @@ allprojects {
repositories {
google()
jcenter()
maven { url "https://jitpack.io" }
}
}