只记录体重版本完成,UI优化,功能添加待后期更新
parent
52289ce9e0
commit
ffd84a661c
|
|
@ -5,6 +5,7 @@
|
|||
<option name="linkedExternalProjectsSettings">
|
||||
<GradleProjectSettings>
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="gradleHome" value="/usr/local/Cellar/gradle/8.4/libexec" />
|
||||
<option name="gradleJvm" value="17" />
|
||||
<option name="modules">
|
||||
<set>
|
||||
|
|
|
|||
|
|
@ -78,4 +78,7 @@ dependencies {
|
|||
// view model
|
||||
|
||||
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.6.1")
|
||||
|
||||
implementation("com.google.accompanist:accompanist-systemuicontroller:0.27.0")
|
||||
|
||||
}
|
||||
|
|
@ -7,9 +7,8 @@
|
|||
android:allowBackup="true"
|
||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||
android:fullBackupContent="@xml/backup_rules"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:icon="@drawable/weight"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.WeightTrack"
|
||||
tools:targetApi="31">
|
||||
|
|
|
|||
|
|
@ -24,11 +24,15 @@ import androidx.compose.foundation.layout.wrapContentHeight
|
|||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Edit
|
||||
import androidx.compose.material.icons.outlined.Edit
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.DatePicker
|
||||
import androidx.compose.material3.DatePickerFormatter
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.ModalBottomSheet
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
|
|
@ -37,6 +41,7 @@ import androidx.compose.material3.Text
|
|||
import androidx.compose.material3.rememberDatePickerState
|
||||
import androidx.compose.material3.rememberModalBottomSheetState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
|
|
@ -48,18 +53,19 @@ import androidx.compose.ui.Alignment
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.painter.Painter
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.eacenic.weighttrack.ui.theme.WeightTrackTheme
|
||||
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
||||
import kotlinx.coroutines.launch
|
||||
import java.time.Instant
|
||||
import java.time.LocalDateTime
|
||||
import java.time.ZoneId
|
||||
import java.time.ZoneOffset
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.util.Date
|
||||
|
||||
class MainActivity : ComponentActivity() {
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
|
|
@ -88,9 +94,18 @@ private val dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
|||
fun WeightTrackLayout(
|
||||
weightTrackViewModel: WeightTrackViewModel = viewModel()
|
||||
) {
|
||||
|
||||
val systemUIController = rememberSystemUiController()
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
systemUIController.setStatusBarColor(Color(0xFF424242))
|
||||
}
|
||||
|
||||
val weightRecords by weightTrackViewModel.historyData.collectAsState()
|
||||
val newestRecord by weightTrackViewModel.newestRecord.collectAsState()
|
||||
|
||||
var openBottomSheet by rememberSaveable { mutableStateOf(false) }
|
||||
var curRecord by rememberSaveable { mutableStateOf<WeightRecord?>(null) }
|
||||
|
||||
weightTrackViewModel.loadWeightRecords()
|
||||
|
||||
|
|
@ -101,58 +116,77 @@ fun WeightTrackLayout(
|
|||
Column(
|
||||
modifier = Modifier.padding(horizontal = 20.dp)
|
||||
) {
|
||||
CurrentWeight(62.6f, Modifier.padding(top = 20.dp))
|
||||
CurrentWeight(newestRecord, Modifier.padding(top = 20.dp))
|
||||
LazyColumn(
|
||||
modifier = Modifier.fillMaxHeight(0.9f)
|
||||
) {
|
||||
this.items(weightRecords) {
|
||||
this.items(weightRecords) { it ->
|
||||
// Text(text = "${it.weight}")
|
||||
WeightRecordItem(weightRecord = it)
|
||||
WeightRecordItem(
|
||||
weightRecord = it,
|
||||
onClickEdit = { record ->
|
||||
curRecord = record
|
||||
openBottomSheet = true
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
EditButton(onClick = { openBottomSheet = true })
|
||||
}
|
||||
|
||||
if (openBottomSheet) {
|
||||
BottomSheetEditor(
|
||||
expandBottomSheet = openBottomSheet,
|
||||
onDismiss = {
|
||||
openBottomSheet = false
|
||||
}
|
||||
curRecord = null
|
||||
},
|
||||
curRecord = curRecord
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
@Composable
|
||||
fun WeightRecordItem(weightRecord: WeightRecord) {
|
||||
Box(
|
||||
fun WeightRecordItem(
|
||||
weightRecord: WeightRecord,
|
||||
onClickEdit: (curRecord: WeightRecord) -> Unit
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight()
|
||||
.padding(vertical = 5.dp)
|
||||
.padding(vertical = 5.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(
|
||||
text = "${weightRecord.weight}",
|
||||
modifier = Modifier.align(Alignment.CenterStart),
|
||||
fontFamily = doodleShadowFontFamily,
|
||||
fontSize = 36.sp,
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
Text(
|
||||
text = dateTimeFormatter.format(weightRecord.date),
|
||||
modifier = Modifier.align(Alignment.CenterEnd),
|
||||
fontFamily = doodleShadowFontFamily,
|
||||
fontSize = 18.sp
|
||||
fontSize = 18.sp,
|
||||
modifier = Modifier.padding(end = 20.dp)
|
||||
)
|
||||
IconButton(
|
||||
onClick = { onClickEdit(weightRecord) },
|
||||
modifier = Modifier.padding(horizontal = 5.dp)
|
||||
) {
|
||||
Icon(Icons.Filled.Edit, contentDescription = "edit")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun CurrentWeight(
|
||||
currentWeight: Float? = null,
|
||||
curRecord: WeightRecord? = null,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
Row (
|
||||
Row(
|
||||
modifier = modifier
|
||||
.wrapContentHeight()
|
||||
.fillMaxWidth(),
|
||||
|
|
@ -163,13 +197,14 @@ fun CurrentWeight(
|
|||
.fillMaxWidth()
|
||||
.height(120.dp)
|
||||
.clip(RoundedCornerShape(10.dp))
|
||||
.background(Color.Cyan)
|
||||
.background(Color(0xFF424242))
|
||||
|
||||
) {
|
||||
Text(
|
||||
text = "${currentWeight ?: "No Data"}",
|
||||
text = "${curRecord?.weight ?: "No Data"}",
|
||||
modifier = Modifier.align(Alignment.Center),
|
||||
fontSize = 80.sp,
|
||||
color = Color.White,
|
||||
fontFamily = doodleShadowFontFamily
|
||||
)
|
||||
}
|
||||
|
|
@ -192,10 +227,15 @@ fun EditButton(
|
|||
.height(48.dp)
|
||||
.fillMaxWidth(),
|
||||
shape = RoundedCornerShape(5.dp),
|
||||
colors = ButtonDefaults.buttonColors(Color.Cyan),
|
||||
colors = ButtonDefaults.buttonColors(Color(0xFF424242)),
|
||||
onClick = onClick,
|
||||
) {
|
||||
Text(text = "ADD", color = Color.Black, fontSize = 36.sp, fontFamily = doodleShadowFontFamily)
|
||||
Text(
|
||||
text = "ADD",
|
||||
color = Color.White,
|
||||
fontSize = 36.sp,
|
||||
fontFamily = doodleShadowFontFamily
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -204,22 +244,23 @@ fun EditButton(
|
|||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun BottomSheetEditor(
|
||||
expandBottomSheet: Boolean = false,
|
||||
onDismiss: () -> Unit,
|
||||
weightTrackViewModel: WeightTrackViewModel = viewModel()
|
||||
weightTrackViewModel: WeightTrackViewModel = viewModel(),
|
||||
curRecord: WeightRecord? = null
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
val bottomSheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
|
||||
|
||||
var text by remember { mutableStateOf("") }
|
||||
var clickable by remember { mutableStateOf(false) }
|
||||
val datePickerState = rememberDatePickerState()
|
||||
var text by remember { mutableStateOf("${curRecord?.weight ?: ""}") }
|
||||
var clickable = text.isNotEmpty()
|
||||
|
||||
|
||||
if (expandBottomSheet) {
|
||||
val datePickerState = rememberDatePickerState(
|
||||
initialSelectedDateMillis = curRecord?.date?.toInstant(ZoneOffset.UTC)?.toEpochMilli()
|
||||
)
|
||||
|
||||
ModalBottomSheet(
|
||||
onDismissRequest = onDismiss,
|
||||
sheetState = bottomSheetState
|
||||
|
|
@ -239,8 +280,20 @@ fun BottomSheetEditor(
|
|||
modifier = Modifier.fillMaxWidth(),
|
||||
onValueChange = {
|
||||
val newVal = it.toFloatOrNull()
|
||||
if ((it.isNotEmpty() && newVal == null) || (newVal !=null && newVal > 1000f)) {
|
||||
Toast.makeText(context, "只能输入数字,且要求数字小于1000", Toast.LENGTH_SHORT).show()
|
||||
if ((it.isNotEmpty() && newVal == null) || (newVal != null && newVal > 1000f)) {
|
||||
Toast.makeText(
|
||||
context,
|
||||
"只能输入数字,且要求数字小于1000",
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
return@OutlinedTextField
|
||||
}
|
||||
if (it.length > 6) {
|
||||
Toast.makeText(
|
||||
context,
|
||||
"数字长度不能超过6位",
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
return@OutlinedTextField
|
||||
}
|
||||
text = it
|
||||
|
|
@ -248,9 +301,11 @@ fun BottomSheetEditor(
|
|||
},
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier
|
||||
Spacer(
|
||||
modifier = Modifier
|
||||
.height(20.dp)
|
||||
.fillMaxWidth())
|
||||
.fillMaxWidth()
|
||||
)
|
||||
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
|
|
@ -258,7 +313,7 @@ fun BottomSheetEditor(
|
|||
DatePicker(
|
||||
state = datePickerState,
|
||||
modifier = Modifier.padding(16.dp),
|
||||
title = { Text(text="称重日期") },
|
||||
title = { Text(text = "称重日期") },
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -281,9 +336,13 @@ fun BottomSheetEditor(
|
|||
Spacer(modifier = Modifier.size(60.dp))
|
||||
Button(
|
||||
onClick = {
|
||||
Toast.makeText(context, "save weight", Toast.LENGTH_SHORT).show()
|
||||
Log.e(TAG, "BottomSheetEditor: ${Date(datePickerState.selectedDateMillis!!)}")
|
||||
weightTrackViewModel.addWeightRecord(WeightRecord(weight = text.toFloat(), date = LocalDateTime.now()))
|
||||
val newDate = LocalDateTime.ofInstant(
|
||||
Instant.ofEpochMilli(datePickerState.selectedDateMillis!!),
|
||||
ZoneId.systemDefault()
|
||||
)
|
||||
val newRecord = curRecord?.copy(weight = text.toFloat(), date = newDate)
|
||||
?: WeightRecord(weight = text.toFloat(), date = newDate)
|
||||
weightTrackViewModel.addWeightRecord(newRecord)
|
||||
text = ""
|
||||
onDismiss()
|
||||
},
|
||||
|
|
@ -297,6 +356,5 @@ fun BottomSheetEditor(
|
|||
Spacer(modifier = Modifier.size(40.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,34 +1,31 @@
|
|||
package com.eacenic.weighttrack
|
||||
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.lifecycle.ViewModel
|
||||
import io.objectbox.kotlin.boxFor
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import java.time.LocalDateTime
|
||||
import java.util.Arrays
|
||||
|
||||
const val TAG = "WeightTrackViewModel"
|
||||
class WeightTrackViewModel: ViewModel() {
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
private var _historyData = MutableStateFlow<List<WeightRecord>>(mutableListOf<WeightRecord>(
|
||||
WeightRecord(weight = 62.6f, date = LocalDateTime.now()),
|
||||
WeightRecord(weight = 63.6f, date = LocalDateTime.now()),
|
||||
WeightRecord(weight = 65.6f, date = LocalDateTime.now())
|
||||
))
|
||||
|
||||
private var _historyData = MutableStateFlow<List<WeightRecord>>(mutableListOf<WeightRecord>())
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
val historyData: StateFlow<List<WeightRecord>> = _historyData
|
||||
|
||||
private var _curRecord = MutableStateFlow<WeightRecord?>(null)
|
||||
val newestRecord = _curRecord
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
fun addWeightRecord(newRecord: WeightRecord) {
|
||||
saveWeightRecord(newRecord)
|
||||
loadWeightRecords()
|
||||
}
|
||||
|
||||
private val weightBox = WeightTrackObjectBox.store.boxFor(WeightRecord::class.java)
|
||||
private val weightBox = WeightTrackObjectBox.store.boxFor(WeightRecord::class)
|
||||
|
||||
private fun saveWeightRecord(weightRecord: WeightRecord) {
|
||||
weightBox.put(weightRecord)
|
||||
|
|
@ -37,6 +34,10 @@ class WeightTrackViewModel: ViewModel() {
|
|||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
fun loadWeightRecords() {
|
||||
val storedData = weightBox.all
|
||||
storedData.sortByDescending { it.date }
|
||||
_historyData.value = storedData
|
||||
if (storedData.isNotEmpty()) {
|
||||
_curRecord.value = storedData[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="297dp"
|
||||
android:height="210dp"
|
||||
android:viewportWidth="297"
|
||||
android:viewportHeight="210">
|
||||
<path
|
||||
android:pathData="M21.15,51.45L21.15,51.45A24.41,14.3 90,0 1,35.44 75.85L35.44,133.96A24.41,14.3 90,0 1,21.15 158.37L21.15,158.37A24.41,14.3 90,0 1,6.85 133.96L6.85,75.85A24.41,14.3 90,0 1,21.15 51.45z"
|
||||
android:strokeWidth="0.59"
|
||||
android:fillColor="#000000"/>
|
||||
<path
|
||||
android:pathData="M115.64,88.33l63.41,0l0,33.15l-63.41,0z"
|
||||
android:strokeWidth="0.49"
|
||||
android:fillColor="#000000"/>
|
||||
<path
|
||||
android:pathData="m76.68,15.39c-22.04,0 -39.78,18.23 -39.78,40.87l0,97.3c0,22.64 17.74,40.87 39.78,40.87 22.04,0 39.78,-18.23 39.78,-40.87L116.46,56.26c0,-22.64 -17.74,-40.87 -39.78,-40.87zM76.68,52.69c7.35,0 13.26,10.63 13.26,23.84l0,56.76c0,13.21 -5.92,23.84 -13.26,23.84 -7.35,0 -13.26,-10.63 -13.26,-23.84L63.42,76.53c0,-13.21 5.91,-23.84 13.26,-23.84z"
|
||||
android:strokeWidth="1.28"
|
||||
android:fillColor="#666666"/>
|
||||
<path
|
||||
android:pathData="m218.41,15.39c-22.04,0 -39.78,18.23 -39.78,40.87l0,97.3c0,22.64 17.74,40.87 39.78,40.87 22.04,0 39.78,-18.23 39.78,-40.87L258.2,56.26c0,-22.64 -17.74,-40.87 -39.78,-40.87zM218.41,52.69c7.35,0 13.26,10.63 13.26,23.84l0,56.76c0,13.21 -5.92,23.84 -13.26,23.84 -7.35,0 -13.26,-10.63 -13.26,-23.84L205.15,76.53c0,-13.21 5.91,-23.84 13.26,-23.84z"
|
||||
android:strokeWidth="1.28"
|
||||
android:fillColor="#666666"/>
|
||||
<path
|
||||
android:pathData="M274.77,51.45L274.77,51.45A24.41,14.3 90,0 1,289.07 75.85L289.07,133.96A24.41,14.3 90,0 1,274.77 158.37L274.77,158.37A24.41,14.3 90,0 1,260.48 133.96L260.48,75.85A24.41,14.3 90,0 1,274.77 51.45z"
|
||||
android:strokeWidth="0.59"
|
||||
android:fillColor="#000000"/>
|
||||
</vector>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 115 KiB |
Loading…
Reference in New Issue