diff --git a/app/build.gradle b/app/build.gradle
index 3e32da3..6931e79 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -67,39 +67,46 @@ android {
dependencies {
implementation 'androidx.room:room-runtime:2.4.2'
- implementation "androidx.compose.ui:ui:1.3.0-alpha01"
- implementation "androidx.compose.ui:ui-tooling-preview:1.3.0-alpha01"
- implementation 'androidx.compose.material:material-icons-extended:1.3.0-alpha01'
- implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.5.0'
- kapt 'androidx.room:room-compiler:2.4.2'
-
implementation 'androidx.room:room-rxjava3:2.4.2'
implementation "androidx.room:room-paging:2.4.2"
implementation "androidx.room:room-ktx:2.4.2"
+ kapt 'androidx.room:room-compiler:2.4.2'
+
+ implementation "androidx.compose.ui:ui:1.3.0-alpha01"
+ implementation "androidx.compose.ui:ui-tooling-preview:1.3.0-alpha01"
+ implementation 'androidx.compose.material:material-icons-extended:1.3.0-alpha01'
+ implementation 'androidx.compose.material:material:1.3.0-alpha01'
+ implementation 'androidx.compose.runtime:runtime-livedata:1.1.1'
+ implementation 'androidx.compose.animation:animation:1.3.0-alpha01'
+ implementation 'androidx.compose.ui:ui-tooling:1.3.0-alpha01'
+ androidTestImplementation 'androidx.compose.ui:ui-test-junit4:1.3.0-alpha01'
+ debugImplementation "androidx.compose.ui:ui-test-manifest:1.1.1"
+
+ implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.5.0'
+ implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.5.0'
+ implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.0'
+ implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.5.0'
+
implementation 'com.google.android.material:material:1.7.0-alpha03'
+ implementation 'com.google.android.material:compose-theme-adapter:1.1.14'
implementation 'androidx.core:core-ktx:1.8.0'
implementation 'androidx.appcompat:appcompat:1.4.2'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation "androidx.constraintlayout:constraintlayout-compose:1.0.1"
- implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.5.0'
- implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.0'
+
implementation 'androidx.navigation:navigation-fragment-ktx:2.5.0'
implementation 'androidx.navigation:navigation-ui-ktx:2.5.0'
+ implementation "androidx.navigation:navigation-compose:2.5.0"
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.activity:activity-compose:1.5.0'
- implementation 'androidx.compose.material:material:1.3.0-alpha01'
- implementation 'androidx.compose.animation:animation:1.3.0-alpha01'
- implementation 'androidx.compose.ui:ui-tooling:1.3.0-alpha01'
- implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.5.0'
- implementation 'com.google.android.material:compose-theme-adapter:1.1.14'
testImplementation 'junit:junit:4.13.2'
- androidTestImplementation 'androidx.compose.ui:ui-test-junit4:1.3.0-alpha01'
+
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
- debugImplementation "androidx.compose.ui:ui-test-manifest:1.1.1"
+
}
\ No newline at end of file
diff --git a/app/schemas/com.sockenklaus.batterytracker.room.BatteryTrackerDB/4.json b/app/schemas/com.sockenklaus.batterytracker.room.BatteryTrackerDB/4.json
new file mode 100644
index 0000000..4776a0d
--- /dev/null
+++ b/app/schemas/com.sockenklaus.batterytracker.room.BatteryTrackerDB/4.json
@@ -0,0 +1,149 @@
+{
+ "formatVersion": 1,
+ "database": {
+ "version": 4,
+ "identityHash": "e86f0253ec49cbc67a601f90d5169a8a",
+ "entities": [
+ {
+ "tableName": "charges",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `charge` REAL NOT NULL, `battery_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `comment` TEXT NOT NULL DEFAULT '', `created_at` INTEGER NOT NULL DEFAULT CURRENT_TIMESTAMP, `synced` INTEGER NOT NULL DEFAULT false, FOREIGN KEY(`battery_id`) REFERENCES `batteries`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "charge",
+ "columnName": "charge",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "batteryId",
+ "columnName": "battery_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "comment",
+ "columnName": "comment",
+ "affinity": "TEXT",
+ "notNull": true,
+ "defaultValue": "''"
+ },
+ {
+ "fieldPath": "createdAt",
+ "columnName": "created_at",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "CURRENT_TIMESTAMP"
+ },
+ {
+ "fieldPath": "synced",
+ "columnName": "synced",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "false"
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [
+ {
+ "name": "index_charges_battery_id",
+ "unique": false,
+ "columnNames": [
+ "battery_id"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_charges_battery_id` ON `${TABLE_NAME}` (`battery_id`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "batteries",
+ "onDelete": "CASCADE",
+ "onUpdate": "NO ACTION",
+ "columns": [
+ "battery_id"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "batteries",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL, `declared_capacity` REAL DEFAULT NULL, `comment` TEXT NOT NULL DEFAULT '', `synced` INTEGER NOT NULL DEFAULT false, `created_at` INTEGER NOT NULL DEFAULT CURRENT_TIMESTAMP)",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "declaredCapacity",
+ "columnName": "declared_capacity",
+ "affinity": "REAL",
+ "notNull": false,
+ "defaultValue": "NULL"
+ },
+ {
+ "fieldPath": "comment",
+ "columnName": "comment",
+ "affinity": "TEXT",
+ "notNull": true,
+ "defaultValue": "''"
+ },
+ {
+ "fieldPath": "synced",
+ "columnName": "synced",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "false"
+ },
+ {
+ "fieldPath": "createdAt",
+ "columnName": "created_at",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "CURRENT_TIMESTAMP"
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ }
+ ],
+ "views": [],
+ "setupQueries": [
+ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
+ "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'e86f0253ec49cbc67a601f90d5169a8a')"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index a334e98..52eddea 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -13,16 +13,10 @@
android:supportsRtl="true"
android:theme="@style/Theme.BatteryTracker"
tools:targetApi="31">
-
+
+ android:exported="true">
diff --git a/app/src/main/java/com/sockenklaus/batterytracker/MainActivity.kt b/app/src/main/java/com/sockenklaus/batterytracker/MainActivity.kt
index 7d0d22d..fb0347b 100644
--- a/app/src/main/java/com/sockenklaus/batterytracker/MainActivity.kt
+++ b/app/src/main/java/com/sockenklaus/batterytracker/MainActivity.kt
@@ -1,56 +1,20 @@
package com.sockenklaus.batterytracker
import android.os.Bundle
-import android.view.Menu
-import com.google.android.material.navigation.NavigationView
-import androidx.navigation.findNavController
-import androidx.navigation.ui.AppBarConfiguration
-import androidx.navigation.ui.navigateUp
-import androidx.navigation.ui.setupActionBarWithNavController
-import androidx.navigation.ui.setupWithNavController
-import androidx.drawerlayout.widget.DrawerLayout
-import androidx.appcompat.app.AppCompatActivity
-import androidx.navigation.NavController
-import com.sockenklaus.batterytracker.databinding.ActivityMainBinding
-import com.sockenklaus.batterytracker.room.BatteryTrackerDB
+import androidx.activity.ComponentActivity
+import androidx.activity.compose.setContent
+import androidx.core.view.WindowCompat
+import com.sockenklaus.batterytracker.ui.BatteryTracker
-class MainActivity : AppCompatActivity() {
-
- private lateinit var appBarConfiguration: AppBarConfiguration
- private lateinit var binding: ActivityMainBinding
- private lateinit var navController: NavController
- val db: BatteryTrackerDB by lazy { BatteryTrackerDB.getInstance(this) }
+class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- binding = ActivityMainBinding.inflate(layoutInflater)
- setContentView(binding.root)
+ WindowCompat.setDecorFitsSystemWindows(window, true)
- setSupportActionBar(binding.appBarMain.toolbar)
-
- val drawerLayout: DrawerLayout = binding.drawerLayout
- val navView: NavigationView = binding.navView
- navController = findNavController(R.id.nav_host_fragment_content_main)
- // Passing each menu ID as a set of Ids because each
- // menu should be considered as top level destinations.
- appBarConfiguration = AppBarConfiguration(
- setOf(
- R.id.nav_home, R.id.nav_add_charge, R.id.nav_add_battery, R.id.nav_settings
- ), drawerLayout
- )
- setupActionBarWithNavController(navController, appBarConfiguration)
- navView.setupWithNavController(navController)
- }
-
- override fun onCreateOptionsMenu(menu: Menu): Boolean {
- // Inflate the menu; this adds items to the action bar if it is present.
- menuInflater.inflate(R.menu.main, menu)
- return true
- }
-
- override fun onSupportNavigateUp(): Boolean {
- val navController = findNavController(R.id.nav_host_fragment_content_main)
- return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
+ setContent {
+ BatteryTracker()
+ }
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/sockenklaus/batterytracker/room/BatteryTrackerDB.kt b/app/src/main/java/com/sockenklaus/batterytracker/room/BatteryTrackerDB.kt
index 756a8ed..51374ad 100644
--- a/app/src/main/java/com/sockenklaus/batterytracker/room/BatteryTrackerDB.kt
+++ b/app/src/main/java/com/sockenklaus/batterytracker/room/BatteryTrackerDB.kt
@@ -12,7 +12,7 @@ import com.sockenklaus.batterytracker.room.entities.Charge
@Database(
entities = [Charge::class, Battery::class],
- version = 3
+ version = 4
)
@TypeConverters(Converters::class)
abstract class BatteryTrackerDB : RoomDatabase() {
diff --git a/app/src/main/java/com/sockenklaus/batterytracker/room/Converters.kt b/app/src/main/java/com/sockenklaus/batterytracker/room/Converters.kt
index aa70b76..010a84f 100644
--- a/app/src/main/java/com/sockenklaus/batterytracker/room/Converters.kt
+++ b/app/src/main/java/com/sockenklaus/batterytracker/room/Converters.kt
@@ -2,11 +2,22 @@ package com.sockenklaus.batterytracker.room
import androidx.room.TypeConverter
import java.time.Instant
+import java.time.LocalDate
import java.time.LocalDateTime
import java.time.ZoneId
class Converters {
+ @TypeConverter
+ fun toLocalDate(value: Long): LocalDate {
+ return LocalDate.ofEpochDay(value)
+ }
+
+ @TypeConverter
+ fun toEpochDay(value: LocalDate): Long {
+ return value.toEpochDay()
+ }
+
@TypeConverter
fun toLocalDateTime(value: Long): LocalDateTime {
return LocalDateTime.ofInstant(Instant.ofEpochMilli(value), ZoneId.systemDefault())
diff --git a/app/src/main/java/com/sockenklaus/batterytracker/room/entities/Charge.kt b/app/src/main/java/com/sockenklaus/batterytracker/room/entities/Charge.kt
index 2926995..f1befd4 100644
--- a/app/src/main/java/com/sockenklaus/batterytracker/room/entities/Charge.kt
+++ b/app/src/main/java/com/sockenklaus/batterytracker/room/entities/Charge.kt
@@ -1,6 +1,7 @@
package com.sockenklaus.batterytracker.room.entities
import androidx.room.*
+import java.time.LocalDate
import java.time.LocalDateTime
@Entity(
@@ -24,7 +25,7 @@ data class Charge(
@ColumnInfo(name = "battery_id")
val batteryId: Int,
- val date: LocalDateTime,
+ val date: LocalDate,
@ColumnInfo(defaultValue = "")
val comment: String = "",
diff --git a/app/src/main/java/com/sockenklaus/batterytracker/ui/BatteryTracker.kt b/app/src/main/java/com/sockenklaus/batterytracker/ui/BatteryTracker.kt
new file mode 100644
index 0000000..5dab18d
--- /dev/null
+++ b/app/src/main/java/com/sockenklaus/batterytracker/ui/BatteryTracker.kt
@@ -0,0 +1,150 @@
+package com.sockenklaus.batterytracker.ui
+
+import androidx.compose.animation.AnimatedContent
+import androidx.compose.animation.ExperimentalAnimationApi
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.wrapContentWidth
+import androidx.compose.material.*
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.*
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.res.stringResource
+import androidx.lifecycle.viewmodel.compose.viewModel
+import androidx.navigation.compose.NavHost
+import androidx.navigation.compose.composable
+import com.sockenklaus.batterytracker.R
+import com.sockenklaus.batterytracker.ui.composables.AddBattery
+import com.sockenklaus.batterytracker.ui.composables.AddCharge
+import com.sockenklaus.batterytracker.ui.composables.Home
+import com.sockenklaus.batterytracker.ui.models.MainViewModel
+import kotlinx.coroutines.launch
+
+@Composable
+fun BatteryTracker() {
+ MaterialTheme {
+ val state: MainViewModel = viewModel()
+ state.init()
+
+ Scaffold(
+ scaffoldState = state.scaffoldState,
+
+ topBar = {
+ if(state.showAppBar){
+ TopAppBar (
+ title = { AppBarTitle(state = state) },
+ navigationIcon = {
+ ToggleDrawerButton(
+ state = state,
+ )
+ }
+ )
+ }
+ },
+ ) { innerPadding ->
+ ModalDrawer(
+ drawerState = state.scaffoldState.drawerState,
+ drawerContent = {
+ NavListItem(
+ textId = R.string.nav_home,
+ icon = Icons.Default.Home,
+ route = "home",
+ state = state,
+ )
+
+ NavListItem(
+ icon = Icons.Default.BatteryChargingFull,
+ textId = R.string.nav_add_charge,
+ route = "add_charge",
+ state = state,
+ )
+
+ NavListItem(
+ icon = Icons.Default.BatteryFull,
+ textId = R.string.nav_add_battery,
+ route = "add_battery",
+ state = state,
+ )
+ }
+ ) {
+ NavHost(
+ navController = state.navController,
+ startDestination = "home",
+ modifier = Modifier.padding(innerPadding))
+ {
+ composable("home") { Home(state.navController) }
+ composable("add_charge") { AddCharge(state.navController) }
+ composable("add_battery") { AddBattery(state.navController) }
+ }
+ }
+ }
+ }
+}
+
+@OptIn(ExperimentalMaterialApi::class, ExperimentalAnimationApi::class)
+@Composable
+fun AppBarTitle(
+ state: MainViewModel
+){
+ val text = if(state.scaffoldState.drawerState.targetValue == DrawerValue.Closed) {
+ state.appTitle
+ } else {
+ stringResource(R.string.nav_header_title)
+ }
+
+ AnimatedContent(targetState = text) {
+ Text(it)
+ }
+}
+
+@Composable
+@OptIn(ExperimentalAnimationApi::class, ExperimentalMaterialApi::class)
+fun ToggleDrawerButton(
+ state: MainViewModel
+){
+ val scope = rememberCoroutineScope()
+
+ val icon = if(state.scaffoldState.drawerState.targetValue == DrawerValue.Open) {
+ Icons.Default.Close
+ } else {
+ Icons.Default.Menu
+ }
+
+ IconButton(
+ onClick = {
+ if(state.scaffoldState.drawerState.isClosed) scope.launch { state.scaffoldState.drawerState.open() }
+ else scope.launch { state.scaffoldState.drawerState.close() }
+ }
+ ) {
+ AnimatedContent(targetState = icon) { targetState ->
+ Icon(targetState, null)
+ }
+ }
+}
+
+@OptIn(ExperimentalMaterialApi::class)
+@Composable
+fun NavListItem(
+ icon: ImageVector,
+ textId: Int?,
+ route: String,
+ state: MainViewModel
+) {
+ val scope = rememberCoroutineScope()
+ val text = if ( textId != null) stringResource(textId) else ""
+
+ ListItem(
+ icon = { Icon(icon, null) },
+ text = { Text(text) },
+ modifier = Modifier.clickable {
+ scope.launch {
+ state.appTitle = text
+ state.navController.navigate(route)
+ state.scaffoldState.drawerState.close()
+ }
+ }.wrapContentWidth()
+ )
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/sockenklaus/batterytracker/ui/composables/AddBattery.kt b/app/src/main/java/com/sockenklaus/batterytracker/ui/composables/AddBattery.kt
new file mode 100644
index 0000000..30f15aa
--- /dev/null
+++ b/app/src/main/java/com/sockenklaus/batterytracker/ui/composables/AddBattery.kt
@@ -0,0 +1,79 @@
+package com.sockenklaus.batterytracker.ui.composables
+
+import androidx.compose.foundation.layout.*
+import androidx.compose.foundation.text.KeyboardOptions
+import androidx.compose.material.*
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.*
+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.input.KeyboardType
+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.ui.composables.util.MyOutlinedTextFieldWithSuffix
+import com.sockenklaus.batterytracker.ui.models.AddBatteryViewModel
+import com.sockenklaus.batterytracker.util.validateDecimal
+
+@Composable
+fun AddBattery(navController: NavController){
+ val model: AddBatteryViewModel = viewModel()
+ val batteries by model.batteries.observeAsState(emptyList())
+
+ val outerPadding = 24.dp
+ val innerPadding = 16.dp
+
+ Column(
+ Modifier.padding(outerPadding)
+ ) {
+
+ MyOutlinedTextFieldWithSuffix(
+ value = model.batteryName,
+ onValueChange = { value ->
+ model.batteryName = value
+ model.batteryHasError = false
+ model.batteryHelperId = R.string.helper_required
+ if(batteries.any{ it.name.equals(value, ignoreCase = true) }){
+ model.batteryHasError = true
+ model.batteryHelperId = R.string.helper_battery_not_unique
+ }
+ },
+ labelId = R.string.hint_enter_battery_name,
+ leadingIcon = { Icon(Icons.Default.Tag, "Icon Tag") },
+ isError = model.batteryHasError,
+ helperTextId = model.batteryHelperId
+ )
+
+ Spacer(Modifier.size(innerPadding))
+
+ MyOutlinedTextFieldWithSuffix(
+ value = model.declaredCapacity,
+ onValueChange = {
+ model.declaredCapacity = validateDecimal(it, model.declaredCapacity)
+ },
+ labelId = R.string.hint_enter_declared_capacity,
+ keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Decimal),
+ leadingIcon = { Icon(Icons.Default.BatteryFull, "Icon Battery Full") },
+ suffix = "Ah"
+ )
+
+ Spacer(Modifier.size(outerPadding))
+
+ ExtendedFloatingActionButton(
+ onClick = {
+ if(model.batteryName.isBlank()) model.batteryHasError = true
+
+ if(!model.batteryHasError && model.saveBattery(model.batteryName, model.declaredCapacity)){
+ navController.navigate("home")
+ }
+ },
+ icon = { Icon(Icons.Default.Save, "Icon Save") },
+ text = { Text(stringResource(R.string.button_save_battery)) },
+ modifier = Modifier.align(Alignment.End)
+ )
+ }
+}
\ No newline at end of file
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
new file mode 100644
index 0000000..78e6fc1
--- /dev/null
+++ b/app/src/main/java/com/sockenklaus/batterytracker/ui/composables/AddCharge.kt
@@ -0,0 +1,179 @@
+package com.sockenklaus.batterytracker.ui.composables
+
+import android.app.DatePickerDialog
+import androidx.compose.foundation.layout.*
+import androidx.compose.foundation.text.KeyboardOptions
+import androidx.compose.material.*
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.BatteryChargingFull
+import androidx.compose.material.icons.filled.EditCalendar
+import androidx.compose.material.icons.filled.Save
+import androidx.compose.material.icons.filled.Tag
+import androidx.compose.runtime.*
+import androidx.compose.runtime.livedata.observeAsState
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.TextRange
+import androidx.compose.ui.text.input.KeyboardType
+import androidx.compose.ui.text.input.TextFieldValue
+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.ui.composables.util.MyOutlinedTextFieldWithSuffix
+import com.sockenklaus.batterytracker.ui.models.AddChargeViewModel
+import com.sockenklaus.batterytracker.ui.theme.Gray500
+import com.sockenklaus.batterytracker.util.validateDecimal
+import java.time.*
+import java.time.format.DateTimeFormatter
+import java.time.format.FormatStyle
+import java.util.*
+
+@OptIn(ExperimentalMaterialApi::class)
+@Composable
+fun AddCharge(navController: NavController){
+ val outerPadding = 24.dp
+ val innerPadding = 16.dp
+
+ var bIdExpanded by remember { mutableStateOf(false)}
+ val model: AddChargeViewModel = viewModel()
+ val batteries by model.batteries.observeAsState(emptyList())
+
+ Column(
+ Modifier.padding(outerPadding)
+ ) {
+ ExposedDropdownMenuBox(
+ expanded = bIdExpanded,
+ onExpandedChange = { bIdExpanded = !bIdExpanded}
+ ) {
+
+ val filteringOptions = batteries.filter { it.name.contains(model.batteryId.text, ignoreCase = true)}
+ OutlinedTextField(
+ value = model.batteryId,
+ onValueChange = {
+ model.batteryId = it
+ model.batteryHasError = false
+ model.batteryHelper = R.string.helper_required
+ bIdExpanded = filteringOptions.size > 1
+ },
+ label = { Text(stringResource(R.string.select_battery_id)) },
+ leadingIcon = { Icon(Icons.Default.Tag, null) },
+ trailingIcon = {
+ ExposedDropdownMenuDefaults.TrailingIcon(expanded = bIdExpanded)
+ },
+ colors = ExposedDropdownMenuDefaults.outlinedTextFieldColors(),
+ modifier = Modifier.fillMaxWidth(),
+ isError = model.batteryHasError
+ )
+
+ if(filteringOptions.isNotEmpty()) {
+ ExposedDropdownMenu(
+ expanded = bIdExpanded,
+ onDismissRequest = { bIdExpanded = false }
+ ) {
+ for (filteringOption in filteringOptions) {
+ DropdownMenuItem(
+ onClick = {
+ model.batteryId = TextFieldValue(
+ text = filteringOption.name,
+ selection = TextRange(filteringOption.name.length)
+ )
+ bIdExpanded = false
+ }
+ ) {
+ Text(filteringOption.name)
+ }
+ }
+ }
+ }
+ }
+ Text(
+ text = stringResource(model.batteryHelper),
+ style = MaterialTheme.typography.caption,
+ color = if(model.batteryHasError) MaterialTheme.colors.error else Gray500,
+ modifier = Modifier.padding(start = 16.dp)
+ )
+
+ Spacer(Modifier.size(innerPadding))
+
+ MyOutlinedTextFieldWithSuffix(
+ value = model.charge,
+ onValueChange = {
+ model.charge = validateDecimal(it, model.charge)
+ model.chargeHasError = false
+ },
+ keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Decimal),
+ labelId = R.string.hint_charge,
+ leadingIcon = { Icon(Icons.Default.BatteryChargingFull, "Icon Battery Charging Full") },
+ isError = model.chargeHasError,
+ helperTextId = R.string.helper_required,
+ suffix = "Ah"
+ )
+
+ Spacer(Modifier.size(innerPadding))
+
+ ChargeDatePicker(
+ date = model.date,
+ onSelect = { model.date = it}
+ )
+
+ Spacer(Modifier.size(outerPadding))
+
+ ExtendedFloatingActionButton(
+ text = { Text(stringResource(R.string.button_save_charge)) },
+ onClick = {
+ if(!batteries.any{ it.name == model.batteryId.text }){
+ model.batteryHasError = true
+ model.batteryHelper = R.string.helper_battery_not_found
+ }
+ if(model.batteryId.text.isBlank()){
+ model.batteryHasError = true
+ model.batteryHelper = R.string.helper_required
+ }
+ if(model.charge.isBlank()){
+ model.chargeHasError = true
+ }
+
+ if(!model.batteryHasError && !model.chargeHasError && model.saveCharge(batteries, model.batteryId.text, model.charge, model.date)){
+ navController.navigate("home")
+ }
+ },
+ icon = { Icon(Icons.Default.Save, "Icon Save") },
+ modifier = Modifier.align(Alignment.End)
+
+ )
+ }
+}
+
+
+@Composable
+fun ChargeDatePicker(
+ date: LocalDate,
+ onSelect: (LocalDate) -> Unit,
+){
+ val outputFormat = DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG).withLocale(Locale.GERMANY)
+ val datePickerDialog = DatePickerDialog(
+ LocalContext.current
+ )
+ datePickerDialog.setOnDateSetListener { _, year, month, day ->
+ onSelect(LocalDate.of(year, month + 1, day))
+ }
+ datePickerDialog.updateDate(date.year, date.monthValue - 1, date.dayOfMonth)
+
+ TextButton(
+ onClick = {
+ datePickerDialog.show()
+ },
+ modifier = Modifier.fillMaxWidth()
+ ){
+ Icon(
+ Icons.Default.EditCalendar,
+ "Edit Calendar Icon",
+ Modifier.size(ButtonDefaults.IconSize),
+ )
+ Spacer(Modifier.size(ButtonDefaults.IconSpacing))
+ Text("Date: ${date.format(outputFormat)}")
+ }
+}
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
new file mode 100644
index 0000000..ab8cbf0
--- /dev/null
+++ b/app/src/main/java/com/sockenklaus/batterytracker/ui/composables/Home.kt
@@ -0,0 +1,85 @@
+package com.sockenklaus.batterytracker.ui.composables
+
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.padding
+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.runtime.*
+import androidx.compose.runtime.livedata.observeAsState
+import androidx.compose.ui.Modifier
+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.ui.composables.util.MyOutlinedTextFieldWithSuffix
+import com.sockenklaus.batterytracker.ui.models.HomeViewModel
+
+@OptIn(ExperimentalMaterialApi::class)
+@Composable
+fun Home(navController: NavController) {
+ val model: HomeViewModel = viewModel()
+ val batteries by model.batteries.observeAsState(emptyList())
+ var filterText by remember { mutableStateOf("")}
+
+ val filteredList = batteries.filter { it.name.contains(filterText, ignoreCase = true) }
+ val modHorizontalPadding = Modifier.padding(horizontal = 16.dp)
+
+ Column {
+ MyOutlinedTextFieldWithSuffix(
+ value = filterText,
+ onValueChange = { filterText = it },
+ labelId = R.string.hint_filter_batteries,
+ modifier = Modifier.padding(
+ start = 16.dp,
+ end = 16.dp,
+ top = 16.dp
+ )
+ )
+
+ LazyColumn(
+ state = LazyListState()
+ ) {
+ items(filteredList){ battery ->
+ ListItem(
+ text = { Text(battery.name) },
+ secondaryText = {
+ if(battery.declaredCapacity != null){
+ Text("Capacity: ${battery.declaredCapacity} Ah")
+ }
+ }
+ )
+ Divider(modHorizontalPadding)
+ }
+ }
+ }
+}
+
+
+/*
+class HomeFragment : Fragment() {
+
+ @OptIn(ExperimentalMaterialApi::class)
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View {
+
+ return ComposeView(requireContext()).apply {
+ setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
+
+ setContent {
+ BatteryTrackerTheme() {
+
+ }
+ }
+ }
+ }
+
+ override fun onDestroyView() {
+ super.onDestroyView()
+ }
+}*/
diff --git a/app/src/main/java/com/sockenklaus/batterytracker/ui/composables/Composables.kt b/app/src/main/java/com/sockenklaus/batterytracker/ui/composables/util/Composables.kt
similarity index 61%
rename from app/src/main/java/com/sockenklaus/batterytracker/ui/composables/Composables.kt
rename to app/src/main/java/com/sockenklaus/batterytracker/ui/composables/util/Composables.kt
index d3b8067..d940a33 100644
--- a/app/src/main/java/com/sockenklaus/batterytracker/ui/composables/Composables.kt
+++ b/app/src/main/java/com/sockenklaus/batterytracker/ui/composables/util/Composables.kt
@@ -1,4 +1,4 @@
-package com.sockenklaus.batterytracker.ui.composables
+package com.sockenklaus.batterytracker.ui.composables.util
import androidx.compose.foundation.background
import androidx.compose.foundation.interaction.MutableInteractionSource
@@ -9,18 +9,104 @@ import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.*
import androidx.compose.material.TextFieldDefaults.OutlinedTextFieldDecorationBox
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.remember
+import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Shape
-import androidx.compose.ui.graphics.SolidColor
-import androidx.compose.ui.graphics.takeOrElse
+import androidx.compose.ui.graphics.*
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.input.VisualTransformation
+import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.sockenklaus.batterytracker.ui.theme.Gray500
+/*@Composable
+fun TopAppBar(
+ title: @Composable () -> Unit,
+ modifier: Modifier = Modifier,
+ navigationIcon: @Composable (() -> Unit)? = null,
+ actions: @Composable RowScope.() -> Unit = {},
+ backgroundColor: Color = MaterialTheme.colors.primarySurface,
+ contentColor: Color = contentColorFor(backgroundColor),
+ elevation: Dp = AppBarDefaults.TopAppBarElevation
+) {
+ AppBar(
+ backgroundColor,
+ contentColor,
+ elevation,
+ AppBarDefaults.ContentPadding,
+ RectangleShape,
+ modifier
+ ) {
+ if (navigationIcon == null) {
+ Spacer(Modifier.width(16.dp - 4.dp))
+ } else {
+ Row(Modifier.fillMaxHeight().width(72.dp - 4.dp), verticalAlignment = Alignment.CenterVertically) {
+ CompositionLocalProvider(
+ LocalContentAlpha provides ContentAlpha.high,
+ content = navigationIcon
+ )
+ }
+ }
+
+ Row(
+ Modifier.fillMaxHeight().weight(1f),
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ ProvideTextStyle(value = MaterialTheme.typography.h6) {
+ CompositionLocalProvider(
+ LocalContentAlpha provides ContentAlpha.high,
+ content = title
+ )
+ }
+ }
+
+ CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.medium) {
+ Row(
+ Modifier.fillMaxHeight(),
+ horizontalArrangement = Arrangement.End,
+ verticalAlignment = Alignment.CenterVertically,
+ content = actions
+ )
+ }
+ }
+}
+
+
@Composable
+private fun AppBar(
+ backgroundColor: Color,
+ contentColor: Color,
+ elevation: Dp,
+ contentPadding: PaddingValues,
+ shape: Shape,
+ modifier: Modifier = Modifier,
+ content: @Composable RowScope.() -> Unit
+) {
+ Surface(
+ color = backgroundColor,
+ contentColor = contentColor,
+ elevation = elevation,
+ shape = shape,
+ modifier = modifier
+ ) {
+ CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.medium) {
+ Row(
+ Modifier.fillMaxWidth()
+ .padding(contentPadding)
+ .height(56.dp),
+ horizontalArrangement = Arrangement.Start,
+ verticalAlignment = Alignment.CenterVertically,
+ content = content
+ )
+ }
+ }
+}*/
+
+
+@Composable
+@OptIn(ExperimentalMaterialApi::class)
fun MyOutlinedTextFieldWithSuffix(
value: String,
onValueChange: (String) -> Unit,
@@ -56,10 +142,10 @@ fun MyOutlinedTextFieldWithSuffix(
Gray500
}
- @OptIn(ExperimentalMaterialApi::class)
BasicTextField(
value = value,
- modifier = modifier.padding(top = 8.dp)
+ modifier = modifier
+ .padding(top = 8.dp)
.background(colors.backgroundColor(enabled).value, shape)
.defaultMinSize(
diff --git a/app/src/main/java/com/sockenklaus/batterytracker/ui/fragments/add_battery/AddBatteryFragment.kt b/app/src/main/java/com/sockenklaus/batterytracker/ui/fragments/add_battery/AddBatteryFragment.kt
deleted file mode 100644
index 251b9fd..0000000
--- a/app/src/main/java/com/sockenklaus/batterytracker/ui/fragments/add_battery/AddBatteryFragment.kt
+++ /dev/null
@@ -1,130 +0,0 @@
-package com.sockenklaus.batterytracker.ui.fragments.add_battery
-
-import android.os.Bundle
-import androidx.fragment.app.Fragment
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import androidx.compose.foundation.layout.*
-import androidx.compose.foundation.text.KeyboardOptions
-import androidx.compose.material.*
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.filled.*
-import androidx.compose.runtime.*
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.platform.ComposeView
-import androidx.compose.ui.platform.ViewCompositionStrategy
-import androidx.compose.ui.res.stringResource
-import androidx.compose.ui.text.input.KeyboardType
-import androidx.compose.ui.unit.dp
-import androidx.lifecycle.ViewModelProvider
-import androidx.navigation.fragment.findNavController
-import com.sockenklaus.batterytracker.R
-import com.sockenklaus.batterytracker.room.entities.Battery
-import com.sockenklaus.batterytracker.ui.composables.MyOutlinedTextFieldWithSuffix
-import com.sockenklaus.batterytracker.ui.theme.BatteryTrackerTheme
-import com.sockenklaus.batterytracker.util.validateDecimal
-
-/**
- * A simple [Fragment] subclass.
- * Use the [AddBatteryFragment.newInstance] factory method to
- * create an instance of this fragment.
- */
-class AddBatteryFragment : Fragment() {
-
- override fun onCreateView(
- inflater: LayoutInflater, container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View {
-
- val model = ViewModelProvider(this)[AddBatteryViewModel::class.java]
-
- var batteries by mutableStateOf(emptyList())
-
- model.batteries.observe(viewLifecycleOwner) {
- batteries = it
- }
-
- return ComposeView(requireContext()).apply {
- setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
-
- setContent {
- BatteryTrackerTheme() {
- val outerPadding = 24.dp
- val innerPadding = 16.dp
-
- Column(
- Modifier.padding(outerPadding)
- ) {
-
- MyOutlinedTextFieldWithSuffix(
- value = model.batteryName,
- onValueChange = { value ->
- model.batteryName = value
- model.batteryHasError = false
- model.batteryHelperId = R.string.helper_required
- if(batteries.any{ it.name.equals(value, ignoreCase = true) }){
- model.batteryHasError = true
- model.batteryHelperId = R.string.helper_battery_not_unique
- }
- },
- labelId = R.string.hint_enter_battery_name,
- leadingIcon = { Icon(Icons.Default.Tag, "Icon Tag") },
- isError = model.batteryHasError,
- helperTextId = model.batteryHelperId
- )
-
- Spacer(Modifier.size(innerPadding))
-
- MyOutlinedTextFieldWithSuffix(
- value = model.declaredCapacity,
- onValueChange = {
- model.declaredCapacity = validateDecimal(it, model.declaredCapacity)
- },
- labelId = R.string.hint_enter_declared_capacity,
- keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Decimal),
- leadingIcon = { Icon(Icons.Default.BatteryFull, "Icon Battery Full") },
- suffix = "Ah"
- )
-
- Spacer(Modifier.size(outerPadding))
-
- ExtendedFloatingActionButton(
- onClick = {
- if(model.batteryName.isBlank()) model.batteryHasError = true
-
- if(!model.batteryHasError && model.saveBattery(model.batteryName, model.declaredCapacity)){
- findNavController().navigate(R.id.action_nav_add_battery_to_nav_home)
- }
- },
- icon = { Icon(Icons.Default.Save, "Icon Save") },
- text = { Text(stringResource(R.string.button_save_battery)) },
- modifier = Modifier.align(Alignment.End)
- )
- }
- }
- }
- }
- }
-
- /*companion object {
-
- * Use this factory method to create a new instance of
- * this fragment using the provided parameters.
- *
- * @param param1 Parameter 1.
- * @param param2 Parameter 2.
- * @return A new instance of fragment AddBatteryFragment.
- *//*
- // TODO: Rename and change types and number of parameters
- @JvmStatic
- fun newInstance(param1: String, param2: String) =
- AddBatteryFragment().apply {
- arguments = Bundle().apply {
- putString(ARG_PARAM1, param1)
- putString(ARG_PARAM2, param2)
- }
- }
- }*/
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/sockenklaus/batterytracker/ui/fragments/add_charge/AddChargeFragment.kt b/app/src/main/java/com/sockenklaus/batterytracker/ui/fragments/add_charge/AddChargeFragment.kt
deleted file mode 100644
index 7f9a336..0000000
--- a/app/src/main/java/com/sockenklaus/batterytracker/ui/fragments/add_charge/AddChargeFragment.kt
+++ /dev/null
@@ -1,212 +0,0 @@
-package com.sockenklaus.batterytracker.ui.fragments.add_charge
-
-import androidx.lifecycle.ViewModelProvider
-import android.os.Bundle
-import androidx.fragment.app.Fragment
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import androidx.compose.foundation.layout.*
-import androidx.compose.foundation.text.KeyboardOptions
-import androidx.compose.material.*
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.filled.BatteryChargingFull
-import androidx.compose.material.icons.filled.EditCalendar
-import androidx.compose.material.icons.filled.Save
-import androidx.compose.material.icons.filled.Tag
-import androidx.compose.runtime.*
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.platform.ComposeView
-import androidx.compose.ui.platform.ViewCompositionStrategy
-import androidx.compose.ui.res.stringResource
-import androidx.compose.ui.text.TextRange
-import androidx.compose.ui.text.input.KeyboardType
-import androidx.compose.ui.text.input.TextFieldValue
-import androidx.compose.ui.unit.dp
-import androidx.navigation.fragment.findNavController
-import com.google.android.material.datepicker.MaterialDatePicker
-import com.sockenklaus.batterytracker.R
-import com.sockenklaus.batterytracker.room.entities.Battery
-import com.sockenklaus.batterytracker.ui.composables.MyOutlinedTextFieldWithSuffix
-import com.sockenklaus.batterytracker.ui.theme.BatteryTrackerTheme
-import com.sockenklaus.batterytracker.ui.theme.Gray500
-import com.sockenklaus.batterytracker.util.validateDecimal
-import java.time.*
-import java.time.format.DateTimeFormatter
-import java.time.format.FormatStyle
-import java.util.*
-
-class AddChargeFragment : Fragment() {
-
- private lateinit var model: AddChargeViewModel
-
- @OptIn(ExperimentalMaterialApi::class)
- override fun onCreateView(
- inflater: LayoutInflater,
- container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View {
-
- model = ViewModelProvider(this)[AddChargeViewModel::class.java]
- var batteries by mutableStateOf(emptyList())
-
- model.batteries.observe(this.viewLifecycleOwner){
- batteries = it
- }
-
- return ComposeView(requireContext()).apply{
- setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
-
- setContent {
- BatteryTrackerTheme() {
- val outerPadding = 24.dp
- val innerPadding = 16.dp
-
- var bIdExpanded by remember { mutableStateOf(false)}
-
- Column(
- Modifier.padding(outerPadding)
- ) {
- ExposedDropdownMenuBox(
- expanded = bIdExpanded,
- onExpandedChange = { bIdExpanded = !bIdExpanded}
- ) {
-
- val filteringOptions = batteries.filter { it.name.contains(model.batteryId.text, ignoreCase = true)}
- OutlinedTextField(
- value = model.batteryId,
- onValueChange = {
- model.batteryId = it
- model.batteryHasError = false
- model.batteryHelper = R.string.helper_required
- bIdExpanded = filteringOptions.size > 1
- },
- label = { Text(stringResource(R.string.select_battery_id)) },
- leadingIcon = { Icon(Icons.Default.Tag, null) },
- trailingIcon = {
- ExposedDropdownMenuDefaults.TrailingIcon(expanded = bIdExpanded)
- },
- colors = ExposedDropdownMenuDefaults.outlinedTextFieldColors(),
- modifier = Modifier.fillMaxWidth(),
- isError = model.batteryHasError
- )
-
- if(filteringOptions.isNotEmpty()) {
- ExposedDropdownMenu(
- expanded = bIdExpanded,
- onDismissRequest = { bIdExpanded = false }
- ) {
- for (filteringOption in filteringOptions) {
- DropdownMenuItem(
- onClick = {
- model.batteryId = TextFieldValue(
- text = filteringOption.name,
- selection = TextRange(filteringOption.name.length)
- )
- bIdExpanded = false
- }
- ) {
- Text(filteringOption.name)
- }
- }
- }
- }
- }
- Text(
- text = stringResource(model.batteryHelper),
- style = MaterialTheme.typography.caption,
- color = if(model.batteryHasError) MaterialTheme.colors.error else Gray500,
- modifier = Modifier.padding(start = 16.dp)
- )
-
- Spacer(Modifier.size(innerPadding))
-
- MyOutlinedTextFieldWithSuffix(
- value = model.charge,
- onValueChange = {
- model.charge = validateDecimal(it, model.charge)
- model.chargeHasError = false
- },
- keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Decimal),
- labelId = R.string.hint_charge,
- leadingIcon = { Icon(Icons.Default.BatteryChargingFull, "Icon Battery Charging Full") },
- isError = model.chargeHasError,
- helperTextId = R.string.helper_required,
- suffix = "Ah"
- )
-
- Spacer(Modifier.size(innerPadding))
-
- ChargeDatePicker(
- date = model.date,
- onSelect = { model.date = it}
- )
-
- Spacer(Modifier.size(outerPadding))
-
- ExtendedFloatingActionButton(
- text = { Text(stringResource(R.string.button_save_charge)) },
- onClick = {
- if(!batteries.any{ it.name == model.batteryId.text }){
- model.batteryHasError = true
- model.batteryHelper = R.string.helper_battery_not_found
- }
- if(model.batteryId.text.isBlank()){
- model.batteryHasError = true
- model.batteryHelper = R.string.helper_required
- }
- if(model.charge.isBlank()){
- model.chargeHasError = true
- }
-
- if(!model.batteryHasError && !model.chargeHasError && model.saveCharge(batteries, model.batteryId.text, model.charge, model.date)){
- findNavController().navigate(R.id.action_nav_add_charge_to_nav_home)
- }
- },
- icon = { Icon(Icons.Default.Save, "Icon Save") },
- modifier = Modifier.align(Alignment.End)
-
- )
- }
- }
- }
- }
- }
-
- @Composable
- fun ChargeDatePicker(
- date: LocalDateTime,
- onSelect: (LocalDateTime) -> Unit,
- ) {
- val dateFormat: DateTimeFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG).withLocale(Locale.GERMANY)
-
- val datePicker = MaterialDatePicker.Builder.datePicker()
- .setTitleText("Select date")
- .setSelection( date.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() )
- .build()
-
- datePicker.addOnPositiveButtonClickListener {
- onSelect(LocalDateTime.ofInstant(Instant.ofEpochMilli(it), ZoneId.systemDefault()))
- }
-
- TextButton(
- onClick = {
- datePicker.show(parentFragmentManager, "tag")
- },
- modifier = Modifier.fillMaxWidth()
- ){
- Icon(
- Icons.Default.EditCalendar,
- "Edit Calendar Icon",
- Modifier.size(ButtonDefaults.IconSize),
- )
- Spacer(Modifier.size(ButtonDefaults.IconSpacing))
- Text("Date: ${date.format(dateFormat)}")
- }
- }
-
- override fun onDestroyView() {
- super.onDestroyView()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/sockenklaus/batterytracker/ui/fragments/home/HomeFragment.kt b/app/src/main/java/com/sockenklaus/batterytracker/ui/fragments/home/HomeFragment.kt
deleted file mode 100644
index c939cdd..0000000
--- a/app/src/main/java/com/sockenklaus/batterytracker/ui/fragments/home/HomeFragment.kt
+++ /dev/null
@@ -1,89 +0,0 @@
-package com.sockenklaus.batterytracker.ui.fragments.home
-
-import android.os.Bundle
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.padding
-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.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.platform.ComposeView
-import androidx.compose.ui.platform.ViewCompositionStrategy
-import androidx.compose.ui.unit.dp
-import androidx.fragment.app.Fragment
-import androidx.lifecycle.viewmodel.compose.viewModel
-import com.sockenklaus.batterytracker.R
-import com.sockenklaus.batterytracker.room.entities.Battery
-import com.sockenklaus.batterytracker.ui.composables.MyOutlinedTextFieldWithSuffix
-import com.sockenklaus.batterytracker.ui.theme.BatteryTrackerTheme
-
-class HomeFragment : Fragment() {
-
- @OptIn(ExperimentalMaterialApi::class)
- override fun onCreateView(
- inflater: LayoutInflater,
- container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View {
-
- return ComposeView(requireContext()).apply {
- setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
-
- setContent {
- BatteryTrackerTheme() {
- val model: HomeViewModel = viewModel()
- var batteries by remember { mutableStateOf(emptyList()) }
- var filterText by remember { mutableStateOf("")}
-
- model.batteries.observe(viewLifecycleOwner) {
- batteries = it
- }
-
- val filteredList = batteries.filter { it.name.contains(filterText, ignoreCase = true) }
- val modHorizontalPadding = Modifier.padding(horizontal = 16.dp)
-
- Column {
- MyOutlinedTextFieldWithSuffix(
- value = filterText,
- onValueChange = { filterText = it },
- labelId = R.string.hint_filter_batteries,
- modifier = Modifier.padding(
- start = 16.dp,
- end = 16.dp,
- top = 16.dp
- )
- )
-
- LazyColumn(
- state = LazyListState()
- ) {
- items(filteredList){ battery ->
- ListItem(
- text = { Text(battery.name) },
- secondaryText = {
- if(battery.declaredCapacity != null){
- Text("Capacity: ${battery.declaredCapacity} Ah")
- }
- }
- )
- Divider(modHorizontalPadding)
- }
- }
- }
- }
- }
- }
- }
-
- override fun onDestroyView() {
- super.onDestroyView()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/sockenklaus/batterytracker/ui/fragments/settings/SettingsFragment.kt b/app/src/main/java/com/sockenklaus/batterytracker/ui/fragments/settings/SettingsFragment.kt
deleted file mode 100644
index 8928469..0000000
--- a/app/src/main/java/com/sockenklaus/batterytracker/ui/fragments/settings/SettingsFragment.kt
+++ /dev/null
@@ -1,27 +0,0 @@
-package com.sockenklaus.batterytracker.ui.fragments.settings
-
-import androidx.lifecycle.ViewModelProvider
-import android.os.Bundle
-import androidx.fragment.app.Fragment
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import com.sockenklaus.batterytracker.R
-
-class SettingsFragment : Fragment() {
-
- companion object {
- fun newInstance() = SettingsFragment()
- }
-
- private lateinit var viewModel: SettingsViewModel
-
- override fun onCreateView(
- inflater: LayoutInflater, container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View? {
- viewModel = ViewModelProvider(this)[SettingsViewModel::class.java]
-
- return inflater.inflate(R.layout.fragment_settings, container, false)
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/sockenklaus/batterytracker/ui/fragments/settings/SettingsViewModel.kt b/app/src/main/java/com/sockenklaus/batterytracker/ui/fragments/settings/SettingsViewModel.kt
deleted file mode 100644
index 4520869..0000000
--- a/app/src/main/java/com/sockenklaus/batterytracker/ui/fragments/settings/SettingsViewModel.kt
+++ /dev/null
@@ -1,7 +0,0 @@
-package com.sockenklaus.batterytracker.ui.fragments.settings
-
-import androidx.lifecycle.ViewModel
-
-class SettingsViewModel : ViewModel() {
- // TODO: Implement the ViewModel
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/sockenklaus/batterytracker/ui/fragments/add_battery/AddBatteryViewModel.kt b/app/src/main/java/com/sockenklaus/batterytracker/ui/models/AddBatteryViewModel.kt
similarity index 93%
rename from app/src/main/java/com/sockenklaus/batterytracker/ui/fragments/add_battery/AddBatteryViewModel.kt
rename to app/src/main/java/com/sockenklaus/batterytracker/ui/models/AddBatteryViewModel.kt
index 61752cf..8cd53bf 100644
--- a/app/src/main/java/com/sockenklaus/batterytracker/ui/fragments/add_battery/AddBatteryViewModel.kt
+++ b/app/src/main/java/com/sockenklaus/batterytracker/ui/models/AddBatteryViewModel.kt
@@ -1,4 +1,4 @@
-package com.sockenklaus.batterytracker.ui.fragments.add_battery
+package com.sockenklaus.batterytracker.ui.models
import android.app.Application
import androidx.compose.runtime.getValue
@@ -16,7 +16,6 @@ import java.lang.Exception
class AddBatteryViewModel(application: Application): AndroidViewModel(application) {
- private val app = application
private val db = BatteryTrackerDB.getInstance(application)
val batteries = db.batteryDao().getBatteries().asLiveData()
diff --git a/app/src/main/java/com/sockenklaus/batterytracker/ui/fragments/add_charge/AddChargeViewModel.kt b/app/src/main/java/com/sockenklaus/batterytracker/ui/models/AddChargeViewModel.kt
similarity index 91%
rename from app/src/main/java/com/sockenklaus/batterytracker/ui/fragments/add_charge/AddChargeViewModel.kt
rename to app/src/main/java/com/sockenklaus/batterytracker/ui/models/AddChargeViewModel.kt
index 37904f2..2ecbf00 100644
--- a/app/src/main/java/com/sockenklaus/batterytracker/ui/fragments/add_charge/AddChargeViewModel.kt
+++ b/app/src/main/java/com/sockenklaus/batterytracker/ui/models/AddChargeViewModel.kt
@@ -1,4 +1,4 @@
-package com.sockenklaus.batterytracker.ui.fragments.add_charge
+package com.sockenklaus.batterytracker.ui.models
import android.app.Application
import androidx.compose.runtime.getValue
@@ -15,7 +15,7 @@ import com.sockenklaus.batterytracker.room.entities.Battery
import com.sockenklaus.batterytracker.room.entities.Charge
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
-import java.time.LocalDateTime
+import java.time.LocalDate
class AddChargeViewModel(application: Application) : AndroidViewModel(application) {
@@ -23,7 +23,7 @@ class AddChargeViewModel(application: Application) : AndroidViewModel(applicatio
var batteries: LiveData> = db.batteryDao().getBatteries().asLiveData()
var batteryId by mutableStateOf(TextFieldValue(""))
- var date: LocalDateTime by mutableStateOf(LocalDateTime.now())
+ var date: LocalDate by mutableStateOf(LocalDate.now())
var charge by mutableStateOf("")
var batteryHasError by mutableStateOf(false)
@@ -35,7 +35,7 @@ class AddChargeViewModel(application: Application) : AndroidViewModel(applicatio
batteryList: List,
batteryName: String,
charge: String,
- date: LocalDateTime
+ date: LocalDate
):Boolean {
val battery = batteryList.find { it.name == batteryName }
diff --git a/app/src/main/java/com/sockenklaus/batterytracker/ui/fragments/home/HomeViewModel.kt b/app/src/main/java/com/sockenklaus/batterytracker/ui/models/HomeViewModel.kt
similarity index 85%
rename from app/src/main/java/com/sockenklaus/batterytracker/ui/fragments/home/HomeViewModel.kt
rename to app/src/main/java/com/sockenklaus/batterytracker/ui/models/HomeViewModel.kt
index 63bf22c..112ac66 100644
--- a/app/src/main/java/com/sockenklaus/batterytracker/ui/fragments/home/HomeViewModel.kt
+++ b/app/src/main/java/com/sockenklaus/batterytracker/ui/models/HomeViewModel.kt
@@ -1,4 +1,4 @@
-package com.sockenklaus.batterytracker.ui.fragments.home
+package com.sockenklaus.batterytracker.ui.models
import android.app.Application
import androidx.lifecycle.*
diff --git a/app/src/main/java/com/sockenklaus/batterytracker/ui/models/MainViewModel.kt b/app/src/main/java/com/sockenklaus/batterytracker/ui/models/MainViewModel.kt
new file mode 100644
index 0000000..ddb5cae
--- /dev/null
+++ b/app/src/main/java/com/sockenklaus/batterytracker/ui/models/MainViewModel.kt
@@ -0,0 +1,21 @@
+package com.sockenklaus.batterytracker.ui.models
+
+import androidx.compose.material.*
+import androidx.compose.runtime.*
+import androidx.lifecycle.ViewModel
+import androidx.navigation.NavHostController
+import androidx.navigation.compose.rememberNavController
+
+class MainViewModel : ViewModel() {
+
+ var showAppBar by mutableStateOf(true)
+ var appTitle by mutableStateOf("Home")
+ lateinit var navController: NavHostController
+ lateinit var scaffoldState: ScaffoldState
+
+ @Composable
+ fun init(){
+ navController = rememberNavController()
+ scaffoldState = rememberScaffoldState()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
deleted file mode 100644
index 3615eaa..0000000
--- a/app/src/main/res/layout/activity_main.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/app_bar_main.xml b/app/src/main/res/layout/app_bar_main.xml
deleted file mode 100644
index 3f2bd1e..0000000
--- a/app/src/main/res/layout/app_bar_main.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/content_main.xml b/app/src/main/res/layout/content_main.xml
deleted file mode 100644
index 6e0ea39..0000000
--- a/app/src/main/res/layout/content_main.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_settings.xml b/app/src/main/res/layout/fragment_settings.xml
deleted file mode 100644
index c496fd6..0000000
--- a/app/src/main/res/layout/fragment_settings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/list_item.xml b/app/src/main/res/layout/list_item.xml
deleted file mode 100644
index b3d58f4..0000000
--- a/app/src/main/res/layout/list_item.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/nav_header_main.xml b/app/src/main/res/layout/nav_header_main.xml
deleted file mode 100644
index 37881c1..0000000
--- a/app/src/main/res/layout/nav_header_main.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/menu/activity_main_drawer.xml b/app/src/main/res/menu/activity_main_drawer.xml
deleted file mode 100644
index d9275fd..0000000
--- a/app/src/main/res/menu/activity_main_drawer.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
\ No newline at end of file
diff --git a/app/src/main/res/menu/main.xml b/app/src/main/res/menu/main.xml
deleted file mode 100644
index 4b177d2..0000000
--- a/app/src/main/res/menu/main.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
\ No newline at end of file
diff --git a/app/src/main/res/navigation/mobile_navigation.xml b/app/src/main/res/navigation/mobile_navigation.xml
deleted file mode 100644
index 5d3fb35..0000000
--- a/app/src/main/res/navigation/mobile_navigation.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index f076b80..ed933cb 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1,21 +1,19 @@
BatteryTracker
- Open navigation drawer
- Close navigation drawer
- Navigation
android.studio@android.com
Navigation header
Settings
- Home
- Gallery
Slideshow
Hello blank fragment
- Settings
Save Settings
- Add Charge
- Add Battery
+
+ Navigation
+ Home
+ Add Charge
+ Add Battery
+
Battery ID
Save Charge
Date
@@ -31,4 +29,5 @@
Battery-Name not unique!
Battery not found
Filter Batteries…
+ MainActivity2
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index d74ff6b..8717394 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,5 +1,8 @@
buildscript {
+ext {
+ compose_version = '1.1.0-beta01'
+}
}// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
id 'com.android.application' version '7.2.1' apply false