基本视图完成,引入ObjectBox 还没有完成

dev
rayc 2024-03-02 17:25:54 +08:00
parent fce70dcda8
commit 783d2921f0
7 changed files with 265 additions and 40 deletions

View File

@ -1,6 +1,7 @@
plugins { plugins {
id("com.android.application") id("com.android.application")
id("org.jetbrains.kotlin.android") id("org.jetbrains.kotlin.android")
id("io.objectbox")
} }
android { android {
@ -67,5 +68,14 @@ dependencies {
debugImplementation("androidx.compose.ui:ui-tooling") debugImplementation("androidx.compose.ui:ui-tooling")
debugImplementation("androidx.compose.ui:ui-test-manifest") debugImplementation("androidx.compose.ui:ui-test-manifest")
// google fonts 感觉有些字体用不了
implementation("androidx.compose.ui:ui-text-google-fonts:1.6.1") implementation("androidx.compose.ui:ui-text-google-fonts:1.6.1")
// implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.6.1")
// implementation("androidx.compose.runtime:runtime-livedata:1.7.0")
// implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1")
// view model
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.6.1")
} }

View File

@ -3,6 +3,7 @@
xmlns:tools="http://schemas.android.com/tools"> xmlns:tools="http://schemas.android.com/tools">
<application <application
android:name=".WeightTrackApp"
android:allowBackup="true" android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules" android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules" android:fullBackupContent="@xml/backup_rules"

View File

@ -1,30 +1,42 @@
package com.eacenic.weighttrack package com.eacenic.weighttrack
import android.annotation.SuppressLint
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.widget.Toast
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.annotation.RequiresApi
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentHeight 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.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Surface import androidx.compose.material3.Surface
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
@ -32,18 +44,22 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.TextUnit import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.eacenic.weighttrack.ui.theme.WeightTrackTheme import com.eacenic.weighttrack.ui.theme.WeightTrackTheme
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
class MainActivity : ComponentActivity() { class MainActivity : ComponentActivity() {
@RequiresApi(Build.VERSION_CODES.O)
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContent { setContent {
WeightTrackTheme { WeightTrackTheme {
// A surface container using the 'background' color from the theme
Surface( Surface(
modifier = Modifier.fillMaxSize(), modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background color = MaterialTheme.colorScheme.background
@ -55,73 +71,93 @@ class MainActivity : ComponentActivity() {
} }
} }
@OptIn(ExperimentalMaterial3Api::class) @RequiresApi(Build.VERSION_CODES.O)
@Composable private val dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
fun WeightTrackLayout() {
val scope = rememberCoroutineScope() @SuppressLint("StateFlowValueCalledInComposition")
@RequiresApi(Build.VERSION_CODES.O)
@Composable
fun WeightTrackLayout(
weightTrackViewModel: WeightTrackViewModel = viewModel()
) {
val weightRecords by weightTrackViewModel.historyData.collectAsState()
var openBottomSheet by rememberSaveable { mutableStateOf(false) } var openBottomSheet by rememberSaveable { mutableStateOf(false) }
var bottomSheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
Surface( Surface(
modifier = Modifier.fillMaxSize(), modifier = Modifier.fillMaxSize(),
color = Color.Gray color = Color.White
) { ) {
Column { Column(
Row { modifier = Modifier.padding(horizontal = 20.dp)
CurrentWeight() ) {
} CurrentWeight(62.6f, Modifier.padding(top = 20.dp))
Button(onClick = { LazyColumn(
openBottomSheet = true modifier = Modifier.fillMaxHeight(0.9f)
}) {
Text(text = "添加")
}
}
if (openBottomSheet) {
ModalBottomSheet(
onDismissRequest = { openBottomSheet = false },
sheetState = bottomSheetState
) { ) {
Row { this.items(weightRecords) {
Button( // Text(text = "${it.weight}")
onClick = { WeightRecordItem(weightRecord = it)
scope.launch { bottomSheetState.hide() }.invokeOnCompletion {
if (!bottomSheetState.isVisible) {
openBottomSheet = false
}
}
}
) {
Text(text = "关闭")
}
} }
} }
EditButton(onClick = { openBottomSheet = true })
} }
BottomSheetEditor(
expandBottomSheet = openBottomSheet,
onDismiss = {
openBottomSheet = false
}
)
} }
} }
@RequiresApi(Build.VERSION_CODES.O)
@Composable @Composable
fun CurrentWeight() { fun WeightRecordItem(weightRecord: WeightRecord) {
Row ( Box(
modifier = Modifier modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()
.padding(vertical = 5.dp)
) {
Text(
text = "${weightRecord.weight}",
modifier = Modifier.align(Alignment.CenterStart),
fontFamily = doodleShadowFontFamily,
fontSize = 36.sp,
)
Text(
text = dateTimeFormatter.format(weightRecord.date),
modifier = Modifier.align(Alignment.CenterEnd),
fontFamily = doodleShadowFontFamily,
fontSize = 18.sp
)
}
}
@Composable
fun CurrentWeight(
currentWeight: Float,
modifier: Modifier = Modifier
) {
Row (
modifier = modifier
.wrapContentHeight() .wrapContentHeight()
.padding(20.dp)
.fillMaxWidth(), .fillMaxWidth(),
horizontalArrangement = Arrangement.Center horizontalArrangement = Arrangement.Center
) { ) {
Box( Box(
modifier = Modifier modifier = Modifier
.fillMaxWidth(0.9f) .fillMaxWidth()
.height(120.dp) .height(120.dp)
.clip(RoundedCornerShape(10.dp)) .clip(RoundedCornerShape(10.dp))
.background(Color.Cyan) .background(Color.Cyan)
) { ) {
Text( Text(
text = "62.6", text = "$currentWeight",
modifier = Modifier.align(Alignment.Center), modifier = Modifier.align(Alignment.Center),
fontSize = 80.sp, fontSize = 80.sp,
fontFamily = doodleShadowFontFamily fontFamily = doodleShadowFontFamily
@ -129,3 +165,115 @@ fun CurrentWeight() {
} }
} }
} }
@Composable
fun EditButton(
onClick: () -> Unit
) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Center,
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()
) {
Button(
modifier = Modifier
.height(48.dp)
.fillMaxWidth(),
shape = RoundedCornerShape(5.dp),
colors = ButtonDefaults.buttonColors(Color.Cyan),
onClick = onClick,
) {
Text(text = "ADD", color = Color.Black, fontSize = 36.sp, fontFamily = doodleShadowFontFamily)
}
}
}
@RequiresApi(Build.VERSION_CODES.O)
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun BottomSheetEditor(
expandBottomSheet: Boolean = false,
onDismiss: () -> Unit,
weightTrackViewModel: WeightTrackViewModel = viewModel()
) {
val context = LocalContext.current
val scope = rememberCoroutineScope()
val bottomSheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
var text by remember { mutableStateOf("") }
var clickable by remember { mutableStateOf(false) }
if (expandBottomSheet) {
ModalBottomSheet(
onDismissRequest = onDismiss,
sheetState = bottomSheetState
) {
Column(
modifier = Modifier
.wrapContentHeight()
.fillMaxWidth()
) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 20.dp)
) {
OutlinedTextField(
value = text,
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()
return@OutlinedTextField
}
text = it
clickable = text.isNotEmpty()
},
)
}
Spacer(modifier = Modifier
.height(20.dp)
.fillMaxWidth())
Row(
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth()
) {
Button(
onClick = {
scope.launch { bottomSheetState.hide() }.invokeOnCompletion {
if (!bottomSheetState.isVisible) {
onDismiss()
}
}
}
) {
Text(text = "CANCEL", fontSize = 18.sp, fontFamily = doodleShadowFontFamily)
}
Spacer(modifier = Modifier.size(60.dp))
Button(
onClick = {
Toast.makeText(context, "save weight", Toast.LENGTH_SHORT).show()
weightTrackViewModel.addWeightRecord(WeightRecord(text.toFloat(), LocalDateTime.now()))
text = ""
onDismiss()
},
enabled = clickable
) {
Text(text = "CONFIRM", fontSize = 18.sp, fontFamily = doodleShadowFontFamily)
}
}
Spacer(modifier = Modifier
.height(40.dp)
.fillMaxWidth())
}
}
}
}

View File

@ -0,0 +1,14 @@
package com.eacenic.weighttrack
import io.objectbox.annotation.Entity
import io.objectbox.annotation.Id
import java.time.LocalDateTime
@Entity
data class WeightRecord(
@Id
var id: Long = 0,
var weight: Float,
var date: LocalDateTime,
var isDeleted: Boolean = false
)

View File

@ -0,0 +1,11 @@
package com.eacenic.weighttrack
import android.app.Application
class WeightTrackApp: Application() {
override fun onCreate() {
super.onCreate()
}
}

View File

@ -0,0 +1,32 @@
package com.eacenic.weighttrack
import android.os.Build
import android.util.Log
import androidx.annotation.RequiresApi
import androidx.lifecycle.ViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import java.time.LocalDateTime
const val TAG = "WeightTrackViewModel"
class WeightTrackViewModel: ViewModel() {
@RequiresApi(Build.VERSION_CODES.O)
private var _historyData = MutableStateFlow<List<WeightRecord>>(mutableListOf<WeightRecord>(
WeightRecord(62.6f, LocalDateTime.now()),
WeightRecord(63.6f, LocalDateTime.now()),
WeightRecord(65.6f, LocalDateTime.now())
))
@RequiresApi(Build.VERSION_CODES.O)
val historyData: StateFlow<List<WeightRecord>> = _historyData
@RequiresApi(Build.VERSION_CODES.O)
fun addWeightRecord(newRecord: WeightRecord) {
val newRecords = _historyData.value.toMutableList()
newRecords.add(newRecord)
_historyData.value = newRecords
Log.e(TAG, "$newRecord")
Log.e(TAG, "${_historyData.value}")
}
}

View File

@ -1,4 +1,13 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules. // Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath("io.objectbox:objectbox-gradle-plugin:3.8.0")
}
}
plugins { plugins {
id("com.android.application") version "8.2.2" apply false id("com.android.application") version "8.2.2" apply false
id("org.jetbrains.kotlin.android") version "1.9.0" apply false id("org.jetbrains.kotlin.android") version "1.9.0" apply false