diff --git a/app/build.gradle b/app/build.gradle index 6355508..d95eb3d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -41,6 +41,8 @@ android { minifyEnabled true shrinkResources true proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + applicationIdSuffix '.release' + versionNameSuffix 'release' } } compileOptions { @@ -64,6 +66,7 @@ android { } } namespace 'com.sockenklaus.batterytracker' + flavorDimensions } dependencies { diff --git a/app/src/main/java/com/sockenklaus/batterytracker/room/dao/ChargeDao.kt b/app/src/main/java/com/sockenklaus/batterytracker/room/dao/ChargeDao.kt index 8fa8846..dedfb41 100644 --- a/app/src/main/java/com/sockenklaus/batterytracker/room/dao/ChargeDao.kt +++ b/app/src/main/java/com/sockenklaus/batterytracker/room/dao/ChargeDao.kt @@ -26,6 +26,6 @@ interface ChargeDao { @Query("SELECT * FROM batteries WHERE id = :id") fun getBatteryAndCharges(id: Int): Flow - @Query("SELECT * FROM charges WHERE battery_id = :id ORDER BY date DESC") + @Query("SELECT * FROM charges WHERE battery_id = :id ORDER BY created_at DESC") fun getChargesByBatteryId(id: Int): Flow> } \ No newline at end of file diff --git a/app/src/main/java/com/sockenklaus/batterytracker/ui/BatteryTracker.kt b/app/src/main/java/com/sockenklaus/batterytracker/ui/BatteryTracker.kt index f2aeee3..c4dbf98 100644 --- a/app/src/main/java/com/sockenklaus/batterytracker/ui/BatteryTracker.kt +++ b/app/src/main/java/com/sockenklaus/batterytracker/ui/BatteryTracker.kt @@ -37,6 +37,10 @@ fun BatteryTracker() { val state: MainViewModel = viewModel() state.init() + /** + * TODO Is there a smarter way to work with Scaffold? Is it possible to change the + * components of the Scaffold from within the composables? + */ Scaffold( scaffoldState = state.scaffoldState, @@ -67,20 +71,6 @@ fun BatteryTracker() { route = Routes.HOME, state = state, ) - - NavListItem( - icon = Icons.Default.BatteryChargingFull, - textId = R.string.nav_add_charge, - route = Routes.ADD_CHARGE, - state = state, - ) - - NavListItem( - icon = Icons.Default.BatteryFull, - textId = R.string.nav_add_battery, - route = Routes.ADD_BATTERY, - state = state, - ) } ) { NavHost( @@ -92,9 +82,23 @@ fun BatteryTracker() { state.currentScreen = Routes.HOME Home(state.navController) } - composable(Routes.ADD_CHARGE) { - state.currentScreen = Routes.ADD_CHARGE - AddCharge(state.navController) + composable( + route = Routes.ADD_CHARGE + ){ + AddCharge( + navController = state.navController + ) + } + composable( + route = "${Routes.ADD_CHARGE}/{batteryId}", + arguments = listOf(navArgument("batteryId"){ type = NavType.IntType }) + ) { + val id = it.arguments?.getInt("batteryId") + state.currentScreen = "${Routes.ADD_CHARGE} for Battery ${state.getBatteryName(id = id)}" + AddCharge( + batteryId = id, + navController = state.navController + ) } composable(Routes.ADD_BATTERY) { state.currentScreen = Routes.ADD_BATTERY @@ -107,7 +111,8 @@ fun BatteryTracker() { val id = navBackStackEntry.arguments?.getInt("batteryId") state.currentScreen = Routes.BATTERY_DETAILS + ": " + state.getBatteryName(id = id) BatteryDetails( - batteryId = id, + batteryId = id , + navController = state.navController ) } } diff --git a/app/src/main/java/com/sockenklaus/batterytracker/ui/composables/AddCharge.kt b/app/src/main/java/com/sockenklaus/batterytracker/ui/composables/AddCharge.kt index b8c33bb..0168784 100644 --- a/app/src/main/java/com/sockenklaus/batterytracker/ui/composables/AddCharge.kt +++ b/app/src/main/java/com/sockenklaus/batterytracker/ui/composables/AddCharge.kt @@ -35,7 +35,10 @@ import java.util.* @OptIn(ExperimentalMaterialApi::class) @Composable -fun AddCharge(navController: NavController){ +fun AddCharge( + batteryId: Int? = null, + navController: NavController +){ val outerPadding = 16.dp val innerPadding = 16.dp @@ -43,6 +46,12 @@ fun AddCharge(navController: NavController){ val model: AddChargeViewModel = viewModel() val batteries by model.batteries.observeAsState(emptyList()) + if(batteryId != null && batteries.any { it.id == batteryId }) { + model.batteryName = TextFieldValue( + text = batteries.find { it.id == batteryId }!!.name + ) + } + Column( Modifier.padding(outerPadding) ) { @@ -51,11 +60,12 @@ fun AddCharge(navController: NavController){ onExpandedChange = { bIdExpanded = !bIdExpanded} ) { - val filteringOptions = batteries.filter { it.name.contains(model.batteryId.text, ignoreCase = true)} + val filteringOptions = batteries.filter { it.name.contains(model.batteryName.text, ignoreCase = true)} OutlinedTextField( - value = model.batteryId, + enabled = batteryId == null, + value = model.batteryName, onValueChange = { - model.batteryId = it + model.batteryName = it model.batteryHasError = false model.batteryHelper = R.string.helper_required bIdExpanded = filteringOptions.size > 1 @@ -82,7 +92,7 @@ fun AddCharge(navController: NavController){ for (filteringOption in filteringOptions) { DropdownMenuItem( onClick = { - model.batteryId = TextFieldValue( + model.batteryName = TextFieldValue( text = filteringOption.name, selection = TextRange(filteringOption.name.length) ) @@ -134,11 +144,11 @@ fun AddCharge(navController: NavController){ ExtendedFloatingActionButton( text = { Text(stringResource(R.string.button_save_charge)) }, onClick = { - if(!batteries.any{ it.name == model.batteryId.text }){ + if(!batteries.any{ it.name == model.batteryName.text }){ model.batteryHasError = true model.batteryHelper = R.string.helper_battery_not_found } - if(model.batteryId.text.isBlank()){ + if(model.batteryName.text.isBlank()){ model.batteryHasError = true model.batteryHelper = R.string.helper_required } @@ -146,8 +156,12 @@ fun AddCharge(navController: NavController){ model.chargeHasError = true } - if(!model.batteryHasError && !model.chargeHasError && model.saveCharge(batteries, model.batteryId.text, model.charge, model.date)){ - navController.navigate(Routes.HOME) + if(!model.batteryHasError && !model.chargeHasError && model.saveCharge(batteries, model.batteryName.text, model.charge, model.date)){ + val id = model.getBatId( + batteries, + model.batteryName.text + ) + navController.navigate("${Routes.BATTERY_DETAILS}/${id}") } }, icon = { Icon(Icons.Default.Save, "Icon Save") }, diff --git a/app/src/main/java/com/sockenklaus/batterytracker/ui/composables/BatteryDetails.kt b/app/src/main/java/com/sockenklaus/batterytracker/ui/composables/BatteryDetails.kt index 55fc7c4..6002d3d 100644 --- a/app/src/main/java/com/sockenklaus/batterytracker/ui/composables/BatteryDetails.kt +++ b/app/src/main/java/com/sockenklaus/batterytracker/ui/composables/BatteryDetails.kt @@ -1,19 +1,21 @@ package com.sockenklaus.batterytracker.ui.composables -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.lazy.items import androidx.compose.material.* import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.ArrowBack import androidx.compose.runtime.* -import androidx.compose.runtime.livedata.observeAsState +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.NavController +import com.sockenklaus.batterytracker.R import com.sockenklaus.batterytracker.room.entities.Battery import com.sockenklaus.batterytracker.room.entities.Charge import com.sockenklaus.batterytracker.ui.AppBarTitle @@ -26,14 +28,16 @@ import java.util.* @OptIn(ExperimentalMaterialApi::class) @Composable fun BatteryDetails( - batteryId: Int? = null + batteryId: Int?, + navController: NavController ){ val model: BatteryDetailsViewModel = viewModel() val battery by model.battery.collectAsState(Battery(name = "")) val charges: List by model.charges.collectAsState(emptyList()) - Column( - modifier = Modifier.padding(bottom = 16.dp) + Box( + modifier = Modifier + .fillMaxSize() ){ val outputFormat = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).withLocale(Locale.GERMANY) @@ -50,8 +54,17 @@ fun BatteryDetails( Divider(Modifier.padding(horizontal = 16.dp)) } } - + ExtendedFloatingActionButton( + text = { Text(stringResource(R.string.add_charge)) }, + onClick = { + navController.navigate("${Routes.ADD_CHARGE}/${battery.id}") + }, + icon = { Icon(Icons.Default.Add, "Icon Add") }, + modifier = Modifier.align(Alignment.BottomEnd) + .padding(16.dp) + ) } + } @OptIn(ExperimentalMaterialApi::class) @@ -76,6 +89,6 @@ fun DetailsTopAppBar( ) { Icon(Icons.Default.ArrowBack, null) } - } + }, ) } \ No newline at end of file diff --git a/app/src/main/java/com/sockenklaus/batterytracker/ui/composables/Home.kt b/app/src/main/java/com/sockenklaus/batterytracker/ui/composables/Home.kt index 182be79..9481f75 100644 --- a/app/src/main/java/com/sockenklaus/batterytracker/ui/composables/Home.kt +++ b/app/src/main/java/com/sockenklaus/batterytracker/ui/composables/Home.kt @@ -1,6 +1,5 @@ package com.sockenklaus.batterytracker.ui.composables -import android.inputmethodservice.Keyboard import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn @@ -8,9 +7,13 @@ import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.lazy.items import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.* +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Add import androidx.compose.runtime.* import androidx.compose.runtime.livedata.observeAsState +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.unit.dp @@ -33,47 +36,63 @@ fun Home( val filteredList = batteries.filter { it.name.contains(filterText, ignoreCase = true) } - Column( - modifier = Modifier.padding(bottom = 16.dp) - ) { - MyOutlinedTextFieldWithSuffix( - value = filterText, - onValueChange = { filterText = it }, - labelId = R.string.hint_filter_batteries, - modifier = Modifier.padding( - top = 16.dp, - start = 16.dp, - end = 16.dp - ) - .fillMaxWidth(), - singleLine = true, - keyboardOptions = KeyboardOptions( - imeAction = ImeAction.Search - ) - ) - - LazyColumn( - state = LazyListState(), + Box( + modifier = Modifier.fillMaxSize() + ){ + Column( + modifier = Modifier + .padding(bottom = 16.dp) + .fillMaxHeight() ) { - items(filteredList){ battery -> - ListItem( - text = { - ListPrimaryText(battery) - }, - secondaryText = { - ListSecondaryText( - min = model.getMinChargeById(battery.id), - avg = model.getAvgChargeById(battery.id), - max = model.getMaxChargeById(battery.id) - ) - }, - modifier = Modifier.clickable { - navController.navigate("${Routes.BATTERY_DETAILS}/${battery.id}") - } + MyOutlinedTextFieldWithSuffix( + value = filterText, + onValueChange = { filterText = it }, + labelId = R.string.hint_filter_batteries, + modifier = Modifier + .padding( + top = 16.dp, + start = 16.dp, + end = 16.dp + ) + .fillMaxWidth(), + singleLine = true, + keyboardOptions = KeyboardOptions( + imeAction = ImeAction.Search ) - Divider(Modifier.padding(horizontal = 16.dp)) + ) + + LazyColumn( + state = LazyListState(), + ) { + items(filteredList){ battery -> + ListItem( + text = { + ListPrimaryText(battery) + }, + secondaryText = { + ListSecondaryText( + min = model.getMinChargeById(battery.id), + avg = model.getAvgChargeById(battery.id), + max = model.getMaxChargeById(battery.id) + ) + }, + modifier = Modifier.clickable { + navController.navigate("${Routes.BATTERY_DETAILS}/${battery.id}") + } + ) + Divider(Modifier.padding(horizontal = 16.dp)) + } } } + ExtendedFloatingActionButton( + text = { Text(stringResource(R.string.nav_add_battery)) }, + icon = { Icon(Icons.Default.Add, contentDescription = "Add Battery") }, + onClick = { + navController.navigate(Routes.ADD_BATTERY) + }, + modifier = Modifier.padding(16.dp) + .align(Alignment.BottomEnd) + ) } } diff --git a/app/src/main/java/com/sockenklaus/batterytracker/ui/models/AddChargeViewModel.kt b/app/src/main/java/com/sockenklaus/batterytracker/ui/models/AddChargeViewModel.kt index 101da50..540cc4d 100644 --- a/app/src/main/java/com/sockenklaus/batterytracker/ui/models/AddChargeViewModel.kt +++ b/app/src/main/java/com/sockenklaus/batterytracker/ui/models/AddChargeViewModel.kt @@ -1,7 +1,6 @@ package com.sockenklaus.batterytracker.ui.models import android.app.Application -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue @@ -23,7 +22,7 @@ class AddChargeViewModel(application: Application) : AndroidViewModel(applicatio private val db = BatteryTrackerDB.getInstance(application) var batteries: LiveData> = db.batteryDao().getBatteries().asLiveData() - var batteryId by mutableStateOf(TextFieldValue("")) + var batteryName by mutableStateOf(TextFieldValue("")) var date: LocalDate by mutableStateOf(LocalDate.now()) var charge by mutableStateOf("") @@ -32,6 +31,14 @@ class AddChargeViewModel(application: Application) : AndroidViewModel(applicatio var chargeHasError by mutableStateOf(false) + fun getBatId( + batteries: List, + name: String + ) : Int? { + + return batteries.find { it.name == name }?.id + } + fun saveCharge( batteryList: List, batteryName: String, diff --git a/app/src/main/java/com/sockenklaus/batterytracker/ui/models/BatteryDetailsViewModel.kt b/app/src/main/java/com/sockenklaus/batterytracker/ui/models/BatteryDetailsViewModel.kt index 36e2dd5..0c90647 100644 --- a/app/src/main/java/com/sockenklaus/batterytracker/ui/models/BatteryDetailsViewModel.kt +++ b/app/src/main/java/com/sockenklaus/batterytracker/ui/models/BatteryDetailsViewModel.kt @@ -7,9 +7,6 @@ import com.sockenklaus.batterytracker.room.entities.Battery import com.sockenklaus.batterytracker.room.entities.Charge import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.collect -import kotlinx.coroutines.flow.flow -import kotlinx.coroutines.launch class BatteryDetailsViewModel( application: Application, diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ed933cb..f3b96f0 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -11,7 +11,7 @@ Navigation Home - Add Charge + Add Charge Add Battery Battery ID