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