加入图书页面以及和图片相关的viewmodel代码
1.加入图书页面
- AddBookScreen:这是一个用于添加书籍的屏幕,它接收一个NavController对象和一个可选的modifier参数。
- 它首先定义了一个focusManager,用于管理键盘操作。
- 使用mutableStateOf创建了一个状态变量searchText,用于存储搜索框中的文本。
-
Column:使用Column构建了屏幕的主体布局,并设置了内边距。
-
Row:在Column中,使用Row布局创建了一个包含返回图标和搜索框的水平布局。
- IconButton:定义了一个返回图标按钮,点击时会调用navController.popBackStack()返回上一个导航目的地。
- Spacer:在返回图标和搜索框之间添加了空间。
- OutlinedTextField:定义了一个带有轮廓的文本字段,用于输入搜索内容。
- value和onValueChange参数用于控制文本字段的值和更改时的回调。
- label提供了文本字段的标签,指示用户可以搜索书名或作者。
- modifier用于设置文本字段的背景颜色和圆角形状。
- colors参数自定义了文本字段的颜色,包括光标颜色、聚焦时的边框颜色和非聚焦时的边框颜色。
- singleLine设置为true,表示文本字段为单行输入。
- trailingIcon在文本字段的右侧显示一个清除图标,当文本字段中有内容时显示,点击可以清空文本字段。
- keyboardActions定义了键盘操作,其中onSearch用于处理搜索逻辑,同时隐藏键盘。
- keyboardOptions设置了键盘的输入模式为搜索,通常在键盘上显示一个搜索按钮。
app/src/main/java/com/example/BookRecord/AddBooks.kt:
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AddBookScreen(navController: NavController,modifier: Modifier = Modifier,
) {// The focus manager to handle the keyboard actionsval focusManager = LocalFocusManager.current// State for search textvar searchText by remember { mutableStateOf("") }Column(modifier = modifier.padding(12.dp)) {Row(modifier = Modifier.fillMaxWidth(),verticalAlignment = Alignment.CenterVertically) {// Back icon with a larger touch target for better accessibilityIconButton(onClick = { navController.popBackStack() },modifier = Modifier.size(35.dp)) {Icon(imageVector = Icons.Filled.ArrowBack,contentDescription = "Back",tint = Color(0xFF6650a4))}Spacer(modifier = Modifier.width(10.dp)) // Add space between the icon and the search bar// Search input fieldOutlinedTextField(value = searchText,onValueChange = { searchText = it },label = { Text("Search by title, author", color = Color(0xFF6650a4)) },modifier = Modifier.fillMaxWidth().background(Color(0xFFF2F2F2), RoundedCornerShape(20.dp)), // 直接在这里设置背景颜色和形状shape = RoundedCornerShape(20.dp), // 设置输入框的形状colors = TextFieldDefaults.outlinedTextFieldColors(
// backgroundColor = Color(0xFFF2F2F2),cursorColor = Color(0xFF6650a4),focusedBorderColor = Color(0xFF6650a4),unfocusedBorderColor = Color(0xFF6650a4)),singleLine = true,trailingIcon = {if (searchText.isNotEmpty()) {IconButton(onClick = { searchText = "" }) {Icon(imageVector = Icons.Filled.Clear,contentDescription = "Clear",tint = Color(0xFF6650a4))}}},keyboardActions = KeyboardActions(onSearch = {focusManager.clearFocus() // Hide the keyboard// TODO: Implement the search logic here}),keyboardOptions = KeyboardOptions.Default.copy(imeAction = ImeAction.Search))}// TODO: Add the rest of your UI components here}
}
2. BookViewModel
-
BookStatus枚举:定义了书籍的三种状态,分别是正在阅读(READING)、已阅读(READ)和搁置(ON_HOLD)。
-
BookViewModel类:这是一个继承自AndroidViewModel的视图模型类,用于管理和存储书籍数据。
- 类的初始化块中,通过传入的Application对象获取了数据库的访问对象bookDao和noteDao,这些对象用于与数据库进行交互。
- bookRepository和noteRepository是用于数据操作的仓库类实例,它们封装了对数据库的直接访问。
- currentUserUID存储了当前登录用户的用户ID,用于将书籍与用户关联。
- allBooks是一个LiveData对象,用于观察所有书籍的数据变化。
- bookCounts是一个MutableLiveData对象,用于存储和更新书籍状态的计数。
- readingBooks、completeBooks和layasideBooks是MediatorLiveData对象,它们根据书籍的状态过滤allBooks中的数据。
- 在初始化块中,设置了MediatorLiveData的源为allBooks,并根据书籍的不同状态更新这些LiveData对象。
- updateBookCounts方法用于更新书籍状态的计数,并将其存储在bookCounts中。
- addBook方法用于添加新书籍到数据库中。
- deleteBook方法用于从数据库中删除书籍。
- updateBookStatus方法用于更新书籍的状态。
- updateBookReadPage方法用于更新书籍的已阅读页数。
- getNoteCountByBookId方法用于获取指定书籍的笔记数量。
app/src/main/java/com/example/BookRecord/BookViewModel.kt:
enum class BookStatus {READING, // 正在阅读READ, // 已阅读ON_HOLD // 搁置
}//在类的初始化块中,通过传入应用程序的 Application 对象,获取了数据库的访问对象 bookDao 和 noteDao
class BookViewModel(application: Application) : AndroidViewModel(application) {private val bookDao = AppDatabase.getDatabase(application).bookDao()private val noteDao = AppDatabase.getDatabase(application).noteDao()private val bookRepository = BookRepository(bookDao, viewModelScope)private val noteRepository = NoteRepository(noteDao)var currentUserUID = FirebaseAuth.getInstance().currentUser?.uidval allBooks: LiveData<List<Book>> = bookRepository.allBooksval bookCounts = MutableLiveData<Map<String, Int>>()// 使用 MediatorLiveData 替代 Transformations.mapval readingBooks = MediatorLiveData<List<Book>>()val completeBooks = MediatorLiveData<List<Book>>()val layasideBooks = MediatorLiveData<List<Book>>()init {readingBooks.addSource(allBooks) { books ->readingBooks.value = books.filter { it.status == BookStatus.READING }}completeBooks.addSource(allBooks) { books ->completeBooks.value = books.filter { it.status == BookStatus.READ }}layasideBooks.addSource(allBooks) { books ->layasideBooks.value = books.filter { it.status == BookStatus.ON_HOLD }}// Update book countsupdateBookCounts()}private fun updateBookCounts() {val counts = mutableMapOf("have read" to 0, "lay aside" to 0, "reading" to 0)allBooks.observeForever { books ->counts["have read"] = books.count { it.status == BookStatus.READ }counts["lay aside"] = books.count { it.status == BookStatus.ON_HOLD }counts["reading"] = books.count { it.status == BookStatus.READING }bookCounts.value = counts}}// 添加新书籍fun addBook(bookTitle: String, bookImage: String, author: String, pages: String, status: BookStatus, readPage: String, press: String,startTime: LocalDate) = viewModelScope.launch {val newBook = Book(userId = currentUserUID ?: "",//确保不会空,处理未登陆的情况title = bookTitle,image = bookImage,author = author,pages = pages,status = status,readpage = readPage,press = press,startTime = startTime // 设置当前日期为开始时间)bookRepository.insert(newBook)}// 删除书籍fun deleteBook(book: Book) = viewModelScope.launch {bookRepository.delete(book)}// 更新书籍状态fun updateBookStatus(book: Book, newStatus: BookStatus) = viewModelScope.launch {book.status = newStatusbookRepository.update(book)}// 更新已阅读页数fun updateBookReadPage(book: Book, readPage: String) = viewModelScope.launch {book.readpage = readPage // 确保属性名称与你的 Book 类一致bookRepository.update(book)}// 获取指定书籍的笔记数量fun getNoteCountByBookId(bookId: Int): LiveData<Int> {return noteRepository.getNoteCountByBookId(bookId)}}