Skip to content

Commit

Permalink
✨ Feature: opening date
Browse files Browse the repository at this point in the history
  • Loading branch information
lorenzovngl committed Dec 23, 2023
1 parent bebfe70 commit c3d15b1
Show file tree
Hide file tree
Showing 17 changed files with 578 additions and 126 deletions.
57 changes: 48 additions & 9 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,6 @@ android {
vectorDrawables {
useSupportLibrary = true
}
javaCompileOptions {
annotationProcessorOptions {
arguments += mapOf(
"room.schemaLocation" to "$projectDir/schemas",
"room.incremental" to "true"
)
}
}
}

configurations {
Expand Down Expand Up @@ -70,6 +62,10 @@ android {
}
}

sourceSets {
getByName("debug").assets.srcDirs(files("$projectDir/schemas")) // Room
}

compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
Expand All @@ -94,6 +90,21 @@ android {
}
}

class RoomSchemaArgProvider(
@get:InputDirectory
@get:PathSensitive(PathSensitivity.RELATIVE)
val schemaDir: File
) : CommandLineArgumentProvider {

override fun asArguments(): Iterable<String> {
return listOf("room.schemaLocation=${schemaDir.path}")
}
}

ksp {
arg(RoomSchemaArgProvider(File(projectDir, "schemas")))
}

