From 7d865a3d6da7bec7ac6e21cd21ac9a37d22b8031 Mon Sep 17 00:00:00 2001 From: Oqba Date: Wed, 28 Oct 2026 08:51:47 +0330 Subject: [PATCH] =?UTF-8?q?=D8=A7=D8=B1=D8=AA=D9=82=D8=A7=20=D8=A8=D9=87?= =?UTF-8?q?=20=D9=86=D8=B3=D8=AE=D9=87=201.1.3=20=D9=88=20=D8=A8=D9=87?= =?UTF-8?q?=DB=8C=D9=86=D9=87=E2=80=8C=D8=B3=D8=A7=D8=B2=DB=8C=20=D9=85?= =?UTF-8?q?=D8=AD=D8=A7=D8=B3=D8=A8=D8=A7=D8=AA=20=D9=85=D8=A7=D9=87=20?= =?UTF-8?q?=D8=AC=D8=A7=D8=B1=DB=8C=20=D9=88=20=D8=AA=D8=A7=D8=B1=DB=8C?= =?UTF-8?q?=D8=AE=20=D8=B4=D9=85=D8=B3=DB=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 4 +-- .../ui/screens/PersonScreen.kt | 13 +++++++++ .../monthlypaymentapp/utils/ShamsiUtils.kt | 29 +++++++++++++++++++ .../viewmodel/PersonViewModel.kt | 21 +++++++++----- .../monthlypaymentapp/viewmodel/UiModels.kt | 1 + 5 files changed, 59 insertions(+), 9 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 34c9165..0318805 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -30,8 +30,8 @@ android { applicationId = "com.oqba26.monthlypaymentapp" minSdk = 25 targetSdk = 34 - versionCode = 13 - versionName = "1.1.2" + versionCode = 14 + versionName = "1.1.3" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" vectorDrawables { useSupportLibrary = true } } diff --git a/app/src/main/java/com/oqba26/monthlypaymentapp/ui/screens/PersonScreen.kt b/app/src/main/java/com/oqba26/monthlypaymentapp/ui/screens/PersonScreen.kt index 05eb1ad..484bfd1 100644 --- a/app/src/main/java/com/oqba26/monthlypaymentapp/ui/screens/PersonScreen.kt +++ b/app/src/main/java/com/oqba26/monthlypaymentapp/ui/screens/PersonScreen.kt @@ -1114,6 +1114,19 @@ fun DashboardCard( Text("${formatNumberAsPersian(data.totalIncome)} تومان", style = MaterialTheme.typography.bodyMedium, fontWeight = FontWeight.Bold) } + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = if (isMosqueCategory) "مجموع کمک‌های جمع‌آوری شده دوره جاری" else "مجموع حقوق جمع‌آوری شده دوره جاری", + style = MaterialTheme.typography.titleSmall, + fontWeight = FontWeight.Bold + ) + Text("${formatNumberAsPersian(data.totalCycleIncome)} تومان", style = MaterialTheme.typography.bodyMedium, fontWeight = FontWeight.Bold) + } + if (financialReportData.totalOverdueDebt > 0 || financialReportData.debtors.isNotEmpty()) { HorizontalDivider(modifier = Modifier.padding(vertical = 2.dp)) diff --git a/app/src/main/java/com/oqba26/monthlypaymentapp/utils/ShamsiUtils.kt b/app/src/main/java/com/oqba26/monthlypaymentapp/utils/ShamsiUtils.kt index 676d946..7a8996e 100644 --- a/app/src/main/java/com/oqba26/monthlypaymentapp/utils/ShamsiUtils.kt +++ b/app/src/main/java/com/oqba26/monthlypaymentapp/utils/ShamsiUtils.kt @@ -30,3 +30,32 @@ fun formatTimestampToPersianDateTime(timestamp: Long): String { val time = formatTimestampToPersianTime(timestamp) return "$date، ساعت $time" } + +fun isTimestampInCurrentCycle(timestamp: Long): Boolean { + val now = PersianDate() + val curYear = now.shYear + val curMonth = now.shMonth + val curDay = now.shDay + + val (startYear, startMonth) = if (curDay >= 20) { + curYear to curMonth + } else { + if (curMonth == 1) (curYear - 1) to 12 else curYear to (curMonth - 1) + } + + val (endYear, endMonth) = if (startMonth == 12) { + (startYear + 1) to 1 + } else { + startYear to (startMonth + 1) + } + + val recordDate = PersianDate(Date(timestamp)) + val rYear = recordDate.shYear + val rMonth = recordDate.shMonth + val rDay = recordDate.shDay + + val isFirstHalf = (rYear == startYear && rMonth == startMonth && rDay >= 20) + val isSecondHalf = (rYear == endYear && rMonth == endMonth && rDay < 20) + + return isFirstHalf || isSecondHalf +} diff --git a/app/src/main/java/com/oqba26/monthlypaymentapp/viewmodel/PersonViewModel.kt b/app/src/main/java/com/oqba26/monthlypaymentapp/viewmodel/PersonViewModel.kt index 9a04706..a59804b 100644 --- a/app/src/main/java/com/oqba26/monthlypaymentapp/viewmodel/PersonViewModel.kt +++ b/app/src/main/java/com/oqba26/monthlypaymentapp/viewmodel/PersonViewModel.kt @@ -14,6 +14,7 @@ import com.oqba26.monthlypaymentapp.utils.getCurrentShamsiDay import com.oqba26.monthlypaymentapp.utils.getCurrentShamsiMonth import com.oqba26.monthlypaymentapp.utils.getCurrentShamsiYear import com.oqba26.monthlypaymentapp.utils.getPersianMonthName +import com.oqba26.monthlypaymentapp.utils.isTimestampInCurrentCycle import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.coroutineScope @@ -69,9 +70,6 @@ class PersonViewModel @Inject constructor( private val _infoMessage = MutableSharedFlow() val infoMessage = _infoMessage.asSharedFlow() - val isOperatorMode: StateFlow = settingsRepository.isOperatorModeFlow - .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000L), false) - private val _uiState = MutableStateFlow(PersonListUiState()) val uiState: StateFlow = _uiState.asStateFlow() @@ -248,13 +246,13 @@ class PersonViewModel @Inject constructor( ) } - updateDashboard(uiModels.size, relevantPayments) + val categoryPayments = allPayments.filter { it.category == category } + updateDashboard(uiModels.size, relevantPayments, categoryPayments) val (paidModels, unpaidModels) = uiModels.partition { it.hasPaidThisMonth } // محاسبه گزارشات مالی جامع val personsMap = persons.associateBy { it.id } - val categoryPayments = allPayments.filter { it.category == category } val totalAllTimeIncome = categoryPayments.sumOf { it.amount } val debtorsList = unpaidModels.filter { it.debtCount > 0 }.map { personModel -> @@ -590,11 +588,20 @@ class PersonViewModel @Inject constructor( exportManager.shareReceipt(payment, personName) } - private fun updateDashboard(totalPersonCount: Int, paymentsThisMonth: List) { + private fun updateDashboard( + totalPersonCount: Int, + paymentsThisMonth: List, + categoryPayments: List + ) { val paidCount = paymentsThisMonth.map { it.personId }.distinct().size val totalIncome = paymentsThisMonth.sumOf { it.amount } + val cyclePayments = categoryPayments.filter { payment -> + val time = payment.createdAt ?: payment.timestamp + isTimestampInCurrentCycle(time) + } + val totalCycleIncome = cyclePayments.sumOf { it.amount } val progress = if (totalPersonCount > 0) paidCount.toFloat() / totalPersonCount.toFloat() else 0f - _dashboardData.value = DashboardUiModel(paidCount, totalPersonCount, totalIncome, progress) + _dashboardData.value = DashboardUiModel(paidCount, totalPersonCount, totalIncome, totalCycleIncome, progress) } private fun createPaymentRecord(personId: String, month: Int, year: Int, amount: Double, description: String): PaymentRecord { diff --git a/app/src/main/java/com/oqba26/monthlypaymentapp/viewmodel/UiModels.kt b/app/src/main/java/com/oqba26/monthlypaymentapp/viewmodel/UiModels.kt index 857404b..a27d0b2 100644 --- a/app/src/main/java/com/oqba26/monthlypaymentapp/viewmodel/UiModels.kt +++ b/app/src/main/java/com/oqba26/monthlypaymentapp/viewmodel/UiModels.kt @@ -143,6 +143,7 @@ data class DashboardUiModel( val paidCount: Int = 0, val totalCount: Int = 0, val totalIncome: Double = 0.0, + val totalCycleIncome: Double = 0.0, val progress: Float = 0f )