diff --git a/.project b/.project
new file mode 100644
index 0000000..02da4bc
--- /dev/null
+++ b/.project
@@ -0,0 +1,17 @@
+
+
+ MyAllowance
+ Project MyAllowance created by Buildship.
+
+
+
+
+ org.eclipse.buildship.core.gradleprojectbuilder
+
+
+
+
+
+ org.eclipse.buildship.core.gradleprojectnature
+
+
diff --git a/.settings/org.eclipse.buildship.core.prefs b/.settings/org.eclipse.buildship.core.prefs
new file mode 100644
index 0000000..e889521
--- /dev/null
+++ b/.settings/org.eclipse.buildship.core.prefs
@@ -0,0 +1,2 @@
+connection.project.dir=
+eclipse.preferences.version=1
diff --git a/app/.classpath b/app/.classpath
new file mode 100644
index 0000000..eb19361
--- /dev/null
+++ b/app/.classpath
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/app/.project b/app/.project
new file mode 100644
index 0000000..ac485d7
--- /dev/null
+++ b/app/.project
@@ -0,0 +1,23 @@
+
+
+ app
+ Project app created by Buildship.
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.buildship.core.gradleprojectbuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+ org.eclipse.buildship.core.gradleprojectnature
+
+
diff --git a/app/.settings/org.eclipse.buildship.core.prefs b/app/.settings/org.eclipse.buildship.core.prefs
new file mode 100644
index 0000000..b1886ad
--- /dev/null
+++ b/app/.settings/org.eclipse.buildship.core.prefs
@@ -0,0 +1,2 @@
+connection.project.dir=..
+eclipse.preferences.version=1
diff --git a/app/build.gradle b/app/build.gradle
index e1cfc8d..3d11e8a 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -18,7 +18,7 @@ android {
}
defaultConfig {
applicationId "com.wbrawner.budget"
- minSdkVersion 23
+ minSdkVersion 24
targetSdkVersion 27
versionCode 1
versionName "1.0"
@@ -29,6 +29,11 @@ android {
buildConfigField "String", "ACRA_URL", "\"${acra.getProperty("url")}\""
buildConfigField "String", "ACRA_USER", "\"${acra.getProperty("user")}\""
buildConfigField "String", "ACRA_PASS", "\"${acra.getProperty("pass")}\""
+ javaCompileOptions {
+ annotationProcessorOptions {
+ arguments = ["room.schemaLocation": "$projectDir/schemas".toString()]
+ }
+ }
}
buildTypes {
release {
@@ -36,6 +41,9 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
+ sourceSets {
+ androidTest.assets.srcDirs += files("$projectDir/schemas".toString())
+ }
}
dependencies {
diff --git a/app/schemas/com.wbrawner.budget.data.BudgetDatabase/2.json b/app/schemas/com.wbrawner.budget.data.BudgetDatabase/2.json
new file mode 100644
index 0000000..73db9a0
--- /dev/null
+++ b/app/schemas/com.wbrawner.budget.data.BudgetDatabase/2.json
@@ -0,0 +1,113 @@
+{
+ "formatVersion": 1,
+ "database": {
+ "version": 2,
+ "identityHash": "b68fd456557e5153b2fe6514a5193c07",
+ "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, `categoryId` INTEGER, `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": "categoryId",
+ "columnName": "categoryId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Category",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER, `name` TEXT NOT NULL, `amount` REAL NOT NULL, `repeat` TEXT, `color` INTEGER NOT NULL, PRIMARY KEY(`id`))",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "amount",
+ "columnName": "amount",
+ "affinity": "REAL",
+ "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, \"b68fd456557e5153b2fe6514a5193c07\")"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 0e89ae7..36c5963 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -20,7 +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 c0f379a..30efa53 100644
--- a/app/src/main/java/com/wbrawner/budget/AllowanceApplication.kt
+++ b/app/src/main/java/com/wbrawner/budget/AllowanceApplication.kt
@@ -3,9 +3,10 @@ package com.wbrawner.budget
import android.app.Application
import android.arch.persistence.room.Room
import android.content.Context
-import com.wbrawner.budget.data.TransactionDao
-import com.wbrawner.budget.data.TransactionsDatabase
-import com.wbrawner.budget.BuildConfig
+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 org.acra.ACRA
import org.acra.annotation.AcraCore
import org.acra.annotation.AcraHttpSender
@@ -18,23 +19,28 @@ import org.acra.sender.HttpSender
basicAuthPassword = BuildConfig.ACRA_PASS,
httpMethod = HttpSender.Method.POST)
class AllowanceApplication: Application() {
- lateinit var database: TransactionsDatabase
+ lateinit var database: BudgetDatabase
private set
- lateinit var dao: TransactionDao
+ lateinit var transactionDao: TransactionDao
+ private set
+
+ lateinit var categoryDao: CategoryDao
private set
override fun onCreate() {
super.onCreate()
- database = Room.databaseBuilder(applicationContext, TransactionsDatabase::class.java, "transactions")
+ database = Room.databaseBuilder(applicationContext, BudgetDatabase::class.java, "transactions")
+ .addMigrations(MIGRATION_1_2())
.build()
- dao = database.dao()
+ transactionDao = database.transactionDao()
+ categoryDao = database.categoryDao()
}
override fun attachBaseContext(base: Context?) {
super.attachBaseContext(base)
- ACRA.init(this)
+ if (!BuildConfig.DEBUG) ACRA.init(this)
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/com/wbrawner/budget/categories/AddEditCategoryActivity.kt b/app/src/main/java/com/wbrawner/budget/categories/AddEditCategoryActivity.kt
new file mode 100644
index 0000000..29cf14e
--- /dev/null
+++ b/app/src/main/java/com/wbrawner/budget/categories/AddEditCategoryActivity.kt
@@ -0,0 +1,96 @@
+package com.wbrawner.budget.categories
+
+import android.arch.lifecycle.Observer
+import android.arch.lifecycle.ViewModelProviders
+import android.graphics.Color
+import android.os.Bundle
+import android.support.v7.app.AppCompatActivity
+import android.view.Menu
+import android.view.MenuItem
+import com.wbrawner.budget.R
+import com.wbrawner.budget.data.model.Category
+import kotlinx.android.synthetic.main.activity_add_edit_category.*
+
+class AddEditCategoryActivity : AppCompatActivity() {
+ lateinit var viewModel: CategoryViewModel
+ var id: Int? = null
+ var menu: Menu? = null
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_add_edit_category)
+ setSupportActionBar(action_bar)
+ supportActionBar?.setDisplayHomeAsUpEnabled(true)
+ viewModel = ViewModelProviders.of(this).get(CategoryViewModel::class.java)
+
+ if (intent?.hasExtra(EXTRA_CATEGORY_ID) == false) {
+ setTitle(R.string.title_add_category)
+ return
+ }
+
+ viewModel.getCategory(intent!!.extras!!.getInt(EXTRA_CATEGORY_ID))
+ .observe(this, Observer { category ->
+ if (category == null) {
+ menu?.findItem(R.id.action_delete)?.isVisible = false
+ return@Observer
+ }
+ id = category.id
+ 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))
+ })
+ }
+
+
+ override fun onCreateOptionsMenu(menu: Menu?): Boolean {
+ menuInflater.inflate(R.menu.menu_add_edit, menu)
+ if (id != null) {
+ menu?.findItem(R.id.action_delete)?.isVisible = true
+ }
+ return true
+ }
+
+ override fun onOptionsItemSelected(item: MenuItem?): Boolean {
+ when (item?.itemId) {
+ android.R.id.home -> onBackPressed()
+ R.id.action_save -> {
+ if (!validateFields()) return true
+ viewModel.saveCategory(Category(
+ id = id,
+ name = edit_category_name.text.toString(),
+ amount = edit_category_amount.text.toString().toDouble(),
+ color = Color.parseColor("#FF0000"),
+ repeat = "never"
+ ))
+ finish()
+ }
+ R.id.action_delete -> {
+ viewModel.deleteCategoryById(this@AddEditCategoryActivity.id!!)
+ finish()
+ }
+ }
+ return true
+ }
+
+
+ private fun validateFields(): Boolean {
+ var errors = false
+ if (edit_category_name.text.isEmpty()) {
+ edit_category_name.error = getString(R.string.required_field_name)
+ errors = true
+ }
+
+ if (edit_category_amount.text.isEmpty()) {
+ edit_category_amount.error = getString(R.string.required_field_amount)
+ errors = true
+ }
+
+ return !errors
+ }
+
+
+ companion object {
+ const val EXTRA_CATEGORY_ID = "EXTRA_CATEGORY_ID"
+ }
+}
diff --git a/app/src/main/java/com/wbrawner/budget/categories/CategoryAdapter.kt b/app/src/main/java/com/wbrawner/budget/categories/CategoryAdapter.kt
new file mode 100644
index 0000000..07d8005
--- /dev/null
+++ b/app/src/main/java/com/wbrawner/budget/categories/CategoryAdapter.kt
@@ -0,0 +1,64 @@
+package com.wbrawner.budget.categories
+
+import android.arch.lifecycle.LifecycleOwner
+import android.arch.lifecycle.Observer
+import android.content.Intent
+import android.support.v4.content.ContextCompat.startActivity
+import android.support.v7.widget.RecyclerView
+import android.view.LayoutInflater
+import android.view.View
+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.data.model.Category
+
+class CategoryAdapter(
+ private val lifecycleOwner: LifecycleOwner,
+ private val data: List,
+ private val viewModel: CategoryViewModel
+) : RecyclerView.Adapter() {
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
+ val view = LayoutInflater.from(parent.context)
+ .inflate(R.layout.list_item_category, parent, false)
+ return ViewHolder(view)
+ }
+
+ override fun getItemCount(): Int = data.size
+
+ override fun onBindViewHolder(holder: ViewHolder, position: Int) {
+ val category = data[position]
+ holder.title?.text = category.name
+ holder.amount?.text = String.format("${'$'}%.02f", category.amount)
+ viewModel.getCurrentBalance(category.id!!)
+ .observe(lifecycleOwner, Observer { balance ->
+ holder.progress?.isIndeterminate = false
+ if (balance == null) {
+ holder.progress?.progress = 0
+ } else {
+ holder.progress?.max = category.amount.toInt()
+ holder.progress?.setProgress(
+ Math.abs(balance).toInt(),
+ true
+ )
+ }
+ })
+ holder.itemView.setOnClickListener {
+ startActivity(
+ it.context.applicationContext,
+ Intent(it.context.applicationContext, AddEditCategoryActivity::class.java)
+ .apply {
+ putExtra(EXTRA_CATEGORY_ID, category.id)
+ },
+ null
+ )
+ }
+ }
+
+ inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
+ val title: TextView? = itemView.findViewById(R.id.category_title)
+ val amount: TextView? = itemView.findViewById(R.id.category_amount)
+ val progress: ProgressBar? = itemView.findViewById(R.id.category_progress)
+ }
+}
diff --git a/app/src/main/java/com/wbrawner/budget/categories/CategoryListFragment.kt b/app/src/main/java/com/wbrawner/budget/categories/CategoryListFragment.kt
new file mode 100644
index 0000000..0878b4e
--- /dev/null
+++ b/app/src/main/java/com/wbrawner/budget/categories/CategoryListFragment.kt
@@ -0,0 +1,69 @@
+package com.wbrawner.budget.categories
+
+import android.arch.lifecycle.Observer
+import android.arch.lifecycle.ViewModelProviders
+import android.content.Intent
+import android.os.Bundle
+import android.support.design.widget.FloatingActionButton
+import android.support.text.emoji.widget.EmojiTextView
+import android.support.v4.app.Fragment
+import android.support.v7.widget.LinearLayoutManager
+import android.support.v7.widget.RecyclerView
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import com.wbrawner.budget.R
+import com.wbrawner.budget.data.model.Category
+
+class CategoryListFragment : Fragment() {
+ lateinit var viewModel: CategoryViewModel
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ if (activity == null) {
+ return
+ }
+
+ if (savedInstanceState != null) {
+ return
+ }
+
+ viewModel = ViewModelProviders.of(activity!!).get(CategoryViewModel::class.java)
+ }
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
+ val view = inflater.inflate(R.layout.fragment_transaction_list, container, false)
+ val recyclerView = view.findViewById(R.id.list_transactions)
+ val fab = view.findViewById(R.id.fab_add_transaction)
+ recyclerView.layoutManager = LinearLayoutManager(activity)
+ viewModel.getCategories()
+ .observe(this, Observer> { data ->
+ val noDataView = view.findViewById(R.id.transaction_list_no_data)
+ if (data == null || data.isEmpty()) {
+ recyclerView.adapter = null
+ noDataView?.setText("No data FIX ME")
+ recyclerView?.visibility = View.GONE
+ noDataView?.visibility = View.VISIBLE
+ } else {
+ recyclerView.adapter = CategoryAdapter(this, data, viewModel)
+ recyclerView.visibility = View.VISIBLE
+ noDataView.visibility = View.GONE
+ }
+ })
+ recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
+ override fun onScrolled(recyclerView: RecyclerView?, dx: Int, dy: Int) {
+ if (dy > 0) fab.hide() else fab.show()
+ }
+ })
+ fab.setOnClickListener {
+ startActivity(Intent(activity, AddEditCategoryActivity::class.java))
+ }
+
+ return view
+ }
+
+ companion object {
+ const val TAG_FRAGMENT = "categories"
+ const val TITLE_FRAGMENT = R.string.title_categories
+ }
+}
diff --git a/app/src/main/java/com/wbrawner/budget/categories/CategoryViewModel.kt b/app/src/main/java/com/wbrawner/budget/categories/CategoryViewModel.kt
new file mode 100644
index 0000000..3f351b7
--- /dev/null
+++ b/app/src/main/java/com/wbrawner/budget/categories/CategoryViewModel.kt
@@ -0,0 +1,26 @@
+package com.wbrawner.budget.categories
+
+import android.app.Application
+import android.arch.lifecycle.AndroidViewModel
+import android.arch.lifecycle.LiveData
+import com.wbrawner.budget.AllowanceApplication
+import com.wbrawner.budget.data.model.Category
+import com.wbrawner.budget.data.CategoryRepository
+
+class CategoryViewModel(application: Application): AndroidViewModel(application) {
+ private val categoryRepo = CategoryRepository((application as AllowanceApplication).categoryDao)
+
+ fun getCategory(id: Int): LiveData = categoryRepo.getCategory(id)
+
+ fun getCategories(): LiveData> = categoryRepo.getCategories()
+
+ fun saveCategory(category: Category) = categoryRepo.save(category)
+
+ fun deleteCategory(category: Category) = categoryRepo.delete(category)
+
+ fun deleteCategoryById(id: Int) = categoryRepo.deleteById(id)
+
+ 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/data/BudgetDatabase.kt b/app/src/main/java/com/wbrawner/budget/data/BudgetDatabase.kt
new file mode 100644
index 0000000..004a6b3
--- /dev/null
+++ b/app/src/main/java/com/wbrawner/budget/data/BudgetDatabase.kt
@@ -0,0 +1,16 @@
+package com.wbrawner.budget.data
+
+import android.arch.persistence.room.Database
+import android.arch.persistence.room.RoomDatabase
+import android.arch.persistence.room.TypeConverters
+import com.wbrawner.budget.data.dao.CategoryDao
+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)
+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
new file mode 100644
index 0000000..51168f8
--- /dev/null
+++ b/app/src/main/java/com/wbrawner/budget/data/CategoryRepository.kt
@@ -0,0 +1,44 @@
+package com.wbrawner.budget.data
+
+import android.arch.lifecycle.LiveData
+import android.os.Handler
+import android.os.HandlerThread
+import com.wbrawner.budget.data.dao.CategoryDao
+import com.wbrawner.budget.data.model.Category
+import com.wbrawner.budget.data.model.Transaction
+
+class CategoryRepository(private val dao: CategoryDao) {
+ private val handler: Handler
+
+ init {
+ val thread = HandlerThread("category")
+ thread.start()
+ handler = Handler(thread.looper)
+ }
+
+ fun getCategories(): LiveData> = dao.loadMultiple()
+
+
+ fun getCategory(id: Int): LiveData = dao.load(id)
+
+
+ fun save(category: Category) {
+ handler.post { dao.save(category) }
+ }
+
+
+ fun delete(category: Category) {
+ handler.post { dao.delete(category) }
+ }
+
+
+ fun deleteById(id: Int) {
+ handler.post { dao.deleteById(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 30babaa..8691d7a 100644
--- a/app/src/main/java/com/wbrawner/budget/data/TransactionRepository.kt
+++ b/app/src/main/java/com/wbrawner/budget/data/TransactionRepository.kt
@@ -3,10 +3,13 @@ package com.wbrawner.budget.data
import android.arch.lifecycle.LiveData
import android.os.Handler
import android.os.HandlerThread
+import com.wbrawner.budget.data.dao.TransactionDao
+import com.wbrawner.budget.data.model.Transaction
+import com.wbrawner.budget.data.model.TransactionCategory
+import com.wbrawner.budget.data.model.TransactionWithCategory
-class TransactionRepository(val dao: TransactionDao) {
- val handler: Handler
- val uiHandler: Handler = Handler()
+class TransactionRepository(private val dao: TransactionDao) {
+ private val handler: Handler
init {
val thread = HandlerThread("transactions")
@@ -14,36 +17,13 @@ class TransactionRepository(val dao: TransactionDao) {
handler = Handler(thread.looper)
}
- fun getTransactionsByType(count: Int, type: TransactionType): LiveData> =
+ fun getTransactionsByType(count: Int, type: TransactionType): LiveData> =
dao.loadMultipleByType(count, type)
- fun getTransactions(count: Int): LiveData> = dao.loadMultiple(count)
+ fun getTransactions(count: Int): LiveData> = dao.loadMultiple(count)
-// fun getTransactions(count: Int): LiveData> {
-// val data = MutableLiveData>()
-//
-// handler.post {
-// val transactions = ArrayList()
-// for (i in 0..count) {
-// transactions.add(Transaction(
-// i,
-// "Transaction $i",
-// Date(),
-// "Spent some money on something",
-// (Math.random() * 100).toFloat(),
-// TransactionType.EXPENSE
-// ))
-// }
-//
-// uiHandler.post {
-// data.value = transactions
-// }
-// }
-//
-// return data
-// }
- fun getTransaction(id: Int): LiveData = dao.load(id)
+ fun getTransaction(id: Int): LiveData = dao.load(id)
fun save(transaction: Transaction) {
@@ -62,4 +42,6 @@ class TransactionRepository(val dao: TransactionDao) {
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/TransactionsDatabase.kt b/app/src/main/java/com/wbrawner/budget/data/TransactionsDatabase.kt
deleted file mode 100644
index 9df4892..0000000
--- a/app/src/main/java/com/wbrawner/budget/data/TransactionsDatabase.kt
+++ /dev/null
@@ -1,11 +0,0 @@
-package com.wbrawner.budget.data
-
-import android.arch.persistence.room.Database
-import android.arch.persistence.room.RoomDatabase
-import android.arch.persistence.room.TypeConverters
-
-@Database(entities = [(Transaction::class)], version = 1, exportSchema = false)
-@TypeConverters(DateTypeConverter::class, TransactionTypeTypeConverter::class)
-abstract class TransactionsDatabase: RoomDatabase() {
- abstract fun dao(): TransactionDao
-}
\ No newline at end of file
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 8cbcc5b..603d6bf 100644
--- a/app/src/main/java/com/wbrawner/budget/data/TypeConverters.kt
+++ b/app/src/main/java/com/wbrawner/budget/data/TypeConverters.kt
@@ -1,5 +1,6 @@
package com.wbrawner.budget.data
+import android.arch.persistence.room.TypeConverter
import java.text.SimpleDateFormat
import java.util.*
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
new file mode 100644
index 0000000..e1617c0
--- /dev/null
+++ b/app/src/main/java/com/wbrawner/budget/data/dao/CategoryDao.kt
@@ -0,0 +1,37 @@
+package com.wbrawner.budget.data.dao
+
+import android.arch.lifecycle.LiveData
+import android.arch.persistence.room.Dao
+import android.arch.persistence.room.Delete
+import android.arch.persistence.room.Insert
+import android.arch.persistence.room.OnConflictStrategy.REPLACE
+import android.arch.persistence.room.Query
+import com.wbrawner.budget.data.model.Category
+import com.wbrawner.budget.data.model.Transaction
+
+@Dao
+interface CategoryDao {
+ @Insert(onConflict = REPLACE)
+ fun save(category: Category)
+
+ @Query("SELECT * FROM `Category` WHERE id = :id")
+ fun load(id: Int): LiveData
+
+ @Query("SELECT * FROM `Category`")
+ 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
+
+ @Delete
+ fun delete(category: Category)
+
+ @Query("DELETE FROM `Category` WHERE id = :id")
+ fun deleteById(id: Int)
+
+
+ @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/TransactionDao.kt b/app/src/main/java/com/wbrawner/budget/data/dao/TransactionDao.kt
similarity index 64%
rename from app/src/main/java/com/wbrawner/budget/data/TransactionDao.kt
rename to app/src/main/java/com/wbrawner/budget/data/dao/TransactionDao.kt
index 3484722..4f20470 100644
--- a/app/src/main/java/com/wbrawner/budget/data/TransactionDao.kt
+++ b/app/src/main/java/com/wbrawner/budget/data/dao/TransactionDao.kt
@@ -1,4 +1,4 @@
-package com.wbrawner.budget.data
+package com.wbrawner.budget.data.dao
import android.arch.lifecycle.LiveData
import android.arch.persistence.room.Dao
@@ -6,6 +6,10 @@ import android.arch.persistence.room.Delete
import android.arch.persistence.room.Insert
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
interface TransactionDao {
@@ -13,13 +17,13 @@ interface TransactionDao {
fun save(transaction: Transaction)
@Query("SELECT * FROM `Transaction` WHERE id = :id")
- fun load(id: Int): LiveData
+ fun load(id: Int): LiveData
@Query("SELECT * FROM `Transaction` LIMIT :count")
- fun loadMultiple(count: Int): LiveData>
+ fun loadMultiple(count: Int): LiveData>
@Query("SELECT * FROM `Transaction` WHERE type = :type LIMIT :count")
- fun loadMultipleByType(count: Int, type: TransactionType): LiveData>
+ 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
@@ -29,4 +33,7 @@ interface TransactionDao {
@Query("DELETE FROM `Transaction` WHERE id = :id")
fun deleteById(id: Int)
+
+ @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
new file mode 100644
index 0000000..ac73356
--- /dev/null
+++ b/app/src/main/java/com/wbrawner/budget/data/migrations/MIGRATION_1_2.kt
@@ -0,0 +1,13 @@
+package com.wbrawner.budget.data.migrations
+
+import android.arch.persistence.db.SupportSQLiteDatabase
+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")
+ }
+
+}
\ No newline at end of file
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
new file mode 100644
index 0000000..40cb2f2
--- /dev/null
+++ b/app/src/main/java/com/wbrawner/budget/data/model/Category.kt
@@ -0,0 +1,15 @@
+package com.wbrawner.budget.data.model
+
+import android.arch.persistence.room.Entity
+import android.arch.persistence.room.PrimaryKey
+import android.support.annotation.ColorInt
+
+@Entity
+class Category(
+ @PrimaryKey
+ val id: Int?,
+ val name: String,
+ val amount: Double,
+ val repeat: String?,
+ @ColorInt val color: Int
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/wbrawner/budget/data/Transaction.kt b/app/src/main/java/com/wbrawner/budget/data/model/Transaction.kt
similarity index 73%
rename from app/src/main/java/com/wbrawner/budget/data/Transaction.kt
rename to app/src/main/java/com/wbrawner/budget/data/model/Transaction.kt
index 688af4d..b62a19a 100644
--- a/app/src/main/java/com/wbrawner/budget/data/Transaction.kt
+++ b/app/src/main/java/com/wbrawner/budget/data/model/Transaction.kt
@@ -1,7 +1,8 @@
-package com.wbrawner.budget.data
+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
@@ -12,5 +13,6 @@ class Transaction(
val date: Date,
val description: String,
val amount: Double,
+ val categoryId: Int?,
val type: TransactionType
)
\ No newline at end of file
diff --git a/app/src/main/java/com/wbrawner/budget/data/model/TransactionCategory.kt b/app/src/main/java/com/wbrawner/budget/data/model/TransactionCategory.kt
new file mode 100644
index 0000000..1b5acd5
--- /dev/null
+++ b/app/src/main/java/com/wbrawner/budget/data/model/TransactionCategory.kt
@@ -0,0 +1,10 @@
+package com.wbrawner.budget.data.model
+
+class TransactionCategory(
+ val id: Int,
+ val name: String
+) {
+ override fun toString(): String {
+ return name
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/wbrawner/budget/data/model/TransactionWithCategory.kt b/app/src/main/java/com/wbrawner/budget/data/model/TransactionWithCategory.kt
new file mode 100644
index 0000000..14bd314
--- /dev/null
+++ b/app/src/main/java/com/wbrawner/budget/data/model/TransactionWithCategory.kt
@@ -0,0 +1,14 @@
+package com.wbrawner.budget.data.model
+
+import android.arch.persistence.room.Embedded
+import android.arch.persistence.room.Relation
+import com.wbrawner.budget.data.model.Category
+import com.wbrawner.budget.data.model.Transaction
+
+class TransactionWithCategory {
+ @Embedded
+ lateinit var transaction: Transaction
+
+ @Relation(parentColumn = "id", entityColumn = "id")
+ lateinit var categorySet: Set
+}
\ 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/overview/OverviewFragment.kt
index e8d2b2e..19f5f3d 100644
--- a/app/src/main/java/com/wbrawner/budget/overview/OverviewFragment.kt
+++ b/app/src/main/java/com/wbrawner/budget/overview/OverviewFragment.kt
@@ -20,12 +20,7 @@ class OverviewFragment : Fragment() {
return
}
- if (savedInstanceState != null) {
- return
- }
-
viewModel = ViewModelProviders.of(activity!!).get(TransactionViewModel::class.java)
-
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
@@ -64,4 +59,4 @@ class OverviewFragment : Fragment() {
const val TAG_FRAGMENT = "overview"
const val TITLE_FRAGMENT = R.string.app_name
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/com/wbrawner/budget/addedittransaction/AddEditTransactionActivity.kt b/app/src/main/java/com/wbrawner/budget/transactions/AddEditTransactionActivity.kt
similarity index 65%
rename from app/src/main/java/com/wbrawner/budget/addedittransaction/AddEditTransactionActivity.kt
rename to app/src/main/java/com/wbrawner/budget/transactions/AddEditTransactionActivity.kt
index 99a008e..4ad04b0 100644
--- a/app/src/main/java/com/wbrawner/budget/addedittransaction/AddEditTransactionActivity.kt
+++ b/app/src/main/java/com/wbrawner/budget/transactions/AddEditTransactionActivity.kt
@@ -1,4 +1,4 @@
-package com.wbrawner.budget.addedittransaction
+package com.wbrawner.budget.transactions
import android.arch.lifecycle.Observer
import android.arch.lifecycle.ViewModelProviders
@@ -6,10 +6,12 @@ import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.view.Menu
import android.view.MenuItem
+import android.widget.ArrayAdapter
import com.wbrawner.budget.R
-import com.wbrawner.budget.data.Transaction
+import com.wbrawner.budget.data.model.Transaction
+import com.wbrawner.budget.data.model.TransactionCategory
import com.wbrawner.budget.data.TransactionType
-import com.wbrawner.budget.transactions.TransactionViewModel
+import com.wbrawner.budget.data.model.TransactionWithCategory
import kotlinx.android.synthetic.main.activity_add_edit_transaction.*
import java.util.*
@@ -26,6 +28,22 @@ class AddEditTransactionActivity : AppCompatActivity() {
setSupportActionBar(action_bar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
viewModel = ViewModelProviders.of(this).get(TransactionViewModel::class.java)
+ viewModel.getCategories()
+ .observe(this, Observer> { categories ->
+ val adapter = ArrayAdapter(
+ this@AddEditTransactionActivity,
+ android.R.layout.simple_list_item_1
+ )
+
+ adapter.add(TransactionCategory(0, getString(R.string.uncategorized)))
+ if (categories == null || categories.isEmpty()) {
+ return@Observer
+ }
+
+ adapter.addAll(categories)
+ 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")
@@ -37,11 +55,12 @@ class AddEditTransactionActivity : AppCompatActivity() {
}
viewModel.getTransaction(intent!!.extras!!.getInt(EXTRA_TRANSACTION_ID))
- .observe(this, Observer { transaction ->
- if (transaction == null) {
+ .observe(this, Observer { transactionWithCategory ->
+ if (transactionWithCategory == null) {
menu?.findItem(R.id.action_delete)?.isVisible = false
return@Observer
}
+ val transaction = transactionWithCategory.transaction
id = transaction.id
type = transaction.type
setTitle(type.editTitle)
@@ -55,6 +74,15 @@ class AddEditTransactionActivity : AppCompatActivity() {
val month = field.get(Calendar.MONTH)
val day = field.get(Calendar.DAY_OF_MONTH)
edit_transaction_date.updateDate(year, month, day)
+ if (transactionWithCategory.categorySet.isNotEmpty()) {
+ val category = transactionWithCategory.categorySet.first()
+ for (i in 0 until edit_transaction_category.adapter.count) {
+ if (category.id == (edit_transaction_category.adapter.getItem(i) as TransactionCategory).id) {
+ edit_transaction_category.setSelection(i)
+ break
+ }
+ }
+ }
})
}
@@ -81,7 +109,8 @@ class AddEditTransactionActivity : AppCompatActivity() {
date = cal.time,
description = edit_transaction_description.text.toString(),
amount = edit_transaction_amount.text.toString().toDouble(),
- type = type
+ type = type,
+ categoryId = (edit_transaction_category.selectedItem as TransactionCategory).id
))
finish()
}
diff --git a/app/src/main/java/com/wbrawner/budget/transactions/TransactionAdapter.kt b/app/src/main/java/com/wbrawner/budget/transactions/TransactionAdapter.kt
index fe5b416..6c05a20 100644
--- a/app/src/main/java/com/wbrawner/budget/transactions/TransactionAdapter.kt
+++ b/app/src/main/java/com/wbrawner/budget/transactions/TransactionAdapter.kt
@@ -8,13 +8,15 @@ import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import com.wbrawner.budget.R
-import com.wbrawner.budget.addedittransaction.AddEditTransactionActivity
-import com.wbrawner.budget.addedittransaction.AddEditTransactionActivity.Companion.EXTRA_TRANSACTION_ID
-import com.wbrawner.budget.data.Transaction
+import com.wbrawner.budget.transactions.AddEditTransactionActivity.Companion.EXTRA_TRANSACTION_ID
+import com.wbrawner.budget.data.model.Transaction
+import com.wbrawner.budget.data.model.TransactionWithCategory
import java.text.SimpleDateFormat
-class TransactionAdapter(private val data: List)
- : RecyclerView.Adapter() {
+class TransactionAdapter() : RecyclerView.Adapter() {
+ private lateinit var data: List
+ private lateinit var listType: Class
+
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.list_item_transaction, parent, false)
@@ -24,7 +26,9 @@ class TransactionAdapter(private val data: List)
override fun getItemCount(): Int = data.size
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
- val transaction = data[position]
+ val transaction: Transaction =
+ if (listType == TransactionWithCategory::class.java) (data[position] as TransactionWithCategory).transaction
+ else data[position] as Transaction
holder.title.text = transaction.title
holder.date.text = SimpleDateFormat.getDateInstance(SimpleDateFormat.SHORT).format(transaction.date)
holder.amount.text = String.format("${'$'}%.02f", transaction.amount)
@@ -44,7 +48,16 @@ class TransactionAdapter(private val data: List)
}
}
- inner class ViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) {
+ constructor(transactions: List) : this() {
+ if (transactions.isEmpty()) {
+ return
+ }
+
+ listType = transactions.first().javaClass
+ data = transactions
+ }
+
+ inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val title = itemView.findViewById(R.id.transaction_title)
val date = itemView.findViewById(R.id.transaction_date)
val amount = itemView.findViewById(R.id.transaction_amount)
diff --git a/app/src/main/java/com/wbrawner/budget/transactions/TransactionListActivity.kt b/app/src/main/java/com/wbrawner/budget/transactions/TransactionListActivity.kt
index d903aa7..f25d21f 100644
--- a/app/src/main/java/com/wbrawner/budget/transactions/TransactionListActivity.kt
+++ b/app/src/main/java/com/wbrawner/budget/transactions/TransactionListActivity.kt
@@ -6,6 +6,7 @@ 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 kotlinx.android.synthetic.main.activity_transaction_list.*
@@ -21,6 +22,7 @@ class TransactionListActivity : AppCompatActivity() {
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)
else ->
updateFragment(OverviewFragment.TAG_FRAGMENT, OverviewFragment.TITLE_FRAGMENT)
}
@@ -38,13 +40,17 @@ class TransactionListActivity : AppCompatActivity() {
var fragment = supportFragmentManager.findFragmentByTag(tag)
val ft = supportFragmentManager.beginTransaction()
if (fragment == null) {
- fragment = if (tag == "overview") OverviewFragment()
- else
- TransactionListFragment().apply {
- arguments = Bundle().apply {
- putSerializable(TransactionListFragment.ARG_TYPE, TransactionType.valueOf(tag))
+ fragment = when (tag) {
+ OverviewFragment.TAG_FRAGMENT -> OverviewFragment()
+ CategoryListFragment.TAG_FRAGMENT -> CategoryListFragment()
+ else -> {
+ TransactionListFragment().apply {
+ arguments = Bundle().apply {
+ putSerializable(TransactionListFragment.ARG_TYPE, TransactionType.valueOf(tag))
+ }
}
}
+ }
ft.add(R.id.content_container, fragment, tag)
}
for (fmFragment in supportFragmentManager.fragments) {
diff --git a/app/src/main/java/com/wbrawner/budget/transactions/TransactionListFragment.kt b/app/src/main/java/com/wbrawner/budget/transactions/TransactionListFragment.kt
index 337fab8..555d6e4 100644
--- a/app/src/main/java/com/wbrawner/budget/transactions/TransactionListFragment.kt
+++ b/app/src/main/java/com/wbrawner/budget/transactions/TransactionListFragment.kt
@@ -13,10 +13,9 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.wbrawner.budget.R
-import com.wbrawner.budget.addedittransaction.AddEditTransactionActivity
-import com.wbrawner.budget.addedittransaction.AddEditTransactionActivity.Companion.EXTRA_TYPE
-import com.wbrawner.budget.data.Transaction
+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
@@ -43,7 +42,7 @@ class TransactionListFragment : Fragment() {
val fab = view.findViewById(R.id.fab_add_transaction)
recyclerView.layoutManager = LinearLayoutManager(activity)
viewModel.getTransactionsByType(20, type)
- .observe(this, Observer> { data ->
+ .observe(this, Observer> { data ->
val noDataView = view.findViewById(R.id.transaction_list_no_data)
if (data == null || data.isEmpty()) {
recyclerView.adapter = null
diff --git a/app/src/main/java/com/wbrawner/budget/transactions/TransactionViewModel.kt b/app/src/main/java/com/wbrawner/budget/transactions/TransactionViewModel.kt
index a3e02be..ea1dcb5 100644
--- a/app/src/main/java/com/wbrawner/budget/transactions/TransactionViewModel.kt
+++ b/app/src/main/java/com/wbrawner/budget/transactions/TransactionViewModel.kt
@@ -4,22 +4,25 @@ import android.app.Application
import android.arch.lifecycle.AndroidViewModel
import android.arch.lifecycle.LiveData
import com.wbrawner.budget.AllowanceApplication
-import com.wbrawner.budget.data.Transaction
-import com.wbrawner.budget.data.TransactionRepository
-import com.wbrawner.budget.data.TransactionType
+import com.wbrawner.budget.data.*
+import com.wbrawner.budget.data.model.Transaction
+import com.wbrawner.budget.data.model.TransactionCategory
+import com.wbrawner.budget.data.model.TransactionWithCategory
class TransactionViewModel(application: Application): AndroidViewModel(application) {
- private val transactionRepo = TransactionRepository((application as AllowanceApplication).dao)
+ private val transactionRepo = TransactionRepository((application as AllowanceApplication).transactionDao)
- fun getTransaction(id: Int): LiveData = transactionRepo.getTransaction(id)
+ fun getTransaction(id: Int): LiveData = transactionRepo.getTransaction(id)
- fun getTransactions(count: Int): LiveData> = transactionRepo.getTransactions(count)
+ fun getTransactions(count: Int): LiveData> = transactionRepo.getTransactions(count)
- fun getTransactionsByType(count: Int, type: TransactionType): LiveData>
+ fun getTransactionsByType(count: Int, type: TransactionType): LiveData>
= transactionRepo.getTransactionsByType(count, type)
fun getCurrentBalance(): LiveData = transactionRepo.getCurrentBalance()
+ fun getCategories(): LiveData> = transactionRepo.getCategories()
+
fun saveTransaction(transaction: Transaction) = transactionRepo.save(transaction)
fun deleteTransaction(transaction: Transaction) = transactionRepo.delete(transaction)
diff --git a/app/src/main/res/drawable/ic_baseline_category_24px.xml b/app/src/main/res/drawable/ic_baseline_category_24px.xml
new file mode 100644
index 0000000..ba008f3
--- /dev/null
+++ b/app/src/main/res/drawable/ic_baseline_category_24px.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_add_edit_category.xml b/app/src/main/res/layout/activity_add_edit_category.xml
new file mode 100644
index 0000000..3312118
--- /dev/null
+++ b/app/src/main/res/layout/activity_add_edit_category.xml
@@ -0,0 +1,81 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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 5ca5e08..1f4a08a 100644
--- a/app/src/main/res/layout/activity_add_edit_transaction.xml
+++ b/app/src/main/res/layout/activity_add_edit_transaction.xml
@@ -88,10 +88,31 @@
+
+
+
+
diff --git a/app/src/main/res/layout/list_item_category.xml b/app/src/main/res/layout/list_item_category.xml
new file mode 100644
index 0000000..6f2d1c5
--- /dev/null
+++ b/app/src/main/res/layout/list_item_category.xml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/menu/main_navigation.xml b/app/src/main/res/menu/main_navigation.xml
index 87a976d..c498d0c 100644
--- a/app/src/main/res/menu/main_navigation.xml
+++ b/app/src/main/res/menu/main_navigation.xml
@@ -12,4 +12,8 @@
android:id="@+id/action_income"
android:icon="@drawable/ic_attach_money_black_24dp"
android:title="@string/title_income" />
+
\ 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 e72e63c..09ece57 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -19,4 +19,13 @@
Edit Expense
🌳\nGet to work! Money doesn\'t grow on trees after all
🤔\nAre you sure you haven\'t spent any money?
+ Categories
+ Edit Category
+ Amount
+ Name
+ Add Category
+ Uncategorized
+ Category
+ Name is a required field
+ Amount is a required field
diff --git a/app/src/main/res/xml/shortcuts.xml b/app/src/main/res/xml/shortcuts.xml
index 508068f..320c19b 100644
--- a/app/src/main/res/xml/shortcuts.xml
+++ b/app/src/main/res/xml/shortcuts.xml
@@ -10,7 +10,7 @@
+ android:targetClass="com.wbrawner.budget.transactions.AddEditTransactionActivity">
@@ -25,7 +25,7 @@
+ android:targetClass="com.wbrawner.budget.transactions.AddEditTransactionActivity">
diff --git a/build.gradle b/build.gradle
index 6a0f417..ff630b8 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,13 +1,13 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
- ext.kotlin_version = '1.2.41'
+ ext.kotlin_version = '1.3.0'
repositories {
google()
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.1.4'
+ classpath 'com.android.tools.build:gradle:3.2.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index f20b0fe..c9fbfeb 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip