下面的代码我把导入第三方包相关的代码都省略了
1. 主页面
-
HomeScreen:这是一个主屏幕的界面,它接收一个GoogleSignInClient对象、一个NavController对象和一个可选的modifier参数。它使用了LocalFocusManager来管理焦点,以及LocalBooksViewModel和LocalreadingRecordViewModel来获取和更新书籍和阅读记录的状态。它还包含了一个搜索框,用于过滤正在阅读的书籍列表,并且有一个悬浮按钮用于添加书籍。
-
Books:这个Composable函数用于显示一个书籍列表。它接收一个NavController对象、一个书籍列表books、一个可选的modifier参数、一个BookViewModel和一个ReadingRecordViewModel。它使用LazyColumn来懒加载列表项,并为每本书创建一个卡片,显示书籍的标题、封面、阅读状态和其他信息。还有一个按钮用于编辑书籍的笔记。
-
InputPageNumberDialogButton:这个Composable函数用于显示一个按钮,当点击时会弹出一个对话框,允许用户输入当前阅读的页码。它还包含了逻辑来更新书籍的阅读进度和阅读记录。
-
SmallAddButton:这是一个小的悬浮按钮,用于触发添加书籍的操作。
-
ExpandedDropdownMenuExample:这是一个下拉菜单,用于更改书籍的阅读状态(例如:正在阅读、已完成、搁置)。
app/src/main/java/com/example/BookRecord/HomeScreen.kt:
@Composable
fun HomeScreen(googleSignInClient: GoogleSignInClient,navController: NavController,//auth: FirebaseAuth, // 传入FirebaseAuth实例modifier: Modifier = Modifier,
){// 鼠标的焦点val focusManager = LocalFocusManager.current// 搜索文本状态var searchText by remember { mutableStateOf("") }val bookViewModel = LocalBooksViewModel.currentval readingRecordViewModel = LocalreadingRecordViewModel.current// 获取正在读的书籍列表val readingBooks by bookViewModel.readingBooks.observeAsState(initial = emptyList())// 搜索框和列表布局// 使得 Column 可点击,并在点击时清除焦点Scaffold(floatingActionButton = {SmallAddButton(onClick = {// 在这里定义点击悬浮按钮后的动作,比如打开添加图书的界面//navController.navigate("AddBooks")bookViewModel.addBook(bookTitle = "The Great Gatsby",bookImage = "https://images.app.goo.gl/5zUzBVRjTqKxDdeV8",author = "F. Scott Fitzgerald",pages = "300",status = BookStatus.READING,readPage = "0",press = "xxx",startTime = LocalDate.now())})},floatingActionButtonPosition = FabPosition.End, // 将按钮放在右下角){ paddingValues ->Column(modifier = Modifier.padding(paddingValues).clickable(onClick = { focusManager.clearFocus() }).padding(16.dp)){Row(modifier = Modifier.fillMaxWidth(),verticalAlignment = Alignment.CenterVertically // 垂直居中对齐 Row 内的元素) {Column(modifier = Modifier.weight(9f)){Text(text = "Books you are reading",fontSize = 25.sp,fontWeight = FontWeight.Bold,color = Color(0xFF6650a4),modifier = Modifier.padding(end = 5.dp) // 根据需要调整文本的右边距)}Column(modifier = Modifier.weight(1f),horizontalAlignment = Alignment.CenterHorizontally){IconButton(onClick = {FirebaseAuth.getInstance().signOut()googleSignInClient.signOut()navController.navigate("LoginScreen"){popUpTo(0) { inclusive = true }}}) {Icon(imageVector = Icons.Filled.Settings,contentDescription = "Setting",tint = Color(0xFF6650a4),modifier = Modifier.size(40.dp))}}}// 搜索框OutlinedTextField(value = searchText,onValueChange = { searchText = it },label = { Text("Filter book", color = Color(0xFF6650a4)) },modifier = Modifier.fillMaxWidth().padding(bottom = 4.dp).background(Color(0xFFF2F2F2), RoundedCornerShape(20.dp)), // 设置浅灰色背景和圆角形状shape = RoundedCornerShape(20.dp), // 设置输入框的四个角更圆滑trailingIcon = { // 在搜索框的右侧添加一个搜索图标Icon(imageVector = Icons.Filled.FilterAlt,contentDescription = "Search",modifier = Modifier.clickable { focusManager.clearFocus() })},)// 基于搜索文本过滤整个书籍列表,而不仅仅是标题val filteredBooks = readingBooks.filter { it.title.contains(searchText, ignoreCase = true) }// 将过滤后的书籍列表传递给 Books 函数Books(navController, books = filteredBooks,bookViewModel = bookViewModel, readingRecordViewModel = readingRecordViewModel)}}}@Composable
fun Books(navController: NavController, books: List<Book>, modifier: Modifier = Modifier,bookViewModel:BookViewModel,readingRecordViewModel:ReadingRecordViewModel) {val context = LocalContext.currentLazyColumn {items(books) { book -> // 正确使用 books 作为列表Card(modifier = Modifier.padding(4.dp).fillMaxWidth()){Row(modifier = Modifier.padding(10.dp).fillMaxWidth(), // 确保 Row 填充父容器宽度) {// 用 Image 替换原有的 Column 显示书名Box(modifier = Modifier){Image(// 把图片替换成 Book.imagepainter = painterResource(id = R.drawable.book1), // 确保你的图片资源正确contentDescription = "Book Image",modifier = Modifier.size(100.dp))}Box(modifier = Modifier.weight(1f)) {Row(modifier = Modifier.padding(top = 0.dp, start = 15.dp)){Text(text = book.title, fontSize = 13.sp)}Row(modifier = Modifier.padding(top = 40.dp, start = 15.dp)) {// 这个column 是一个 Expanded Dropdown MenuColumn(modifier = Modifier.weight(0.5f)){ExpandedDropdownMenuExample(bookViewModel= bookViewModel, book=book)}// 这个column 是一个方形的 buttonColumn(modifier = Modifier.weight(0.5f)){OutlinedButton(modifier = Modifier.height(30.dp).width(100.dp),contentPadding = PaddingValues(),shape = RoundedCornerShape(5.dp),onClick ={navController.navigate("EditNotesScreen/${book.id}")},//navController.navigate("EditNotesScreen/${book.id}")) {Text(text = "notes", fontSize = 15.sp)Icon(imageVector = Icons.Filled.EditNote,contentDescription = "Select",tint = Color(0xFF6650a4),modifier = Modifier.size(25.dp).padding(start = 5.dp, top = 5.dp))}}}Row(modifier = Modifier.padding(start = 15.dp,top = 72.dp)){Column(modifier = Modifier.weight(3.5f)) {Text(text = "From", fontSize = 12.sp)val formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd")val dateString = book.startTime.format(formatter)Text(text = dateString, fontSize = 12.sp)}// 已经读了多少天Column(modifier = Modifier.weight(2.5f)) {// 计算从开始阅读到现在的天数val daysRead = ChronoUnit.DAYS.between(book.startTime, LocalDate.now()).toInt()Text(text = daysRead.toString(), fontSize = 12.sp)Text(text = "days", fontSize = 12.sp)}Column(modifier = Modifier.weight(4f)){Row(){InputPageNumberDialogButton(bookViewModel=bookViewModel,book = book,readingRecordViewModel = readingRecordViewModel)Box(modifier = Modifier.padding(top = 13.dp,start = 2.dp)){Text(text = "/${book.pages}", fontSize = 12.sp)}}}}}}}}}
}@Composable
fun InputPageNumberDialogButton(bookViewModel: BookViewModel, book: Book,readingRecordViewModel: ReadingRecordViewModel ) {var showDialog by remember { mutableStateOf(false) }var pageNumber by remember { mutableStateOf(book.readpage.toString()) }// Button to show dialogBox(modifier = Modifier.padding(top = 5.dp)) {OutlinedButton(modifier = Modifier.height(25.dp).width(50.dp),contentPadding = PaddingValues(),shape = RoundedCornerShape(5.dp),onClick = {showDialog = true // Show dialog when button is clicked},) {Text(text = pageNumber, fontSize = 15.sp)}}// Dialog for inputif (showDialog) {Dialog(onDismissRequest = { showDialog = false }) {// Dialog contentSurface(shape = MaterialTheme.shapes.medium,modifier = Modifier.fillMaxWidth().padding(16.dp)) {Column(modifier = Modifier.padding(16.dp),horizontalAlignment = Alignment.CenterHorizontally) {Text("Enter the page number", style = MaterialTheme.typography.bodyLarge)Spacer(modifier = Modifier.height(8.dp))OutlinedTextField(value = pageNumber,onValueChange = { value ->// Update only if the input is numericif (value.all { it.isDigit() }) {pageNumber = value}},singleLine = true,modifier = Modifier.fillMaxWidth())Spacer(modifier = Modifier.height(8.dp))Button(onClick = {val oldPageNumber = book.readpage.toIntOrNull() ?: 0pageNumber.toIntOrNull()?.let { newPageNumber ->book.readpage = newPageNumber.toString()bookViewModel.updateBookReadPage(book, newPageNumber.toString())val pagesToAdd = newPageNumber - oldPageNumberif (pagesToAdd > 0) {val newReadingRecord = ReadingRecord(userId = book.userId,date = LocalDate.now(),readPages = pagesToAdd)readingRecordViewModel.insertReadingRecord(newReadingRecord)}showDialog = false}}) {Text("Done", fontSize = 15.sp)}}}}}
}@Composable
fun SmallAddButton(onClick: () -> Unit) {FloatingActionButton(onClick = { onClick() },modifier = Modifier.padding( bottom = 35.dp)) {Icon(Icons.Filled.Add, "Small floating action button.")}
}@Composable
fun ExpandedDropdownMenuExample(bookViewModel: BookViewModel, book: Book) {var expanded by remember { mutableStateOf(false) }val items = listOf("Reading", "Complete", "Lay Aside") // 匹配枚举的描述val statuses = listOf(BookStatus.READING, BookStatus.READ, BookStatus.ON_HOLD)var selectedIndex by remember { mutableStateOf(statuses.indexOf(book.status)) } // 初始选择基于书籍的当前状态val icons = listOf(Icons.Filled.MenuBook, Icons.Filled.Done, Icons.Filled.DeleteForever) // 对应状态的图标Column(modifier = Modifier.fillMaxWidth()) {OutlinedButton(modifier = Modifier.height(30.dp).width(100.dp),contentPadding = PaddingValues(start = 5.dp),shape = RoundedCornerShape(5.dp),onClick = { expanded = true },) {Icon(imageVector = icons[selectedIndex], // 显示当前选择的状态图标contentDescription = "Select",tint = Color(0xFF6650a4),modifier = Modifier.size(20.dp).padding(end = 3.dp))Text(text = items[selectedIndex], fontSize = 15.sp)Icon(imageVector = Icons.Filled.KeyboardArrowDown,contentDescription = "Select",tint = Color(0xFF6650a4),modifier = Modifier.size(20.dp))}DropdownMenu(expanded = expanded,onDismissRequest = { expanded = false },) {items.forEachIndexed { index, title ->DropdownMenuItem(text = { Text(title) },onClick = {selectedIndex = indexexpanded = false// 更新书籍状态bookViewModel.updateBookStatus(book, statuses[index])},leadingIcon = { Icon(icons[index], contentDescription = null) } // 为每个选项添加对应的图标)}}}
}
2. 书架页面
以下是代码的概括性解释:
-
BookShelf:这是一个书架界面的Composable函数,它接收一个NavController对象和一个可选的modifier参数。它使用了LocalFocusManager来管理焦点,以及LocalBooksViewModel来获取书籍的状态。它还包含了一个搜索框,用于过滤书架上的书籍列表,并且有一个可滚动的Tab行,用于在“读完”和“搁置”的书籍列表之间切换。
-
BookGrid:这个Composable函数用于以网格形式显示书籍列表。它接收一个NavController对象、一个BookViewModel和一个书籍列表books,以及一个可选的modifier参数。它使用LazyVerticalGrid来懒加载网格中的列表项,并为每本书创建一个卡片,显示书籍的封面和笔记数量。点击书籍封面会导航到一个笔记屏幕。
以下是代码中一些关键点的详细解释:
- BookShelf中的selectedTabIndex用于跟踪当前选中的Tab标签,它决定了显示“读完”的书籍列表还是“搁置”的书籍列表。
- BookShelf中的ScrollableTabRow组件用于创建可滚动的Tab行,用户可以通过点击不同的Tab来切换显示的书籍列表。
- BookGrid中的LazyVerticalGrid组件用于创建一个垂直滚动的网格布局,每行显示固定数量的书籍。
- BookGrid中的Card组件用于为每本书创建一个卡片,卡片中包含一个Image组件来显示书籍封面,以及一个Row组件来显示笔记图标和数量。
- BookGrid中的Image组件的点击事件被设置为导航到笔记屏幕,这通常用于查看或编辑书籍的笔记。
app/src/main/java/com/example/BookRecord/BookShelf.kt:
@Composable
fun BookShelf(navController: NavController,modifier: Modifier = Modifier,
){// 鼠标的焦点val focusManager = LocalFocusManager.current// 搜索文本状态var searchText by remember { mutableStateOf("") }//tab的标签var selectedTabIndex by remember { mutableStateOf(0) }val tabTitles = listOf("complete", "lay aside")val bookViewModel = LocalBooksViewModel.current// 获取读完的书籍列表val completeBooks by bookViewModel.completeBooks.observeAsState(initial = emptyList())// 获取搁置的书籍列表val layasideBooks by bookViewModel.layasideBooks.observeAsState(initial = emptyList())// 根据选中的Tab来决定展示哪个列表val booksToShow = if (selectedTabIndex == 0) completeBooks else layasideBooks// 搜索框和列表布局// 使得 Column 可点击,并在点击时清除焦点Column(modifier = modifier.clickable(onClick = { focusManager.clearFocus() }).padding(16.dp)) {Row(modifier = Modifier.fillMaxWidth().padding(0.dp),verticalAlignment = Alignment.CenterVertically // 垂直居中对齐 Row 内的元素) {Column(modifier = Modifier.weight(9f)) {Text(text = "Bookshelf",fontSize = 25.sp,fontWeight = FontWeight.Bold,color = Color(0xFF6650a4),modifier = Modifier.padding(end = 5.dp) // 根据需要调整文本的右边距)}Column(modifier = Modifier.weight(1f),horizontalAlignment = Alignment.CenterHorizontally) {// 使用一个图标,表示设置Icon(imageVector = Icons.Filled.Settings,contentDescription = "Setting",tint = Color(0xFF6650a4),modifier = Modifier.size(40.dp) // 根据需要调整图标的大小)}}// 搜索框OutlinedTextField(value = searchText,onValueChange = { searchText = it },label = { Text("Filter book", color = Color(0xFF6650a4)) },modifier = Modifier.fillMaxWidth().padding(bottom = 4.dp).background(Color(0xFFF2F2F2), RoundedCornerShape(20.dp)), // 设置浅灰色背景和圆角形状shape = RoundedCornerShape(20.dp), // 设置输入框的四个角更圆滑trailingIcon = { // 在搜索框的右侧添加一个搜索图标Icon(imageVector = Icons.Filled.FilterAlt,contentDescription = "Search",modifier = Modifier.clickable { focusManager.clearFocus() })},)// Tab 行ScrollableTabRow(selectedTabIndex = selectedTabIndex,edgePadding = 0.dp,contentColor = Color(0xFF6650a4),indicator = {},divider = {}) {tabTitles.forEachIndexed { index, title ->Tab(selected = selectedTabIndex == index,onClick = { selectedTabIndex = index },text = {Text(title,fontSize = 16.sp ,color = if (selectedTabIndex == index) Color(0xFF6650a4) else Color.Gray) })}}// 图书网格列表BookGrid(navController,viewModel= bookViewModel, books = booksToShow.filter { it.title.contains(searchText, ignoreCase = true) })}
}@Composable
fun BookGrid(navController:NavController,viewModel: BookViewModel,books: List<Book>, modifier: Modifier = Modifier) {val columns = 3 // 定义每行显示的书籍数量LazyVerticalGrid(columns = GridCells.Fixed(columns),modifier = modifier.padding(4.dp)) {items(books) { book ->val noteCount = viewModel.getNoteCountByBookId(book.id).observeAsState(initial = 0)Card(modifier = Modifier.aspectRatio(3f / 4f), // 假设每本书的尺寸比例为3:4colors = CardDefaults.cardColors(containerColor = Color.White) // 设置卡片背景色为白色) {Box {Image(painter = painterResource(id = R.drawable.book1), // 你的图片资源contentDescription = "Book Image",modifier = Modifier.fillMaxSize() // 填满 Card.clickable {navController.navigate("notesScreen/${book.id}")})// 笔记图标和数量显示在右下角Row(modifier = Modifier.align(Alignment.BottomEnd)) {Icon(imageVector = Icons.Default.Bookmark,contentDescription = "Note Icon",tint = Color.Gray, // 图标颜色,根据需要调整modifier = Modifier.size(20.dp))// 假设笔记数量为示例用,你可以根据实际情况动态设置Text(text = "${noteCount.value}",color = Color.Gray,fontSize = 15.sp,)}}}}}
}
3. 数据分析页面
-
颜色常量定义:定义了一系列颜色常量,用于图表、文本和背景等UI元素的颜色设置。
-
数据示例:提供了条形图和饼图的示例数据,但这些数据被注释掉了,表明它们可能用于测试或示例。
-
BarChart:这是一个Composable函数,用于绘制一个简单的条形图,显示每天阅读的页数。它使用Canvas API来绘制条形和文本。
-
DisplayTodayDate:这个Composable函数显示今天的日期,格式为“dd/MM/yyyy”。
-
PieChart:这是一个Composable函数,用于绘制一个饼图,显示书籍状态的分布。它使用Canvas API来绘制饼图的扇区和中心文本。
-
Legend:这个Composable函数为饼图提供一个图例,显示每个类别的颜色块和对应的数量。
-
BookStatusPieChart:这个Composable函数组合了PieChart和Legend,创建了一个书籍状态饼图及其图例。
-
TimeRangeSelection:这个Composable函数允许用户选择时间范围,例如“最近7天”或“最近15天”,并更新状态。
-
AnalyticsPage:这是一个主要的Composable函数,它组合了上述函数来构建一个完整的阅读统计页面。它包括页面标题、日期显示、时间范围选择、条形图、总阅读页数显示和书籍状态饼图。
-
AnalyticsScreen:这个Composable函数可能是分析页面的入口点,它调用AnalyticsPage来显示内容。
app/src/main/java/com/example/BookRecord/chart.kt:
// Define your color constants
val colorPrimary = Color(0xFF8C73B8)
val colorOnPrimary = Color(0xFFCCCCCC) // for text on primary color background
val colorRead = Color(0xBEB09AD8) // Green
val colorUnread = Color(0xD29CC9E7) // Red
val colorReading = Color(0xFF9EE0C2) // Blue
val colorBackground = Color(0xFFFFFFFF) // White or any other background color// Sample data for the bar chart, showing pages read each day.
//val readingData7Days = listOf(5, 2, 7, 3, 5, 4, 13) // 近7天
//val readingData15Days = List(15) { (1..20).random() } // 随机生成近30天的数据// Sample data for the pie chart, showing book status distribution.
//val bookShelfData = mapOf("have read" to 33, "lay aside" to 12, "reading" to 6)@Composable
fun BarChart(data: List<ReadingRecordDao.DailyReading>, modifier: Modifier = Modifier.fillMaxWidth().height(200.dp)) {Canvas(modifier = modifier) {val maxCount = data.maxOfOrNull { it.totalPages } ?: 1 // 保证除数不为零val barWidth = size.width / (data.size * 2f)data.forEachIndexed { index, dailyReading ->val barHeight = size.height * (dailyReading.totalPages.toFloat() / maxCount)val barTopLeft = Offset((barWidth / 2 + barWidth * 2 * index), size.height - barHeight)drawRect(color = colorPrimary, //topLeft = barTopLeft,size = Size(barWidth, barHeight))// 新增部分,用于绘制文本val textPaint = android.graphics.Paint().apply {color = android.graphics.Color.BLACK // 文本颜色textSize = 35f // 文本大小textAlign = android.graphics.Paint.Align.CENTER // 文本对齐方式}drawContext.canvas.nativeCanvas.drawText(dailyReading.totalPages.toString(), // 要绘制的文本barTopLeft.x + barWidth / 2, // 文本的x坐标,使其居中于柱子之上barTopLeft.y - 5f, // 文本的y坐标,略高于柱子顶部textPaint // 使用的画笔)}}
}@RequiresApi(0)
@Composable
fun DisplayTodayDate() {Column(modifier = Modifier.padding(0.dp)) {val formatter = org.threeten.bp.format.DateTimeFormatter.ofPattern("dd/MM/yyyy")Spacer(modifier = Modifier.height(10.dp))androidx.compose.material3.Text(text = "Data Until: ${LocalDate.now().format(formatter)}")}
}@Composable
fun PieChart(data: Map<String, Int>, modifier: Modifier = Modifier.size(150.dp)) {Canvas(modifier = modifier) {val total = data.values.sum()val center = Offset(size.width / 2, size.height / 2)val radius = size.minDimension / 2val holeRadius = radius * 0.6f // 中心空洞的半径var startAngle = -90f // 扇形图的起始角度data.forEach { (category, count) ->val sweepAngle = (count / total.toFloat()) * 360f // 扇形图的角度val color = when (category) { // 根据分类获取颜色"have read" -> colorRead"lay aside" -> colorUnread"reading" -> colorReadingelse -> Color.LightGray}drawArc(color = color, // 使用上面定义的颜色startAngle = startAngle,sweepAngle = sweepAngle,useCenter = false, // 画环形topLeft = Offset(center.x - radius, center.y - radius),size = Size(radius * 2, radius * 2), // 环形的尺寸style = Stroke(width = radius - holeRadius) // 环形的宽度)// 如果需要在每个扇区中绘制数字,可以在这里添加代码startAngle += sweepAngle // 下一个扇形的起始角度}// 绘制中心的文本val textPaint = android.graphics.Paint().apply {color = android.graphics.Color.BLACK // 文本颜色textSize = 40f // 文本大小textAlign = android.graphics.Paint.Align.CENTER // 文本对齐方式}drawContext.canvas.nativeCanvas.drawText("$total Books", // 中心的文字center.x, // 中心点x坐标center.y - (textPaint.ascent() + textPaint.descent()) / 2, // 中心点y坐标,垂直居中textPaint // 使用的画笔)}
}@Composable
fun Legend(data: Map<String, Int>, modifier: Modifier) {Column(modifier = modifier.padding(10.dp)) {data.forEach { (category, count) ->Row(verticalAlignment = Alignment.CenterVertically) {// 这里绘制标签颜色的小方块Box(modifier = Modifier.size(20.dp).background(when (category) {"have read" -> colorRead"lay aside" -> colorUnread"reading" -> colorReadingelse -> Color.LightGray}))Spacer(modifier = Modifier.width(4.dp))// 这里是类别名称和数量Text(text = "$category $count",modifier = Modifier.weight(1f))}Spacer(modifier = Modifier.height(2.dp))}}
}@Composable
fun BookStatusPieChart(data: Map<String, Int>) {Row(modifier = Modifier.fillMaxWidth().height(IntrinsicSize.Min).padding(start = 35.dp), // 这里添加左边距verticalAlignment = Alignment.CenterVertically) {// 饼状图占据行的一半宽度PieChart(data = data)Spacer(modifier = Modifier.width(60.dp))// 标签列表占据剩下的宽度Legend(data = data, modifier = Modifier.weight(1f))}
}@Composable
fun TimeRangeSelection(timeRange: String, onTimeRangeSelected: (String) -> Unit) {Column(verticalArrangement = Arrangement.Bottom) {Button(onClick = { onTimeRangeSelected("Last 7 Days") },modifier = Modifier.padding(end = 0.dp).size(129.dp, 35.dp),// 在按钮的右边添加间距colors = ButtonDefaults.buttonColors(backgroundColor = if (timeRange == "Las 7 Days") colorOnPrimary else Color.White)) {Text("Last 7 Days")}Spacer(modifier = Modifier.height(7.dp))Button(modifier = Modifier.size(129.dp,35.dp),onClick = { onTimeRangeSelected("Last 15 Days") },colors = ButtonDefaults.buttonColors(backgroundColor = if (timeRange == "Las 7 Days") colorOnPrimary else Color.White)) {Text("Last 15 Days")}}
}@Composable
fun AnalyticsPage() {val bookViewModel: BookViewModel = viewModel() // 获取ViewModelval readingRecordViewModel: ReadingRecordViewModel = viewModel() // 获取ReadingRecordViewModel// 使用compose的方式观察LiveDataval bookCounts by bookViewModel.bookCounts.observeAsState(initial = mapOf("have read" to 0,"lay aside" to 0,"reading" to 0))val readPagesLast7Days by readingRecordViewModel.readPagesLast7Days.observeAsState(emptyList())val readPagesLast15Days by readingRecordViewModel.readPagesLast15Days.observeAsState(emptyList())// State for the time range selection for the bar chart.var timeRange by remember { mutableStateOf("Last 7 Days") }// Function to calculate total pages read in the selected time range.// Function to calculate total pages read in the selected time range.fun calculateTotalPages(readings: List<ReadingRecordDao.DailyReading>): Int {return readings.sumOf { it.totalPages }}// State for the total pages read.//val totalPages by derivedStateOf { mutableStateOf(calculateTotalPages(if (timeRange == "Last 7 Days") readPagesLast7Days else readPagesLast15Days)) }val totalPages by derivedStateOf {calculateTotalPages(if (timeRange == "Last 7 Days") readPagesLast7Days else readPagesLast15Days)}val scrollState = rememberScrollState()//创建可滚动状态Column(modifier = Modifier.fillMaxSize().padding(15.dp).verticalScroll(scrollState)) { // 加上padding使内容不要紧贴屏幕边缘androidx.compose.material3.Text(text = "Reading Statistics",fontSize = 25.sp,fontWeight = FontWeight.Bold,color = Color(0xFF6650a4),modifier = Modifier.padding(end = 5.dp) // 根据需要调整文本的右边距)Spacer(modifier = Modifier.height(20.dp)) //Text(text = "✔️ Page Count Statistics",style = MaterialTheme.typography.h6,color = Color(0xFF01051D),modifier = Modifier.align(Alignment.Start) //)Spacer(modifier = Modifier.height(15.dp))Row(modifier = Modifier.fillMaxWidth()) {DisplayTodayDate()Spacer(modifier = Modifier.weight(1f)) // 这个Spacer会占据所有可用空间TimeRangeSelection(timeRange) { selectedRange ->timeRange = selectedRange}}Spacer(modifier = Modifier.height(15.dp)) // 添加间隔BarChart(data = if (timeRange == "Last 7 Days") readPagesLast7Days else readPagesLast15Days)Spacer(modifier = Modifier.height(15.dp)) // 添加间隔Text(text = " Total Pages Read in the $timeRange: $totalPages",style = MaterialTheme.typography.h6,fontSize = 15.sp,modifier = Modifier.align(Alignment.CenterHorizontally))Spacer(modifier = Modifier.height(50.dp)) // 标题和扇形图之间的间隔Text("📖 Book Status",style = MaterialTheme.typography.h6,color = Color(0xFF01051D),modifier = Modifier.align(Alignment.Start) //)Spacer(modifier = Modifier.height(60.dp)) // 标题和扇形图之间的间隔BookStatusPieChart(data = bookCounts)}
}@Composable
fun AnalyticsScreen(navController: NavController, modifier: Modifier = Modifier) {AnalyticsPage()
}