dependencies {

implementation(libs.kotlin.stdlib)
Expand All @@ -102,9 +113,11 @@ dependencies {
implementation(libs.activity.compose)
implementation(libs.androidx.navigation.compose)
testImplementation(libs.junit)
testImplementation(libs.junit.jupiter)
androidTestImplementation(libs.test.core.ktx)
androidTestImplementation(libs.androidx.test.ext.junit)
androidTestImplementation(libs.espresso.core)
androidTestImplementation(libs.androidx.room.testing)
androidTestImplementation(libs.androidx.test.rules)
androidTestImplementation(libs.androidx.test.runner)
androidTestImplementation(libs.androidx.uiautomator)
Expand Down Expand Up @@ -158,4 +171,30 @@ if (!buildFoss){
apply(plugin = "com.google.firebase.crashlytics")
}

apply(plugin = "com.google.dagger.hilt.android")
apply(plugin = "com.google.dagger.hilt.android")


tasks.register<Copy>("copyAPKs") {
from(layout.buildDirectory.dir("outputs/apk")) {
include("**/*.apk")
exclude("androidTest/**")
eachFile {
path = name.replace("-full", "")
.replace("-release", "")
}
includeEmptyDirs = false
}
from(layout.buildDirectory.dir("outputs/bundle")) {
include("**/*-release.aab")
eachFile {
path = name.replace("-full", "")
.replace("-release", "")
}
includeEmptyDirs = false
}
into(layout.projectDirectory.dir("apk"))
}

tasks.register("generateAPKs") {
dependsOn("assembleFullDebug", "copyAPKs")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.lorenzovainigli.foodexpirationdates.model

import androidx.room.testing.MigrationTestHelper
import androidx.test.platform.app.InstrumentationRegistry
import org.junit.Rule
import org.junit.Test

class MigrationTest {

private val TEST_DB = "migration-test"

@JvmField
@Rule
val helper: MigrationTestHelper = MigrationTestHelper(
InstrumentationRegistry.getInstrumentation(),
AppDatabase::class.java
)

@Test
fun migrate1To2() {
helper.createDatabase(TEST_DB, 1).apply {
close()
}
helper.runMigrationsAndValidate(TEST_DB, 2, true)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ class AppModule {
application,
AppDatabase::class.java,
"database.db"
).allowMainThreadQueries().build()
).fallbackToDestructiveMigration()
.fallbackToDestructiveMigrationOnDowngrade()
.allowMainThreadQueries().build()
}

@Provides
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
package com.lorenzovainigli.foodexpirationdates.model

import androidx.room.AutoMigration
import androidx.room.Database
import androidx.room.RoomDatabase
import com.lorenzovainigli.foodexpirationdates.model.dao.ExpirationDatesDao
import com.lorenzovainigli.foodexpirationdates.model.entity.ExpirationDate

@Database(
entities = [ExpirationDate::class],
version = 1
version = 2,
autoMigrations = [
AutoMigration(from = 1, to = 2)
],
exportSchema = true
)
abstract class AppDatabase : RoomDatabase() {
abstract val expirationDatesDao: ExpirationDatesDao
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import com.lorenzovainigli.foodexpirationdates.model.entity.ExpirationDate

@Dao
interface ExpirationDatesDao {
@Query("SELECT * FROM expiration_dates ORDER BY expiration_date")
@Query("SELECT * FROM expiration_dates ORDER BY COALESCE(opening_date, expiration_date)")
fun getAll(): Flow<List<ExpirationDate>>

@Query("SELECT * FROM expiration_dates WHERE id = :id")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,36 @@ package com.lorenzovainigli.foodexpirationdates.model.entity
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import java.util.Calendar

@Entity(tableName = "expiration_dates")
data class ExpirationDate(
@PrimaryKey(autoGenerate = true) var id: Int,
@ColumnInfo(name = "food_name") var foodName: String,
@ColumnInfo(name = "expiration_date") var expirationDate: Long,
)
@ColumnInfo(name = "opening_date") var openingDate: Long? = null,
@ColumnInfo(name = "time_span_days") var timeSpanDays: Int? = null,
)

fun computeExpirationDate(
item: ExpirationDate
): Long {
return computeExpirationDate(item.expirationDate, item.openingDate, item.timeSpanDays)
}

fun computeExpirationDate(
expirationDate: Long,
openingDate: Long? = expirationDate,
timeSpanDays: Int? = 0
): Long {
val expirationByOpeningDate = openingDate?.let {
Calendar.getInstance().apply {
timeInMillis = it
add(Calendar.DAY_OF_MONTH, timeSpanDays!!)
}.time.time
}
return when (expirationByOpeningDate) {
null -> expirationDate
else -> minOf(expirationDate, expirationByOpeningDate)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import androidx.hilt.work.HiltWorker
import androidx.work.CoroutineWorker
import androidx.work.WorkerParameters
import com.lorenzovainigli.foodexpirationdates.R
import com.lorenzovainigli.foodexpirationdates.model.entity.computeExpirationDate
import com.lorenzovainigli.foodexpirationdates.model.repository.ExpirationDateRepository
import com.lorenzovainigli.foodexpirationdates.view.MainActivity
import kotlinx.coroutines.flow.first
Expand All @@ -27,27 +28,31 @@ class CheckExpirationsWorker @Inject constructor(
override suspend fun doWork(): Result {
val sb = StringBuilder()
val today = Calendar.getInstance()
val twoDaysAgo = Calendar.getInstance()
twoDaysAgo.add(Calendar.DAY_OF_MONTH, -2)
val yesterday = Calendar.getInstance()
yesterday.add(Calendar.DAY_OF_MONTH, -1)
val tomorrow = Calendar.getInstance()
tomorrow.add(Calendar.DAY_OF_MONTH, 1)
val twoDaysAgo = Calendar.getInstance().apply {
add(Calendar.DAY_OF_MONTH, -2)
}
val yesterday = Calendar.getInstance().apply {
add(Calendar.DAY_OF_MONTH, -1)
}
val tomorrow = Calendar.getInstance().apply {
add(Calendar.DAY_OF_MONTH, 1)
}
val msInADay = (1000 * 60 * 60 * 24)
val filteredList = repository.getAll().first().filter {
it.expirationDate < tomorrow.time.time
computeExpirationDate(it) < tomorrow.time.time
}
if (filteredList.isEmpty()) {
return Result.success()
}
filteredList.map {
val expDate = computeExpirationDate(it)
sb.append(it.foodName).append(" (")
if (it.expirationDate < twoDaysAgo.time.time) {
val days = (today.time.time - it.expirationDate) / msInADay
if (expDate < twoDaysAgo.time.time) {
val days = (today.time.time - expDate) / msInADay
sb.append(applicationContext.getString(R.string.n_days_ago, days))
} else if (it.expirationDate < yesterday.time.time)
} else if (expDate < yesterday.time.time)
sb.append(applicationContext.getString(R.string.yesterday).lowercase())
else if (it.expirationDate < today.time.time) {
else if (expDate < today.time.time) {
sb.append(applicationContext.getString(R.string.today).lowercase())
} else {
sb.append(applicationContext.getString(R.string.tomorrow).lowercase())
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package com.lorenzovainigli.foodexpirationdates.view.composable

import androidx.compose.foundation.layout.Column
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExposedDropdownMenuBox
import androidx.compose.material3.ExposedDropdownMenuDefaults
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
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.tooling.preview.PreviewLightDark
import com.lorenzovainigli.foodexpirationdates.ui.theme.FoodExpirationDatesTheme

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun Dropdown(
modifier: Modifier = Modifier,
choices: Array<String>,
onChange: (String) -> Unit,
isExpandedStartValue: Boolean = false
) {
var isExpanded by remember {
mutableStateOf(isExpandedStartValue)
}
var choice by remember {
mutableStateOf(choices[0])
}
ExposedDropdownMenuBox(
modifier = modifier,
expanded = isExpanded,
onExpandedChange = {
isExpanded = it
}
) {
TextField(
modifier = Modifier.menuAnchor(),
value = choice,
onValueChange = {},
readOnly = true,
trailingIcon = {
ExposedDropdownMenuDefaults.TrailingIcon(expanded = isExpanded)
},
colors = ExposedDropdownMenuDefaults.textFieldColors()
)
ExposedDropdownMenu(
expanded = isExpanded,
onDismissRequest = {
isExpanded = false
}
) {
choices.forEach {
DropdownMenuItem(
text = {
Text(it)
},
onClick = {
choice = it
onChange(it)
isExpanded = false
}
)
}
}
}
}

@Composable
@PreviewLightDark
fun DropdownPreview() {
FoodExpirationDatesTheme {
Surface {
Column {
val choices =(0..3).map { "Choice $it" }.toTypedArray()
Dropdown(
choices = choices,
onChange = {},
isExpandedStartValue = false
)
Dropdown(
choices = choices,
onChange = {},
isExpandedStartValue = true
)
}
}
}
}
Loading

0 comments on commit c3d15b1

Please sign in to comment.