Update Category details page
This commit is contained in:
parent
2146a38bb2
commit
a1da7582b4
9 changed files with 126 additions and 43 deletions
|
@ -23,7 +23,7 @@ class MainActivity : AppCompatActivity() {
|
||||||
getString(R.string.title_overview) -> false
|
getString(R.string.title_overview) -> false
|
||||||
getString(R.string.title_transactions) -> false
|
getString(R.string.title_transactions) -> false
|
||||||
getString(R.string.title_profile) -> false
|
getString(R.string.title_profile) -> false
|
||||||
getString(R.string.title_budgets) -> false
|
getString(R.string.title_categories) -> false
|
||||||
else -> true
|
else -> true
|
||||||
}
|
}
|
||||||
supportActionBar?.setDisplayHomeAsUpEnabled(showHomeAsUp)
|
supportActionBar?.setDisplayHomeAsUpEnabled(showHomeAsUp)
|
||||||
|
|
|
@ -2,6 +2,7 @@ package com.wbrawner.budget.ui.categories
|
||||||
|
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.*
|
import android.view.*
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
@ -14,6 +15,7 @@ import com.wbrawner.budget.AsyncState
|
||||||
import com.wbrawner.budget.R
|
import com.wbrawner.budget.R
|
||||||
import com.wbrawner.budget.ui.EXTRA_BUDGET_ID
|
import com.wbrawner.budget.ui.EXTRA_BUDGET_ID
|
||||||
import com.wbrawner.budget.ui.EXTRA_CATEGORY_ID
|
import com.wbrawner.budget.ui.EXTRA_CATEGORY_ID
|
||||||
|
import com.wbrawner.budget.ui.toAmountSpannable
|
||||||
import com.wbrawner.budget.ui.transactions.TransactionListFragment
|
import com.wbrawner.budget.ui.transactions.TransactionListFragment
|
||||||
import kotlinx.android.synthetic.main.fragment_category_details.*
|
import kotlinx.android.synthetic.main.fragment_category_details.*
|
||||||
|
|
||||||
|
@ -48,7 +50,29 @@ class CategoryDetailsFragment : Fragment() {
|
||||||
progressBar.visibility = View.GONE
|
progressBar.visibility = View.GONE
|
||||||
val category = state.data.category
|
val category = state.data.category
|
||||||
activity?.title = category.title
|
activity?.title = category.title
|
||||||
categoryDescription.text = category.description
|
val tintColor = if (category.expense) R.color.colorTextRed else R.color.colorTextGreen
|
||||||
|
val colorStateList = with(view.context) {
|
||||||
|
android.content.res.ColorStateList.valueOf(getColor(tintColor))
|
||||||
|
}
|
||||||
|
categoryProgress.progressTintList = colorStateList
|
||||||
|
categoryProgress.max = category.amount.toInt()
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||||
|
categoryProgress.setProgress(
|
||||||
|
state.data.balance.toInt(),
|
||||||
|
true
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
categoryProgress.progress = state.data.balance.toInt()
|
||||||
|
}
|
||||||
|
total.text = category.amount.toAmountSpannable()
|
||||||
|
balance.text = state.data.balance.toAmountSpannable()
|
||||||
|
remaining.text = state.data.remaining.toAmountSpannable()
|
||||||
|
if (category.description.isNullOrBlank()) {
|
||||||
|
categoryDescription.visibility = View.GONE
|
||||||
|
} else {
|
||||||
|
categoryDescription.visibility = View.VISIBLE
|
||||||
|
categoryDescription.text = category.description
|
||||||
|
}
|
||||||
childFragmentManager.fragments.firstOrNull()?.let {
|
childFragmentManager.fragments.firstOrNull()?.let {
|
||||||
if (it !is TransactionListFragment) return@let
|
if (it !is TransactionListFragment) return@let
|
||||||
it.reloadItems()
|
it.reloadItems()
|
||||||
|
|
|
@ -23,10 +23,11 @@ class CategoryDetailsViewModel : ViewModel(), AsyncViewModel<CategoryDetails> {
|
||||||
launch {
|
launch {
|
||||||
val category = categoryRepo.findById(id)
|
val category = categoryRepo.findById(id)
|
||||||
val multiplier = if (category.expense) -1 else 1
|
val multiplier = if (category.expense) -1 else 1
|
||||||
val balance = categoryRepo.getBalance(category.id!!).toInt() * multiplier
|
val balance = categoryRepo.getBalance(category.id!!) * multiplier
|
||||||
CategoryDetails(
|
CategoryDetails(
|
||||||
category,
|
category,
|
||||||
balance
|
balance,
|
||||||
|
category.amount - balance
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,5 +35,6 @@ class CategoryDetailsViewModel : ViewModel(), AsyncViewModel<CategoryDetails> {
|
||||||
|
|
||||||
data class CategoryDetails(
|
data class CategoryDetails(
|
||||||
val category: Category,
|
val category: Category,
|
||||||
val balance: Int
|
val balance: Long,
|
||||||
|
val remaining: Long
|
||||||
)
|
)
|
|
@ -12,7 +12,6 @@ import androidx.navigation.fragment.findNavController
|
||||||
import com.wbrawner.budget.AllowanceApplication
|
import com.wbrawner.budget.AllowanceApplication
|
||||||
import com.wbrawner.budget.R
|
import com.wbrawner.budget.R
|
||||||
import com.wbrawner.budget.common.category.Category
|
import com.wbrawner.budget.common.category.Category
|
||||||
import com.wbrawner.budget.ui.EXTRA_BUDGET_ID
|
|
||||||
import com.wbrawner.budget.ui.EXTRA_CATEGORY_ID
|
import com.wbrawner.budget.ui.EXTRA_CATEGORY_ID
|
||||||
import com.wbrawner.budget.ui.base.BindableAdapter
|
import com.wbrawner.budget.ui.base.BindableAdapter
|
||||||
import com.wbrawner.budget.ui.base.BindableData
|
import com.wbrawner.budget.ui.base.BindableData
|
||||||
|
@ -23,7 +22,7 @@ class CategoryListFragment : ListWithAddButtonFragment<Category, CategoryListVie
|
||||||
override val noItemsStringRes: Int = R.string.categories_no_data
|
override val noItemsStringRes: Int = R.string.categories_no_data
|
||||||
override val viewModel: CategoryListViewModel by viewModels()
|
override val viewModel: CategoryListViewModel by viewModels()
|
||||||
override fun reloadItems() {
|
override fun reloadItems() {
|
||||||
viewModel.getCategories(arguments?.getLong(EXTRA_BUDGET_ID))
|
viewModel.getCategories()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun bindData(data: Category): BindableData<Category> = BindableData(data, CATEGORY_VIEW)
|
override fun bindData(data: Category): BindableData<Category> = BindableData(data, CATEGORY_VIEW)
|
||||||
|
|
|
@ -19,7 +19,8 @@ class CategoryListViewModel : ViewModel(), AsyncViewModel<List<Category>> {
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var categoryRepo: CategoryRepository
|
lateinit var categoryRepo: CategoryRepository
|
||||||
|
|
||||||
fun getCategories(budgetId: Long? = null) {
|
fun getCategories() {
|
||||||
|
val budgetId = budgetRepo.currentBudget?.id
|
||||||
if (budgetId == null) {
|
if (budgetId == null) {
|
||||||
state.postValue(AsyncState.Error("Invalid budget ID"))
|
state.postValue(AsyncState.Error("Invalid budget ID"))
|
||||||
return
|
return
|
||||||
|
|
|
@ -32,7 +32,7 @@ class TransactionListFragment : ListWithAddButtonFragment<Transaction, Transacti
|
||||||
get() = mapOf(TRANSACTION_VIEW to { v -> TransactionViewHolder(v, findNavController()) })
|
get() = mapOf(TRANSACTION_VIEW to { v -> TransactionViewHolder(v, findNavController()) })
|
||||||
|
|
||||||
override fun reloadItems() {
|
override fun reloadItems() {
|
||||||
viewModel.getTransactions(arguments?.getLong(EXTRA_CATEGORY_ID))
|
viewModel.getTransactions(categoryId = arguments?.getLong(EXTRA_CATEGORY_ID))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun bindData(data: Transaction): BindableData<Transaction> = BindableData(data, TRANSACTION_VIEW)
|
override fun bindData(data: Transaction): BindableData<Transaction> = BindableData(data, TRANSACTION_VIEW)
|
||||||
|
|
|
@ -1,52 +1,106 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<ScrollView
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:id="@+id/categoryDetails"
|
android:id="@+id/categoryDetails"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="match_parent">
|
||||||
android:fillViewport="true">
|
|
||||||
|
|
||||||
<LinearLayout
|
<TextView
|
||||||
|
android:id="@+id/categoryDescription"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical">
|
android:padding="16dp"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:padding="16dp"
|
android:id="@+id/totalLabel"
|
||||||
android:id="@+id/categoryDescription"
|
android:layout_width="0dp"
|
||||||
android:layout_width="match_parent"
|
android:layout_height="wrap_content"
|
||||||
android:layout_height="wrap_content" />
|
android:paddingHorizontal="8dp"
|
||||||
|
android:text="@string/label_total"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textAllCaps="true"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/balanceLabel"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/categoryDescription" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/balanceLabel"
|
android:id="@+id/balanceLabel"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginBottom="8dp"
|
android:paddingHorizontal="8dp"
|
||||||
android:text="@string/label_current_balance"
|
android:text="@string/label_balance"
|
||||||
android:textAlignment="center" />
|
android:textAlignment="center"
|
||||||
|
android:textAllCaps="true"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/remainingLabel"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/totalLabel"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/categoryDescription" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/balance"
|
android:id="@+id/remainingLabel"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="8dp"
|
android:paddingHorizontal="8dp"
|
||||||
android:textAlignment="center"
|
android:text="@string/label_remaining"
|
||||||
android:textSize="36sp" />
|
android:textAlignment="center"
|
||||||
|
android:textAllCaps="true"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/balanceLabel"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/categoryDescription" />
|
||||||
|
|
||||||
<androidx.fragment.app.FragmentContainerView
|
<TextView
|
||||||
android:id="@+id/transactionsFragmentContainer"
|
android:id="@+id/total"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="0dp"
|
||||||
android:layout_height="0dp"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1" />
|
android:padding="8dp"
|
||||||
</LinearLayout>
|
android:textAlignment="center"
|
||||||
</ScrollView>
|
app:layout_constraintEnd_toStartOf="@+id/balance"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/totalLabel" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/balance"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:textAlignment="center"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/remaining"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/total"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/balanceLabel" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/remaining"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:textAlignment="center"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/balance"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/remainingLabel" />
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/categoryProgress"
|
||||||
|
style="?android:attr/progressBarStyleHorizontal"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/total" />
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/transactionsFragmentContainer"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/categoryProgress" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
android:id="@+id/progressBar"
|
android:id="@+id/progressBar"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center" />
|
android:layout_gravity="center" />
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
|
@ -9,9 +9,9 @@
|
||||||
android:icon="@drawable/ic_attach_money_black_24dp"
|
android:icon="@drawable/ic_attach_money_black_24dp"
|
||||||
android:title="@string/title_transactions" />
|
android:title="@string/title_transactions" />
|
||||||
<item
|
<item
|
||||||
android:id="@+id/budgetsFragment"
|
android:id="@+id/categoryListFragment"
|
||||||
android:icon="@drawable/ic_baseline_category_24px"
|
android:icon="@drawable/ic_baseline_category_24px"
|
||||||
android:title="@string/title_budgets" />
|
android:title="@string/title_categories" />
|
||||||
<item
|
<item
|
||||||
android:id="@+id/profileFragment"
|
android:id="@+id/profileFragment"
|
||||||
android:icon="@drawable/ic_person_black_24dp"
|
android:icon="@drawable/ic_person_black_24dp"
|
||||||
|
|
|
@ -55,4 +55,7 @@
|
||||||
<string name="prompt_year">Year</string>
|
<string name="prompt_year">Year</string>
|
||||||
<string name="archived">Archived</string>
|
<string name="archived">Archived</string>
|
||||||
<string name="title_overview">Overview</string>
|
<string name="title_overview">Overview</string>
|
||||||
|
<string name="label_total">Total</string>
|
||||||
|
<string name="label_balance">Balance</string>
|
||||||
|
<string name="label_remaining">Remaining</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Loading…
Reference in a new issue