From 0fce8fea0b83afb02b5d8780160787e87b8ceedb Mon Sep 17 00:00:00 2001 From: cloudroam <cloudroam> Date: 星期二, 25 二月 2025 08:43:47 +0800 Subject: [PATCH] 新增 --- app/src/main/java/com/example/firstapp/database/entity/Reminder.kt | 13 + app/src/main/java/com/example/firstapp/adapter/ReminderAdapter.kt | 39 ++++ app/src/main/java/com/example/firstapp/database/repository/KeywordRepository.kt | 11 app/src/main/java/com/example/firstapp/core/Core.kt | 2 app/src/main/java/com/example/firstapp/database/entity/KeywordEntity.kt | 2 app/src/main/java/com/example/firstapp/receiver/SmsReceiver.kt | 99 +++++++--- app/src/main/java/com/example/firstapp/ui/reminder/ReminderViewModel.kt | 33 +++ app/src/main/res/layout/fragment_reminder_settings.xml | 82 ++++++-- app/src/main/java/com/example/firstapp/database/dao/KeywordDao.kt | 36 ++- app/src/main/java/com/example/firstapp/database/service/ApiService.kt | 2 app/src/main/res/layout/item_reminder.xml | 39 ++++ app/src/main/java/com/example/firstapp/database/dao/ReminderDao.kt | 17 + app/src/main/java/com/example/firstapp/database/AppDatabase.kt | 15 + app/src/main/java/com/example/firstapp/database/entity/KeywordConfig.kt | 11 + app/src/main/java/com/example/firstapp/database/repository/ReminderRepository.kt | 21 ++ app/src/main/java/com/example/firstapp/App.kt | 18 - app/src/main/java/com/example/firstapp/ui/reminder/ReminderSettingsFragment.kt | 71 ++++++- 17 files changed, 408 insertions(+), 103 deletions(-) diff --git a/app/src/main/java/com/example/firstapp/App.kt b/app/src/main/java/com/example/firstapp/App.kt index f46c3a9..4e0a37b 100644 --- a/app/src/main/java/com/example/firstapp/App.kt +++ b/app/src/main/java/com/example/firstapp/App.kt @@ -3,14 +3,10 @@ import android.annotation.SuppressLint import android.app.Application import android.app.PendingIntent -import android.bluetooth.BluetoothAdapter -import android.bluetooth.BluetoothDevice import android.content.Context import android.content.Intent import android.content.IntentFilter import android.location.Geocoder -import android.net.ConnectivityManager -import android.net.wifi.WifiManager import android.os.Build import androidx.lifecycle.MutableLiveData import androidx.multidex.MultiDex @@ -20,34 +16,26 @@ import com.gyf.cactus.callback.CactusCallback import com.gyf.cactus.ext.cactus import com.hjq.language.MultiLanguages -import com.hjq.language.OnLanguageListener import com.example.firstapp.core.Core +import com.example.firstapp.database.repository.ReminderRepository import com.example.firstapp.database.repository.CodeRepository import com.example.firstapp.database.repository.KeywordRepository import com.example.firstapp.database.repository.MsgRepository import com.example.firstapp.database.service.RetrofitClient import com.example.firstapp.receiver.CactusReceiver -import com.example.firstapp.service.BluetoothScanService -import com.example.firstapp.service.HttpServerService -import com.example.firstapp.utils.ACTION_START import com.example.firstapp.utils.AppInfo -import com.example.firstapp.utils.CactusSave import com.example.firstapp.utils.FRONT_CHANNEL_ID import com.example.firstapp.utils.FRONT_CHANNEL_NAME import com.example.firstapp.utils.FRONT_NOTIFY_ID import com.example.firstapp.utils.FRPC_LIB_VERSION -import com.example.firstapp.utils.HistoryUtils import com.example.firstapp.utils.Log import com.example.firstapp.utils.SettingUtils -import com.example.firstapp.utils.SharedPreference import com.example.firstapp.utils.tinker.TinkerLoadLibrary import com.king.location.LocationClient import com.xuexiang.xutil.file.FileUtils import frpclib.Frpclib -import io.reactivex.Observable import io.reactivex.disposables.Disposable -import io.reactivex.schedulers.Schedulers import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.SupervisorJob import java.io.BufferedWriter @@ -57,8 +45,6 @@ import java.text.SimpleDateFormat import java.util.Date import java.util.Locale -import java.util.TimeZone -import java.util.concurrent.TimeUnit @Suppress("DEPRECATION") class App : Application(), CactusCallback, Configuration.Provider by Core { @@ -67,8 +53,10 @@ val database by lazy { AppDatabase.getInstance(this) } val msgRepository by lazy { MsgRepository(database.msgDao()) } val codeRepository by lazy { CodeRepository(database.codeDao()) } + val reminderRepository by lazy { ReminderRepository(database.reminderDao()) } val keywordRepository by lazy { KeywordRepository(RetrofitClient.apiService,database.keywordDao()) } + companion object { const val TAG: String = "SmsForwarder" diff --git a/app/src/main/java/com/example/firstapp/adapter/ReminderAdapter.kt b/app/src/main/java/com/example/firstapp/adapter/ReminderAdapter.kt new file mode 100644 index 0000000..fb4335b --- /dev/null +++ b/app/src/main/java/com/example/firstapp/adapter/ReminderAdapter.kt @@ -0,0 +1,39 @@ +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.ListAdapter +import androidx.recyclerview.widget.RecyclerView +import com.example.firstapp.database.entity.Reminder +import com.example.firstapp.databinding.ItemReminderBinding +import com.sun.mail.imap.protocol.FetchResponse.getItem + +class ReminderAdapter(private val onDelete: (Reminder) -> Unit) : + ListAdapter<Reminder, ReminderAdapter.ReminderViewHolder>(ReminderDiffCallback()) { + + class ReminderViewHolder(private val binding: ItemReminderBinding) : + RecyclerView.ViewHolder(binding.root) { + + fun bind(reminder: Reminder, onDelete: (Reminder) -> Unit) { + binding.textNickname.text = reminder.nickname + binding.textKeywords.text = reminder.keywords + binding.btnDelete.setOnClickListener { onDelete(reminder) } + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ReminderViewHolder { + return ReminderViewHolder( + ItemReminderBinding.inflate( + LayoutInflater.from(parent.context), parent, false + ) + ) + } + + override fun onBindViewHolder(holder: ReminderViewHolder, position: Int) { + holder.bind(getItem(position), onDelete) + } +} + +class ReminderDiffCallback : DiffUtil.ItemCallback<Reminder>() { + override fun areItemsTheSame(oldItem: Reminder, newItem: Reminder) = oldItem.id == newItem.id + override fun areContentsTheSame(oldItem: Reminder, newItem: Reminder) = oldItem == newItem +} \ No newline at end of file diff --git a/app/src/main/java/com/example/firstapp/core/Core.kt b/app/src/main/java/com/example/firstapp/core/Core.kt index 47c3d20..6a18b64 100644 --- a/app/src/main/java/com/example/firstapp/core/Core.kt +++ b/app/src/main/java/com/example/firstapp/core/Core.kt @@ -6,6 +6,7 @@ import com.example.firstapp.database.repository.CodeRepository import com.example.firstapp.database.repository.KeywordRepository import com.example.firstapp.database.repository.MsgRepository +import com.example.firstapp.database.repository.ReminderRepository import kotlinx.coroutines.launch @@ -15,6 +16,7 @@ val msg: MsgRepository by lazy { (app as App).msgRepository } val code: CodeRepository by lazy { (app as App).codeRepository } val keyword: KeywordRepository by lazy { (app as App).keywordRepository } + val reminder: ReminderRepository by lazy { (app as App).reminderRepository } fun init(app: Application) { this.app = app diff --git a/app/src/main/java/com/example/firstapp/database/AppDatabase.kt b/app/src/main/java/com/example/firstapp/database/AppDatabase.kt index 15e5bec..8c2b7c0 100644 --- a/app/src/main/java/com/example/firstapp/database/AppDatabase.kt +++ b/app/src/main/java/com/example/firstapp/database/AppDatabase.kt @@ -1,5 +1,6 @@ package com.example.firstapp + import android.content.Context import androidx.room.Database import androidx.room.Room @@ -10,9 +11,11 @@ import com.example.firstapp.database.dao.CodeDao import com.example.firstapp.database.dao.KeywordDao import com.example.firstapp.database.dao.MsgDao +import com.example.firstapp.database.dao.ReminderDao import com.example.firstapp.database.entity.Code import com.example.firstapp.database.entity.KeywordEntity import com.example.firstapp.database.entity.Msg +import com.example.firstapp.database.entity.Reminder import com.example.firstapp.utils.DATABASE_NAME import com.example.firstapp.utils.SettingUtils import com.example.firstapp.utils.TAG_LIST @@ -22,8 +25,7 @@ @Database( - entities = [ Msg::class, Code::class, KeywordEntity::class], -// views = [LogsDetail::class], + entities = [ Msg::class, Code::class, KeywordEntity::class, Reminder::class], version = 20, exportSchema = false ) @@ -32,6 +34,7 @@ abstract fun msgDao(): MsgDao abstract fun codeDao(): CodeDao abstract fun keywordDao(): KeywordDao + abstract fun reminderDao(): ReminderDao companion object { @Volatile @@ -108,6 +111,14 @@ `isEnabled` INTEGER NOT NULL ) """) +// database.execSQL(""" +// CREATE TABLE IF NOT EXISTS `reminders` ( +// id INTEGER PRIMARY KEY AUTOINCREMENT, +// type TEXT NOT NULL, +// nickname TEXT NOT NULL, +// keywords TEXT NOT NULL, +// ); +// """) } } diff --git a/app/src/main/java/com/example/firstapp/database/dao/KeywordDao.kt b/app/src/main/java/com/example/firstapp/database/dao/KeywordDao.kt index f4011d5..81a54e1 100644 --- a/app/src/main/java/com/example/firstapp/database/dao/KeywordDao.kt +++ b/app/src/main/java/com/example/firstapp/database/dao/KeywordDao.kt @@ -8,20 +8,30 @@ import com.example.firstapp.database.entity.KeywordConfig import com.example.firstapp.database.entity.KeywordEntity -@Dao -interface KeywordDao { - @Query("SELECT * FROM keywords") - fun getAllKeywords(): List<KeywordEntity> - +//@Dao +//interface KeywordDao { +// @Query("SELECT * FROM keywords") +// fun getAllKeywords(): List<KeywordEntity> +// // @Insert(onConflict = OnConflictStrategy.REPLACE) // suspend fun insertAll(keywords: List<KeywordEntity>) // -// @Query("DELETE FROM keywords") -// suspend fun deleteAll() // -// @Update -// suspend fun update(keyword: KeywordEntity) -// -// @Query("SELECT * FROM keywords WHERE isEnabled = 1") -// fun getEnabledKeywords(): List<KeywordConfig> -} +//// +//// @Query("DELETE FROM keywords") +//// suspend fun deleteAll() +//// +//// @Update +//// suspend fun update(keyword: KeywordEntity) +//// +//// @Query("SELECT * FROM keywords WHERE isEnabled = 1") +//// fun getEnabledKeywords(): List<KeywordConfig> +//} +@Dao +interface KeywordDao { + @Insert(onConflict = OnConflictStrategy.REPLACE) + fun insertAll(keywords: List<KeywordEntity>) + + @Query("SELECT * FROM keywords") + fun getAllKeywords(): List<KeywordEntity> +} \ No newline at end of file diff --git a/app/src/main/java/com/example/firstapp/database/dao/ReminderDao.kt b/app/src/main/java/com/example/firstapp/database/dao/ReminderDao.kt new file mode 100644 index 0000000..8c9b629 --- /dev/null +++ b/app/src/main/java/com/example/firstapp/database/dao/ReminderDao.kt @@ -0,0 +1,17 @@ +package com.example.firstapp.database.dao +import androidx.room.* +import com.example.firstapp.database.entity.Reminder +import kotlinx.coroutines.flow.Flow + +@Dao +interface ReminderDao { + + @Query("SELECT * FROM reminders ORDER BY type") + fun getAllReminders(): Flow<List<Reminder>> + + @Insert + fun insert(reminder: Reminder) + + @Delete + fun delete(reminder: Reminder) +} \ No newline at end of file diff --git a/app/src/main/java/com/example/firstapp/database/entity/KeywordConfig.kt b/app/src/main/java/com/example/firstapp/database/entity/KeywordConfig.kt index 2a3e3a2..c7cfca8 100644 --- a/app/src/main/java/com/example/firstapp/database/entity/KeywordConfig.kt +++ b/app/src/main/java/com/example/firstapp/database/entity/KeywordConfig.kt @@ -8,4 +8,13 @@ val type: String, val keyword: String, val isEnable: Boolean -) +){ + fun toEntity(): KeywordEntity { + return KeywordEntity( + id = id, // 确保与@Entity类字段匹配 + type = type, + keyword = keyword, + isEnabled = isEnable // 注意字段名是否一致(isEnabled vs isEnable) + ) + } +} diff --git a/app/src/main/java/com/example/firstapp/database/entity/KeywordEntity.kt b/app/src/main/java/com/example/firstapp/database/entity/KeywordEntity.kt index 55226ec..db51169 100644 --- a/app/src/main/java/com/example/firstapp/database/entity/KeywordEntity.kt +++ b/app/src/main/java/com/example/firstapp/database/entity/KeywordEntity.kt @@ -10,4 +10,4 @@ val keyword: String, val type: String, val isEnabled: Boolean -) +) \ No newline at end of file diff --git a/app/src/main/java/com/example/firstapp/database/entity/Reminder.kt b/app/src/main/java/com/example/firstapp/database/entity/Reminder.kt new file mode 100644 index 0000000..256b45d --- /dev/null +++ b/app/src/main/java/com/example/firstapp/database/entity/Reminder.kt @@ -0,0 +1,13 @@ +package com.example.firstapp.database.entity + +import androidx.room.Entity +import androidx.room.PrimaryKey + + +@Entity(tableName = "reminders") +data class Reminder( + @PrimaryKey(autoGenerate = true) val id: Long = 0, + val type: String, + val nickname: String, + val keywords: String +) \ No newline at end of file diff --git a/app/src/main/java/com/example/firstapp/database/repository/KeywordRepository.kt b/app/src/main/java/com/example/firstapp/database/repository/KeywordRepository.kt index ef48270..4b9caf7 100644 --- a/app/src/main/java/com/example/firstapp/database/repository/KeywordRepository.kt +++ b/app/src/main/java/com/example/firstapp/database/repository/KeywordRepository.kt @@ -18,7 +18,7 @@ if (response.status == 1) { // 保存到本地数据库作为缓存 saveToLocal(response.data) - response.data + keywordDao.getAllKeywords() } else { // 如果接口请求失败,使用本地缓存 keywordDao.getAllKeywords() @@ -32,9 +32,12 @@ } } - private suspend fun saveToLocal(keywords: List<KeywordEntity>) { - true - //keywordDao.insertAll(keywords.map { it.toEntity() }) + private suspend fun saveToLocal(keywords: List<KeywordConfig>) { +// keywords.map { it.toEntity() } +// keywordDao.insertAll(keywords) + val keywordEntities = keywords.map { it.toEntity() } + keywordDao.insertAll(keywordEntities) } + } diff --git a/app/src/main/java/com/example/firstapp/database/repository/ReminderRepository.kt b/app/src/main/java/com/example/firstapp/database/repository/ReminderRepository.kt new file mode 100644 index 0000000..6017712 --- /dev/null +++ b/app/src/main/java/com/example/firstapp/database/repository/ReminderRepository.kt @@ -0,0 +1,21 @@ +package com.example.firstapp.database.repository + +import com.example.firstapp.database.dao.ReminderDao +import androidx.annotation.WorkerThread +import com.example.firstapp.database.entity.Reminder +import kotlinx.coroutines.flow.Flow + +class ReminderRepository(private val reminderDao: ReminderDao) { + + val allReminders: Flow<List<Reminder>> = reminderDao.getAllReminders() + + @WorkerThread + fun insert(reminder: Reminder) { + reminderDao.insert(reminder) + } + + @WorkerThread + fun delete(reminder: Reminder) { + reminderDao.delete(reminder) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/firstapp/database/service/ApiService.kt b/app/src/main/java/com/example/firstapp/database/service/ApiService.kt index 0ff9daf..0df8e04 100644 --- a/app/src/main/java/com/example/firstapp/database/service/ApiService.kt +++ b/app/src/main/java/com/example/firstapp/database/service/ApiService.kt @@ -13,7 +13,7 @@ interface ApiService { @GET("keywords") - suspend fun getKeywords():ApiResponse<List<KeywordEntity>> //异步挂起 + suspend fun getKeywords():ApiResponse<List<KeywordConfig>> //异步挂起 } // 创建Retrofit实例(单例) diff --git a/app/src/main/java/com/example/firstapp/receiver/SmsReceiver.kt b/app/src/main/java/com/example/firstapp/receiver/SmsReceiver.kt index 18dc9ee..f6fcaa2 100644 --- a/app/src/main/java/com/example/firstapp/receiver/SmsReceiver.kt +++ b/app/src/main/java/com/example/firstapp/receiver/SmsReceiver.kt @@ -48,7 +48,7 @@ Log.d("SmsReceiver", "Received SMS msgId: ${msgId}") // 这里我要写个数组,并创建个对象存放一些内容,如这个对象的属性有匹配内容,正则表达式,并循环遍历 - val ruleList = listOf( + val ruleList = mutableListOf( Rule("快递","京东","\\d{6}"), Rule("快递","菜鸟驿站","\\d{1,2}-\\d{1,2}-\\d{4}") ) @@ -58,41 +58,76 @@ // 获取最新的关键词配置 val keywords = Core.keyword.getKeywords() Log.d("keywords", keywords.toString()) - println(keywords) - // 保存匹配的短信 - //saveMessage(content) + keywords.forEach { keyword -> + ruleList.add( + Rule( + keyword.type, + keyword.keyword, + "\\d{1,2}-\\d{1,2}-\\d{4}" + ) + ) + } + Log.d("RuleList", ruleList.toString()) + for (rule in ruleList) { + val code = rule.extractCodeFromMessage(messageBody.toString()) + + if (code!==null) { + Log.d("SmsReceiver", "Received SMS code: ${code}") + + + // 获取当前时间 + val currentTime = LocalDateTime.now() + // 加2小时 + val futureTime = currentTime.plusHours(2) + // 定义时间格式 + val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss") + // 转换为字符串 + val overtime = futureTime.format(formatter) + // 封装成一个Code对象,并保存在数据库中 + val code = Code(0, rule.type,1, rule.content,1, 1, msgId, code, overtime) + Core.code.insert(code) + Log.d("SMS_DEBUG", "新短信已保存到数据库") + // 发送广播通知数据已更新 + //"com.example.firstapp.DATA_UPDATED" 是一个自定义的广播 Action,相当于一个标识符或者说是一个频道名称。这个名称是我们自己定义的,通常使用应用的包名作为前缀,以避免与其他应用的广播冲突。 + val updateIntent = Intent("com.example.firstapp.DATA_UPDATED") + context.sendBroadcast(updateIntent) + Log.d("SMS_DEBUG", "发送数据更新广播") + }else{ + Log.d("SmsReceiver", "Received SMS code: 没有匹配到内容") + } + } } // kotlin 怎么创建一个类 - for (rule in ruleList) { - val code = rule.extractCodeFromMessage(messageBody.toString()) - - if (code!==null) { - Log.d("SmsReceiver", "Received SMS code: ${code}") - - - // 获取当前时间 - val currentTime = LocalDateTime.now() - // 加2小时 - val futureTime = currentTime.plusHours(2) - // 定义时间格式 - val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss") - // 转换为字符串 - val overtime = futureTime.format(formatter) - // 封装成一个Code对象,并保存在数据库中 - val code = Code(0, rule.type,1, rule.content,1, 1, msgId, code, overtime) - Core.code.insert(code) - Log.d("SMS_DEBUG", "新短信已保存到数据库") - // 发送广播通知数据已更新 - //"com.example.firstapp.DATA_UPDATED" 是一个自定义的广播 Action,相当于一个标识符或者说是一个频道名称。这个名称是我们自己定义的,通常使用应用的包名作为前缀,以避免与其他应用的广播冲突。 - val updateIntent = Intent("com.example.firstapp.DATA_UPDATED") - context.sendBroadcast(updateIntent) - Log.d("SMS_DEBUG", "发送数据更新广播") - }else{ - Log.d("SmsReceiver", "Received SMS code: 没有匹配到内容") - } - } +// for (rule in ruleList) { +// val code = rule.extractCodeFromMessage(messageBody.toString()) +// +// if (code!==null) { +// Log.d("SmsReceiver", "Received SMS code: ${code}") +// +// +// // 获取当前时间 +// val currentTime = LocalDateTime.now() +// // 加2小时 +// val futureTime = currentTime.plusHours(2) +// // 定义时间格式 +// val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss") +// // 转换为字符串 +// val overtime = futureTime.format(formatter) +// // 封装成一个Code对象,并保存在数据库中 +// val code = Code(0, rule.type,1, rule.content,1, 1, msgId, code, overtime) +// Core.code.insert(code) +// Log.d("SMS_DEBUG", "新短信已保存到数据库") +// // 发送广播通知数据已更新 +// //"com.example.firstapp.DATA_UPDATED" 是一个自定义的广播 Action,相当于一个标识符或者说是一个频道名称。这个名称是我们自己定义的,通常使用应用的包名作为前缀,以避免与其他应用的广播冲突。 +// val updateIntent = Intent("com.example.firstapp.DATA_UPDATED") +// context.sendBroadcast(updateIntent) +// Log.d("SMS_DEBUG", "发送数据更新广播") +// }else{ +// Log.d("SmsReceiver", "Received SMS code: 没有匹配到内容") +// } +// } } } diff --git a/app/src/main/java/com/example/firstapp/ui/reminder/ReminderSettingsFragment.kt b/app/src/main/java/com/example/firstapp/ui/reminder/ReminderSettingsFragment.kt index 4454886..5b26509 100644 --- a/app/src/main/java/com/example/firstapp/ui/reminder/ReminderSettingsFragment.kt +++ b/app/src/main/java/com/example/firstapp/ui/reminder/ReminderSettingsFragment.kt @@ -1,18 +1,30 @@ package com.example.firstapp.ui.reminder +import ReminderAdapter import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.ArrayAdapter import android.widget.Toast import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels import androidx.navigation.fragment.findNavController +import androidx.recyclerview.widget.LinearLayoutManager +import com.example.firstapp.App +import com.example.firstapp.database.entity.Reminder import com.example.firstapp.databinding.FragmentReminderSettingsBinding class ReminderSettingsFragment : Fragment() { private var _binding: FragmentReminderSettingsBinding? = null private val binding get() = _binding!! + + private val reminderViewModel: ReminderViewModel by viewModels { + ReminderViewModelFactory((requireActivity().application as App).reminderRepository) + } + + private lateinit var adapter: ReminderAdapter override fun onCreateView( inflater: LayoutInflater, @@ -26,21 +38,60 @@ override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - // 返回按钮点击事件 - binding.btnBack.setOnClickListener { + setupSpinner() + setupRecyclerView() + setupClickListeners() + observeReminders() + } + + private fun setupSpinner() { + val types = arrayOf("驿站", "财务", "其他") + val adapter = ArrayAdapter(requireContext(), android.R.layout.simple_spinner_item, types) + adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) + binding.spinnerType.adapter = adapter + } + + private fun setupRecyclerView() { + adapter = ReminderAdapter { reminder -> + reminderViewModel.deleteReminder(reminder) + } + binding.recyclerReminders.apply { + layoutManager = LinearLayoutManager(context) + this.adapter = this@ReminderSettingsFragment.adapter + } + } + + private fun setupClickListeners() { + binding.btnClose.setOnClickListener { findNavController().navigateUp() } - // 添加提醒按钮点击事件 binding.btnAddReminder.setOnClickListener { - val reminderText = binding.editQuickReminder.text.toString() - if (reminderText.isNotEmpty()) { - // TODO: 保存提醒到数据库 - Toast.makeText(context, "提醒已添加", Toast.LENGTH_SHORT).show() - binding.editQuickReminder.text.clear() - } else { - Toast.makeText(context, "请输入提醒内容", Toast.LENGTH_SHORT).show() + val type = binding.spinnerType.selectedItem.toString() + val nickname = binding.editNickname.text.toString() + val keywords = binding.editKeywords.text.toString() + + if (nickname.isBlank() || keywords.isBlank()) { + Toast.makeText(context, "请填写完整信息", Toast.LENGTH_SHORT).show() + return@setOnClickListener } + + reminderViewModel.insertReminder( + Reminder( + type = type, + nickname = nickname, + keywords = keywords + ) + ) + + binding.editNickname.text.clear() + binding.editKeywords.text.clear() + } + } + + private fun observeReminders() { + reminderViewModel.allReminders.observe(viewLifecycleOwner) { reminders -> + adapter.submitList(reminders) } } diff --git a/app/src/main/java/com/example/firstapp/ui/reminder/ReminderViewModel.kt b/app/src/main/java/com/example/firstapp/ui/reminder/ReminderViewModel.kt new file mode 100644 index 0000000..d1bab81 --- /dev/null +++ b/app/src/main/java/com/example/firstapp/ui/reminder/ReminderViewModel.kt @@ -0,0 +1,33 @@ +package com.example.firstapp.ui.reminder + +import androidx.lifecycle.* +import com.example.firstapp.database.entity.Reminder +import com.example.firstapp.database.repository.ReminderRepository +import kotlinx.coroutines.launch + +class ReminderViewModel(private val repository: ReminderRepository) : ViewModel() { + + // 使用 Flow 获取所有提醒 + val allReminders: LiveData<List<Reminder>> = repository.allReminders.asLiveData() + + // 插入新提醒 + fun insertReminder(reminder: Reminder) = viewModelScope.launch { + repository.insert(reminder) + } + + // 删除提醒 + fun deleteReminder(reminder: Reminder) = viewModelScope.launch { + repository.delete(reminder) + } +} + +// ViewModel Factory +class ReminderViewModelFactory(private val repository: ReminderRepository) : ViewModelProvider.Factory { + override fun <T : ViewModel> create(modelClass: Class<T>): T { + if (modelClass.isAssignableFrom(ReminderViewModel::class.java)) { + @Suppress("UNCHECKED_CAST") + return ReminderViewModel(repository) as T + } + throw IllegalArgumentException("Unknown ViewModel class") + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_reminder_settings.xml b/app/src/main/res/layout/fragment_reminder_settings.xml index 2a5addf..8403cd9 100644 --- a/app/src/main/res/layout/fragment_reminder_settings.xml +++ b/app/src/main/res/layout/fragment_reminder_settings.xml @@ -8,47 +8,81 @@ <RelativeLayout android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" - android:background="#FFFFFF" - android:elevation="4dp"> - - <!-- 返回按钮 --> - <ImageButton - android:id="@+id/btn_back" - android:layout_width="48dp" - android:layout_height="48dp" - android:layout_centerVertical="true" - android:background="?attr/selectableItemBackgroundBorderless" - android:src="@android:drawable/ic_menu_close_clear_cancel" - android:contentDescription="返回" /> + android:background="#FFFFFF"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" - android:text="标题" + android:text="新增短信提醒" android:textSize="18sp" android:textColor="#000000" /> + + <!-- 关闭按钮 --> + <ImageButton + android:id="@+id/btn_close" + android:layout_width="48dp" + android:layout_height="48dp" + android:layout_alignParentEnd="true" + android:layout_centerVertical="true" + android:background="?attr/selectableItemBackgroundBorderless" + android:src="@android:drawable/ic_menu_close_clear_cancel" /> </RelativeLayout> - <!-- 快速提醒输入框 --> - <EditText - android:id="@+id/edit_quick_reminder" + <!-- 提醒类型选择 --> + <Spinner + android:id="@+id/spinner_type" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="16dp" - android:background="@android:drawable/edit_text" - android:hint="快速提醒" - android:padding="12dp" /> + android:padding="12dp" + android:background="@android:drawable/btn_dropdown" /> - <!-- 添加提醒按钮 --> + <!-- 昵称输入框 --> + <EditText + android:id="@+id/edit_nickname" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginHorizontal="16dp" + android:hint="昵称" + android:padding="12dp" + android:background="@android:drawable/edit_text" /> + + <!-- 关键词输入框 --> + <EditText + android:id="@+id/edit_keywords" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_margin="16dp" + android:hint="关键词" + android:padding="12dp" + android:background="@android:drawable/edit_text" /> + + <!-- 已添加列表标题 --> <Button android:id="@+id/btn_add_reminder" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginHorizontal="16dp" - android:layout_marginTop="16dp" + android:layout_margin="16dp" android:backgroundTint="#03A9F4" - android:text="添加到提醒" + android:text="确定新增" android:textColor="#FFFFFF" /> -</LinearLayout> \ No newline at end of file + <TextView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:padding="16dp" + android:text="已添加列表" + android:textStyle="bold" /> + + <!-- 已添加列表 --> + <androidx.recyclerview.widget.RecyclerView + android:id="@+id/recycler_reminders" + android:layout_width="match_parent" + android:layout_height="221dp" + android:layout_weight="1" + android:padding="8dp" /> + + <!-- 确定新增按钮 --> + +</LinearLayout> \ No newline at end of file diff --git a/app/src/main/res/layout/item_reminder.xml b/app/src/main/res/layout/item_reminder.xml new file mode 100644 index 0000000..98b1aa9 --- /dev/null +++ b/app/src/main/res/layout/item_reminder.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="utf-8"?> +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:padding="12dp" + android:background="@android:color/white"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_toStartOf="@id/btn_delete" + android:orientation="vertical"> + + <TextView + android:id="@+id/text_nickname" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="16sp" + android:textColor="#000000" /> + + <TextView + android:id="@+id/text_keywords" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="4dp" + android:textSize="14sp" + android:textColor="#666666" /> + </LinearLayout> + + <ImageButton + android:id="@+id/btn_delete" + android:layout_width="24dp" + android:layout_height="24dp" + android:layout_alignParentEnd="true" + android:layout_centerVertical="true" + android:background="@null" + android:src="@android:drawable/ic_delete" /> + +</RelativeLayout> \ No newline at end of file -- Gitblit v1.9.3