Update Category details page

This commit is contained in:
William Brawner 2020-08-07 16:56:45 -07:00
parent 2146a38bb2
commit a1da7582b4
9 changed files with 126 additions and 43 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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