From 270ff4fa07b28373c0ac618e0ea60546b54004c5 Mon Sep 17 00:00:00 2001 From: Rafal Wisniewski <2krafal.wisniewski@gmail.com> Date: Wed, 6 May 2026 12:47:11 +0200 Subject: [PATCH] fix: add date to filter --- app/build.gradle.kts | 2 +- .../java/cc/n0th1ng/tripmoney/MainActivity.kt | 26 ++- .../n0th1ng/tripmoney/data/dao/ExpenseDao.kt | 21 ++- .../data/repository/ExpenseRepository.kt | 15 +- .../cc/n0th1ng/tripmoney/navigation/TopBar.kt | 89 +--------- .../screens/listexpense/DateTimePicker.kt | 14 +- .../screens/listexpense/FilterDialog.kt | 155 ++++++++++++++++++ .../screens/listexpense/ListExpenseScreen.kt | 11 -- .../cc/n0th1ng/tripmoney/utils/DateUtils.kt | 3 - 9 files changed, 204 insertions(+), 132 deletions(-) create mode 100644 app/src/main/java/cc/n0th1ng/tripmoney/screens/listexpense/FilterDialog.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index a569677..363720b 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -15,7 +15,7 @@ android { } defaultConfig { applicationId = "cc.n0th1ng.tripmoney" - minSdk = 24 + minSdk = 26 targetSdk = 36 versionCode = 1 versionName = "1.0" diff --git a/app/src/main/java/cc/n0th1ng/tripmoney/MainActivity.kt b/app/src/main/java/cc/n0th1ng/tripmoney/MainActivity.kt index 654eef2..ac4c1ba 100644 --- a/app/src/main/java/cc/n0th1ng/tripmoney/MainActivity.kt +++ b/app/src/main/java/cc/n0th1ng/tripmoney/MainActivity.kt @@ -44,6 +44,7 @@ import cc.n0th1ng.tripmoney.viewmodel.SettingsViewModel import cc.n0th1ng.tripmoney.viewmodel.TripViewModel import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.launch +import java.time.LocalDate @AndroidEntryPoint class MainActivity : ComponentActivity() { @@ -57,7 +58,6 @@ class MainActivity : ComponentActivity() { NavigationDrawer() } } - } } @@ -111,14 +111,16 @@ fun NavigationDrawer() { startDestination = if (currentTripId == -1) Screens.TRIP_PICKER else Screens.LIST_EXPENSE, modifier = Modifier.padding(innerPadding) ) { - composable(Screens.LIST_EXPENSE+"?dateToScroll={dateToScroll}", - arguments = listOf(navArgument("dateToScroll"){defaultValue = ""})) { - backStackEntry -> + composable( + Screens.LIST_EXPENSE + "?dateToScroll={dateToScroll}", + arguments = listOf(navArgument("dateToScroll") { defaultValue = "" }) + ) { backStackEntry -> ListExpenseScreen( filter = filter, search = search, initialAutoOpen = shouldTriggerAutoOpen, onAutoOpenConsumed = { hasHandledStartupOpen = true }, - dateToScroll = backStackEntry.arguments?.getString("dateToScroll")?: "") + dateToScroll = backStackEntry.arguments?.getString("dateToScroll") ?: "" + ) } composable(Screens.TRIP_PICKER) { TripPickerScreen(navController) @@ -139,7 +141,9 @@ fun NavigationDrawer() { data class Filter( val categories: List = emptyList(), val startAmount: Double = 0.0, - val endAmount: Double = Double.MAX_VALUE + val endAmount: Double = Double.MAX_VALUE, + val startDate: LocalDate = LocalDate.MIN, + val endDate: LocalDate = LocalDate.MAX ) { fun with(category: Category): Filter { return this.copy(categories = categories + category) @@ -153,11 +157,19 @@ data class Filter( return this.copy(endAmount = amount) } + fun withStartDate(date: LocalDate): Filter { + return this.copy(startDate = date) + } + + fun withEndDate(date: LocalDate): Filter { + return this.copy(endDate = date) + } + fun without(category: Category): Filter { return this.copy(categories = categories - category) } fun isDefault(): Boolean { - return this.categories.isEmpty() && startAmount == 0.0 && endAmount == Double.MAX_VALUE + return this.categories.isEmpty() && startAmount == 0.0 && endAmount == Double.MAX_VALUE && startDate == LocalDate.MIN && endDate == LocalDate.MAX } } \ No newline at end of file diff --git a/app/src/main/java/cc/n0th1ng/tripmoney/data/dao/ExpenseDao.kt b/app/src/main/java/cc/n0th1ng/tripmoney/data/dao/ExpenseDao.kt index 4948ae4..0cec6b1 100644 --- a/app/src/main/java/cc/n0th1ng/tripmoney/data/dao/ExpenseDao.kt +++ b/app/src/main/java/cc/n0th1ng/tripmoney/data/dao/ExpenseDao.kt @@ -40,6 +40,12 @@ interface ExpenseDao { AND ( :endAmount IS NULL OR expense.amount <= :endAmount ) + AND ( + :startDate IS NULL OR expense.datetime >= :startDate + ) + AND ( + :endDate IS NULL OR expense.datetime <= :endDate + ) ORDER BY expense.datetime DESC """ @@ -50,7 +56,9 @@ interface ExpenseDao { categoryIds: List, categoriesEmpty: Boolean, startAmount: Double?, - endAmount: Double? + endAmount: Double?, + startDate: Long?, + endDate: Long? ): PagingSource @Transaction @@ -74,7 +82,12 @@ interface ExpenseDao { AND ( :endAmount IS NULL OR expense.amount <= :endAmount ) - + AND ( + :startDate IS NULL OR expense.datetime >= :startDate + ) + AND ( + :endDate IS NULL OR expense.datetime <= :endDate + ) ORDER BY expense.datetime DESC """ ) @@ -84,7 +97,9 @@ interface ExpenseDao { categoryIds: List, categoriesEmpty: Boolean, startAmount: Double?, - endAmount: Double? + endAmount: Double?, + startDate: Long?, + endDate: Long? ): Flow> @Query( diff --git a/app/src/main/java/cc/n0th1ng/tripmoney/data/repository/ExpenseRepository.kt b/app/src/main/java/cc/n0th1ng/tripmoney/data/repository/ExpenseRepository.kt index b3ddbd1..fdc069e 100644 --- a/app/src/main/java/cc/n0th1ng/tripmoney/data/repository/ExpenseRepository.kt +++ b/app/src/main/java/cc/n0th1ng/tripmoney/data/repository/ExpenseRepository.kt @@ -1,7 +1,5 @@ package cc.n0th1ng.tripmoney.data.repository -import android.os.Build -import androidx.annotation.RequiresApi import androidx.annotation.WorkerThread import androidx.paging.Pager import androidx.paging.PagingConfig @@ -10,9 +8,11 @@ import cc.n0th1ng.tripmoney.Filter import cc.n0th1ng.tripmoney.data.dao.ExpenseDao import cc.n0th1ng.tripmoney.data.entity.Expense import cc.n0th1ng.tripmoney.data.entity.ExpenseDto +import cc.n0th1ng.tripmoney.screens.listexpense.toEpochMilli import cc.n0th1ng.tripmoney.utils.Currencies import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.first +import java.time.LocalDate import javax.inject.Inject class ExpenseRepository @Inject constructor( @@ -49,9 +49,10 @@ class ExpenseRepository @Inject constructor( categoryIds = categoryIds, categoriesEmpty = categoryIds.isEmpty(), startAmount = filter.startAmount, - endAmount = filter.endAmount + endAmount = filter.endAmount, + startDate = if(filter.startDate == LocalDate.MIN) null else filter.startDate.toEpochMilli(), + endDate = if(filter.endDate == LocalDate.MAX) null else filter.endDate.plusDays(1).toEpochMilli(), ) - } ).flow } @@ -62,18 +63,18 @@ class ExpenseRepository @Inject constructor( filter: Filter = Filter() ): Flow> { val categoryIds = filter.categories.map { it.id } - return expenseDao.expenseDto( tripId = tripId, search = search.takeIf { it.isNotBlank() }, categoryIds = categoryIds, categoriesEmpty = categoryIds.isEmpty(), startAmount = filter.startAmount, - endAmount = filter.endAmount + endAmount = filter.endAmount, + startDate = if(filter.startDate == LocalDate.MIN) null else filter.startDate.toEpochMilli(), + endDate = if(filter.endDate == LocalDate.MAX) null else filter.endDate.plusDays(1).toEpochMilli(), ) } - @RequiresApi(Build.VERSION_CODES.O) suspend fun recalculateTripExpenses(tripId: Int) { val expenses = getExpensesDto(tripId).first() expenses.forEach { expenseDto -> diff --git a/app/src/main/java/cc/n0th1ng/tripmoney/navigation/TopBar.kt b/app/src/main/java/cc/n0th1ng/tripmoney/navigation/TopBar.kt index c8b7c6d..2412fa5 100644 --- a/app/src/main/java/cc/n0th1ng/tripmoney/navigation/TopBar.kt +++ b/app/src/main/java/cc/n0th1ng/tripmoney/navigation/TopBar.kt @@ -2,8 +2,6 @@ package cc.n0th1ng.tripmoney.navigation import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.FlowRow import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding @@ -12,11 +10,7 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.filled.Close import androidx.compose.material.icons.filled.Menu -import androidx.compose.material3.AlertDialog -import androidx.compose.material3.Button -import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.FilterChip import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme @@ -44,6 +38,7 @@ import cc.n0th1ng.tripmoney.Filter import cc.n0th1ng.tripmoney.R import cc.n0th1ng.tripmoney.data.entity.Category import cc.n0th1ng.tripmoney.screens.addexpense.categoriesToPreview +import cc.n0th1ng.tripmoney.screens.listexpense.FilterDialog import cc.n0th1ng.tripmoney.theme.TripMoneyTheme import cc.n0th1ng.tripmoney.utils.AllPreviews import com.composables.icons.materialsymbols.outlined.R.drawable @@ -159,71 +154,9 @@ fun TopBar( showFilter = false } ) - - } } -@Composable -fun FilterDialog( - onDismiss: () -> Unit, - onSave: (Filter) -> Unit, - onClear: () -> Unit, - categories: List, - filter: Filter -) { - var filter by remember { mutableStateOf(filter) } - var fromAmountString by remember { mutableStateOf(filter.startAmount.toString()) } - var toAmountString by remember { mutableStateOf(filter.endAmount.toString()) } - AlertDialog( - onDismissRequest = onDismiss, - dismissButton = { - Button( - colors = ButtonDefaults.buttonColors(containerColor = MaterialTheme.colorScheme.secondary), - enabled = true, - onClick = onClear - ) { Text(stringResource(R.string.clear)) } - }, - confirmButton = { - Button( - enabled = true, - onClick = { - onSave( - filter.withStartAmount(fromAmountString.safeToDouble()) - .withEndAmount(toAmountString.safeToDouble()) - ) - }) { Text(stringResource(R.string.save)) } - }, title = { Text("Filter") }, - text = { - Column(verticalArrangement = Arrangement.spacedBy(10.dp)) { - Text(text = "Categories") - FlowRow(horizontalArrangement = Arrangement.spacedBy(7.dp)) { - categories.forEach { - FilterChip(selected = filter.categories.contains(it), onClick = { - filter = if (filter.categories.contains(it)) { - filter.without(it) - } else { - filter.with(it) - } - }, label = { - Row(horizontalArrangement = Arrangement.spacedBy(5.dp)) { - Icon(painterResource(it.icon.resource), contentDescription = null) - Text(text = it.name) - } - }) - } - } - AmountTextField(label = "from", onValueChange = { newText -> - fromAmountString = newText - }, value = fromAmountString) - AmountTextField(label = "to", onValueChange = { newText -> - toAmountString = newText - }, value = toAmountString) - - } - }) -} - @Composable fun AmountTextField(label: String, onValueChange: (String) -> Unit, value: String) { var value by remember { mutableStateOf(value) } @@ -276,24 +209,4 @@ fun PreviewTopBar() { filter = Filter() ) } -} - -@AllPreviews -@Composable -fun PreviewFilterDialog() { - TripMoneyTheme { - FilterDialog( - onDismiss = {}, - onSave = {}, - categories = categoriesToPreview, - filter = Filter(), - onClear = {} - ) - } -} - -private fun String.safeToDouble(): Double { - if (this == "∞") return Double.MAX_VALUE - if (this.isEmpty()) return 0.0 - return this.toDouble() } \ No newline at end of file diff --git a/app/src/main/java/cc/n0th1ng/tripmoney/screens/listexpense/DateTimePicker.kt b/app/src/main/java/cc/n0th1ng/tripmoney/screens/listexpense/DateTimePicker.kt index ba608df..6e2c942 100644 --- a/app/src/main/java/cc/n0th1ng/tripmoney/screens/listexpense/DateTimePicker.kt +++ b/app/src/main/java/cc/n0th1ng/tripmoney/screens/listexpense/DateTimePicker.kt @@ -1,7 +1,5 @@ package cc.n0th1ng.tripmoney.screens.listexpense -import android.os.Build -import androidx.annotation.RequiresApi import androidx.compose.foundation.layout.Row import androidx.compose.material3.AlertDialog import androidx.compose.material3.DatePicker @@ -21,8 +19,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview -import cc.n0th1ng.tripmoney.R.* +import cc.n0th1ng.tripmoney.R.string import cc.n0th1ng.tripmoney.theme.TripMoneyTheme import cc.n0th1ng.tripmoney.utils.AllPreviews import java.time.Instant @@ -31,7 +28,6 @@ import java.time.LocalDateTime import java.time.LocalTime import java.time.ZoneId -@RequiresApi(Build.VERSION_CODES.O) @OptIn(ExperimentalMaterial3Api::class) @Composable fun DateRangePicker( @@ -75,7 +71,6 @@ fun DateRangePicker( } } -@RequiresApi(Build.VERSION_CODES.O) @OptIn(ExperimentalMaterial3Api::class) @Composable fun DatePicker( @@ -117,7 +112,6 @@ fun DatePicker( } } -@RequiresApi(Build.VERSION_CODES.O) @OptIn(ExperimentalMaterial3Api::class) @Composable fun TimePicker( @@ -147,7 +141,6 @@ fun TimePicker( } @Composable -@RequiresApi(Build.VERSION_CODES.O) @OptIn(ExperimentalMaterial3Api::class) fun DateTimePicker( dateTime: LocalDateTime = LocalDateTime.now(), @@ -181,15 +174,12 @@ fun DateTimePicker( } } -@RequiresApi(Build.VERSION_CODES.O) fun LocalDateTime.toEpochMilli(): Long = this.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() -@RequiresApi(Build.VERSION_CODES.O) fun LocalDate.toEpochMilli(): Long = - this.atStartOfDay().atZone(ZoneId.of("UTC")).toInstant().toEpochMilli() + this.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() -@RequiresApi(Build.VERSION_CODES.O) @AllPreviews @Composable fun DatePickerPreview() { diff --git a/app/src/main/java/cc/n0th1ng/tripmoney/screens/listexpense/FilterDialog.kt b/app/src/main/java/cc/n0th1ng/tripmoney/screens/listexpense/FilterDialog.kt new file mode 100644 index 0000000..6d368f6 --- /dev/null +++ b/app/src/main/java/cc/n0th1ng/tripmoney/screens/listexpense/FilterDialog.kt @@ -0,0 +1,155 @@ +package cc.n0th1ng.tripmoney.screens.listexpense + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.FlowRow +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.sizeIn +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.AlertDialog +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.FilterChip +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import cc.n0th1ng.tripmoney.Filter +import cc.n0th1ng.tripmoney.R +import cc.n0th1ng.tripmoney.data.entity.Category +import cc.n0th1ng.tripmoney.navigation.AmountTextField +import cc.n0th1ng.tripmoney.screens.addexpense.categoriesToPreview +import cc.n0th1ng.tripmoney.theme.TripMoneyTheme +import cc.n0th1ng.tripmoney.utils.AllPreviews +import cc.n0th1ng.tripmoney.utils.pretty +import java.time.LocalDate + +@Composable +fun FilterDialog( + onDismiss: () -> Unit, + onSave: (Filter) -> Unit, + onClear: () -> Unit, + categories: List, + filter: Filter +) { + var filter by remember { mutableStateOf(filter) } + var fromAmountString by remember { mutableStateOf(filter.startAmount.toString()) } + var toAmountString by remember { mutableStateOf(filter.endAmount.toString()) } + AlertDialog( + onDismissRequest = onDismiss, + dismissButton = { + Button( + colors = ButtonDefaults.buttonColors(containerColor = MaterialTheme.colorScheme.secondary), + enabled = true, + onClick = onClear + ) { Text(stringResource(R.string.clear)) } + }, + confirmButton = { + Button( + enabled = true, + onClick = { + onSave(filter) + }) { Text(stringResource(R.string.save)) } + }, title = { Text("Filter") }, + text = { + var showDatePicker by remember { mutableStateOf(false) } + var startDate by remember { + mutableStateOf(filter.startDate) + } + var endDate by remember { + mutableStateOf(filter.endDate) + } + Column(verticalArrangement = Arrangement.spacedBy(10.dp)) { + Text(text = "Categories") + FlowRow( + horizontalArrangement = Arrangement.spacedBy(7.dp), + modifier = Modifier + .sizeIn(maxHeight = 200.dp) + .verticalScroll(rememberScrollState()) + ) { + categories.forEach { + FilterChip(selected = filter.categories.contains(it), onClick = { + filter = if (filter.categories.contains(it)) { + filter.without(it) + } else { + filter.with(it) + } + }, label = { + Row(horizontalArrangement = Arrangement.spacedBy(5.dp)) { + Icon(painterResource(it.icon.resource), contentDescription = null) + Text(text = it.name) + } + }) + } + } + Button( + modifier = Modifier + .fillMaxWidth(1f), + shape = MaterialTheme.shapes.medium, + onClick = { showDatePicker = true }) { + val startDateFormatted = startDate.pretty() + val endDateFormatted = endDate.pretty() + Text( + text = + if(startDate == LocalDate.MIN && endDate == LocalDate.MAX) "Show all dates" else + "$startDateFormatted - $endDateFormatted", + fontSize = 17.sp + ) + } + AmountTextField(label = "from", onValueChange = { newText -> + fromAmountString = newText + filter = filter.withStartAmount(newText.safeToDouble()) + }, value = fromAmountString) + AmountTextField(label = "to", onValueChange = { newText -> + toAmountString = newText + filter = filter.withEndAmount(newText.safeToDouble()) + }, value = toAmountString) + } + + if (showDatePicker) { + DateRangePicker( + startDate = if(startDate == LocalDate.MIN) LocalDate.now() else startDate, + endDate = if(endDate == LocalDate.MAX) LocalDate.now() else endDate, + onDismiss = { showDatePicker = false }, + onConfirm = { newStartDate, newEndDate -> + startDate = newStartDate + endDate = newEndDate + filter = filter.withStartDate(startDate).withEndDate(endDate) + showDatePicker = false + }) + } + }) +} + + +@AllPreviews +@Composable +fun PreviewFilterDialog() { + TripMoneyTheme { + FilterDialog( + onDismiss = {}, + onSave = {}, + categories = categoriesToPreview.plus(categoriesToPreview).plus(categoriesToPreview), + filter = Filter(), + onClear = {} + ) + } +} + + +private fun String.safeToDouble(): Double { + if (this == "∞") return Double.MAX_VALUE + if (this.isEmpty()) return 0.0 + return this.toDouble() +} \ No newline at end of file diff --git a/app/src/main/java/cc/n0th1ng/tripmoney/screens/listexpense/ListExpenseScreen.kt b/app/src/main/java/cc/n0th1ng/tripmoney/screens/listexpense/ListExpenseScreen.kt index 662b3b6..0c9bdd0 100644 --- a/app/src/main/java/cc/n0th1ng/tripmoney/screens/listexpense/ListExpenseScreen.kt +++ b/app/src/main/java/cc/n0th1ng/tripmoney/screens/listexpense/ListExpenseScreen.kt @@ -1,8 +1,6 @@ package cc.n0th1ng.tripmoney.screens.listexpense import android.annotation.SuppressLint -import android.os.Build -import androidx.annotation.RequiresApi import androidx.compose.foundation.background import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.layout.Arrangement @@ -85,7 +83,6 @@ import java.time.format.DateTimeFormatter import kotlin.random.Random -@RequiresApi(Build.VERSION_CODES.O) @Composable fun ListExpenseScreen( filter: Filter, @@ -124,7 +121,6 @@ fun ListExpenseScreen( @OptIn(ExperimentalMaterial3Api::class) @SuppressLint("UnusedMaterial3ScaffoldPaddingParameter") -@RequiresApi(Build.VERSION_CODES.O) @Composable fun ListExpenseScreen( currentTrip: Trip?, @@ -286,7 +282,6 @@ fun ListExpenseScreen( } -@RequiresApi(Build.VERSION_CODES.O) @Composable fun CustomDivider(date: LocalDate, sum: Double, currency: String) { Row( @@ -329,7 +324,6 @@ fun CustomDivider(date: LocalDate, sum: Double, currency: String) { } } -@RequiresApi(Build.VERSION_CODES.O) @Composable fun SwipeToDeleteExpenseCard( expenseDto: ExpenseDto, @@ -422,7 +416,6 @@ fun DeleteConfirmationDialog( } } -@RequiresApi(Build.VERSION_CODES.O) @Composable fun ExpenseCard( expenseDto: ExpenseDto, @@ -523,7 +516,6 @@ fun ExpenseCard( } } -@RequiresApi(Build.VERSION_CODES.O) @AllPreviews @Composable fun PreviewListExpenseScreen() { @@ -550,7 +542,6 @@ fun PreviewListExpenseScreen() { } } -@RequiresApi(Build.VERSION_CODES.O) @AllPreviews @Composable fun PreviewListExpenseScreenWithoutExpenses() { @@ -577,7 +568,6 @@ fun PreviewListExpenseScreenWithoutExpenses() { } } -@RequiresApi(Build.VERSION_CODES.O) @AllPreviews @Composable fun PreviewListExpenseScreenWithoutTrip() { @@ -609,7 +599,6 @@ fun PreviewDeleteConfirmationDialog() { } -@RequiresApi(Build.VERSION_CODES.O) private fun sampleExpenseDtoWithConvertedAmountList(): List { val sampleCategories = listOf( Category( diff --git a/app/src/main/java/cc/n0th1ng/tripmoney/utils/DateUtils.kt b/app/src/main/java/cc/n0th1ng/tripmoney/utils/DateUtils.kt index 626cba8..30fd399 100644 --- a/app/src/main/java/cc/n0th1ng/tripmoney/utils/DateUtils.kt +++ b/app/src/main/java/cc/n0th1ng/tripmoney/utils/DateUtils.kt @@ -1,11 +1,8 @@ package cc.n0th1ng.tripmoney.utils -import android.os.Build -import androidx.annotation.RequiresApi import java.time.LocalDate import java.time.format.DateTimeFormatter -@RequiresApi(Build.VERSION_CODES.O) fun LocalDate.pretty(): String { return this.format(DateTimeFormatter.ofPattern("dd MMM yyyy")) } \ No newline at end of file