From 2167ea58d1c297b0536d5cab6517707f1892b95f Mon Sep 17 00:00:00 2001
From: cloudroam <cloudroam>
Date: 星期五, 21 二月 2025 09:34:00 +0800
Subject: [PATCH] 登录;注册;关键字接口对接

---
 app/src/main/res/layout/item_layout.xml                                         |    9 
 app/src/main/res/values/styles.xml                                              |    8 
 app/src/main/res/drawable/login_robot.png                                       |    0 
 app/src/main/java/com/example/firstapp/database/repository/KeywordRepository.kt |   40 ++
 app/src/main/java/com/example/firstapp/core/Core.kt                             |    2 
 app/src/main/java/com/example/firstapp/ui/login/LoginViewModel.kt               |   45 ++
 app/src/main/res/xml/network_security_config.xml                                |    7 
 app/src/main/java/com/example/firstapp/database/dao/KeywordDao.kt               |   27 +
 .idea/vcs.xml                                                                   |    6 
 app/src/main/java/com/example/firstapp/database/AppDatabase.kt                  |   39 +
 app/src/main/java/com/example/firstapp/adapter/MyAdapter.kt                     |    4 
 app/src/main/java/com/example/firstapp/MainActivity.kt                          |  119 +++++-
 app/src/main/java/com/example/firstapp/activity/LoginActivity.kt                |   44 ++
 app/src/main/res/layout/activity_phone_login.xml                                |   95 +++++
 app/src/main/java/com/example/firstapp/database/entity/KeywordEntity.kt         |   13 
 app/src/main/java/com/example/firstapp/receiver/SmsReceiver.kt                  |   36 ++
 app/src/main/AndroidManifest.xml                                                |   11 
 app/src/main/java/com/example/firstapp/database/entity/Code.kt                  |    1 
 app/src/main/java/com/example/firstapp/database/service/ApiService.kt           |   30 +
 app/src/main/java/com/example/firstapp/workers/KeywordUpdateWorker.kt           |   31 +
 app/src/main/res/drawable/left_forward2.png                                     |    0 
 app/src/main/java/com/example/firstapp/activity/PhoneLoginActivity.kt           |   88 +++++
 app/src/main/res/layout/fragment_notifications.xml                              |  189 ++++++++++
 /dev/null                                                                       |   33 -
 app/src/main/java/com/example/firstapp/database/entity/KeywordConfig.kt         |   11 
 app/src/main/res/layout/activity_login.xml                                      |   88 +++++
 app/src/main/java/com/example/firstapp/App.kt                                   |    3 
 app/src/main/res/layout/dialog_feedback.xml                                     |    1 
 app/src/main/java/com/example/firstapp/database/entity/ApiResponse.kt           |    8 
 29 files changed, 908 insertions(+), 80 deletions(-)

diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="$PROJECT_DIR$" vcs="Git" />
+  </component>
+</project>
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 088e3d9..618fa3d 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -116,7 +116,10 @@
     <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
     <!--    允许广播蓝牙设备信息。-->
     <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
+    <!--    允许语言识别。-->
+    <uses-permission android:name="android.permission.RECORD_AUDIO" />
 
+<!-- 去掉主题   android:theme="@style/Theme.FirstApp"    android:theme="@style/Theme.AppCompat.Light.NoActionBar"-->
     <application
         android:name=".App"
         android:allowBackup="true"
@@ -127,9 +130,11 @@
         android:roundIcon="@mipmap/ic_launcher_round"
         android:supportsRtl="true"
         android:theme="@style/Theme.FirstApp"
+        android:networkSecurityConfig="@xml/network_security_config"
+
         tools:targetApi="31">
         <activity
-            android:name=".MainActivity"
+            android:name=".activity.LoginActivity"
             android:exported="true"
             android:label="@string/app_name">
             <intent-filter>
@@ -138,6 +143,10 @@
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
+        <activity android:name=".MainActivity" />
+        <activity
+            android:name=".activity.PhoneLoginActivity"
+            android:exported="false" />
     </application>
 
 </manifest>
\ No newline at end of file
diff --git a/app/src/main/java/com/example/firstapp/App.kt b/app/src/main/java/com/example/firstapp/App.kt
index 93f6053..f46c3a9 100644
--- a/app/src/main/java/com/example/firstapp/App.kt
+++ b/app/src/main/java/com/example/firstapp/App.kt
@@ -23,7 +23,9 @@
 import com.hjq.language.OnLanguageListener
 import com.example.firstapp.core.Core
 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
@@ -65,6 +67,7 @@
     val database by lazy { AppDatabase.getInstance(this) }
     val msgRepository by lazy { MsgRepository(database.msgDao()) }
     val codeRepository by lazy { CodeRepository(database.codeDao()) }
+    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/MainActivity.kt b/app/src/main/java/com/example/firstapp/MainActivity.kt
index 9c9052d..df33c98 100644
--- a/app/src/main/java/com/example/firstapp/MainActivity.kt
+++ b/app/src/main/java/com/example/firstapp/MainActivity.kt
@@ -18,13 +18,20 @@
 import android.content.BroadcastReceiver
 import android.content.Context
 import android.content.Intent
+import android.net.Uri
 import androidx.lifecycle.ViewModelProvider
 import androidx.recyclerview.widget.LinearLayoutManager
 import androidx.recyclerview.widget.RecyclerView
+import androidx.work.ExistingPeriodicWorkPolicy
+import androidx.work.PeriodicWorkRequestBuilder
+import androidx.work.WorkManager
+import com.example.firstapp.activity.LoginActivity
 import com.example.firstapp.adapter.MyAdapter
-import com.example.firstapp.core.Core
-import com.example.firstapp.entity.Item
 import com.example.firstapp.ui.home.HomeViewModel
+import com.example.firstapp.utils.Log
+import com.example.firstapp.workers.KeywordUpdateWorker
+import java.util.Calendar
+import java.util.concurrent.TimeUnit
 
 class MainActivity : AppCompatActivity() {
 
@@ -41,18 +48,23 @@
         if (isGranted) {
             // 权限授予后注册短信监听器
             registerSmsReceiver()
+            syncRecentSms()
         } else {
             // 权限拒绝,提示用户
             Toast.makeText(this, "Permission Denied", Toast.LENGTH_SHORT).show()
         }
     }
 
+
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
 
         binding = ActivityMainBinding.inflate(layoutInflater)
         setContentView(binding.root)
-
+        setupViews()
+//        binding.btnLogout.setOnClickListener {
+//            logout()
+//        }
         // 在此位置初始化 homeViewModel
         homeViewModel = ViewModelProvider(this).get(HomeViewModel::class.java)
 
@@ -73,27 +85,14 @@
         if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_SMS) != android.content.pm.PackageManager.PERMISSION_GRANTED) {
             // 请求权限
             permissionRequest.launch(Manifest.permission.READ_SMS)
+            syncRecentSms()
         } else {
             // 权限已经授予,继续执行相关操作
             registerSmsReceiver()
+            syncRecentSms()
         }
-
-
-        // 模拟数据
-//        val items = listOf(
-//            Item(1, "First Item", "This is the first item description"),
-//            Item(2, "Second Item", "This is the second item description"),
-//            Item(3, "Third Item", "This is the third item description")
-//        )
-//
-//        val recyclerView = findViewById<RecyclerView>(R.id.recyclerView)
-//        recyclerView.layoutManager = LinearLayoutManager(this)
-//        recyclerView.adapter = MyAdapter(items)
-
-//        var codeList = Core.code.getAllDesc()
         val recyclerView = findViewById<RecyclerView>(R.id.recyclerView)
         recyclerView.layoutManager = LinearLayoutManager(this)
-//        recyclerView.adapter = MyAdapter(codeList)
 
         // 初始化适配器
         adapter = MyAdapter()
@@ -124,8 +123,92 @@
     }
 
     private fun registerSmsReceiver() {
+//        应用启动时执行 registerSmsReceiver()
+//        创建 SmsReceiver 实例
+//        注册广播接收器,开始监听短信
+//        等待新短信到达
+//        新短信到达时,系统发送广播
+//        SmsReceiver 的 onReceive 方法被调用
+//        处理短信内容
+//        发送数据更新广播
+//        MainActivity 接收到更新广播
+//        更新 UI
+        Log.d("SMS_DEBUG", "MainActivity收到数据更新广播")
         smsReceiver = SmsReceiver()
         val filter = IntentFilter(Telephony.Sms.Intents.SMS_RECEIVED_ACTION)
         registerReceiver(smsReceiver, filter)
     }
+
+    private fun setupKeywordUpdate() {
+        val updateRequest = PeriodicWorkRequestBuilder<KeywordUpdateWorker>(
+            1, TimeUnit.HOURS,  // 每小时更新一次
+            15, TimeUnit.MINUTES  // 灵活时间窗口
+        ).build()
+
+        WorkManager.getInstance(this).enqueueUniquePeriodicWork(
+            "keyword_update", ExistingPeriodicWorkPolicy.REPLACE, updateRequest
+        )
+    }
+
+    private fun setupViews() {
+        // 获取并显示当前登录的手机号
+        val phone =
+            getSharedPreferences("user_info", Context.MODE_PRIVATE).getString("phone", "") ?: ""
+
+//        binding.apply {
+//            tvPhone.text = "当前登录手机号:$phone"
+//        }
+    }
+
+    private fun logout() {
+        // 清除登录信息
+        getSharedPreferences("user_info", Context.MODE_PRIVATE)
+            .edit()
+            .clear()
+            .apply()
+
+        // 跳转回登录页
+        startActivity(Intent(this, LoginActivity::class.java))
+        finish()
+    }
+
+    private fun syncRecentSms() {
+        try {
+            val calendar = Calendar.getInstance()
+            calendar.add(Calendar.DAY_OF_YEAR, -3) // 获取3天前的时间
+            val threeDaysAgo = calendar.timeInMillis
+
+            val cursor = contentResolver.query(
+                Uri.parse("content://sms/sent"),
+                arrayOf("address", "body", "date"),
+                "date >= ?",
+                arrayOf(threeDaysAgo.toString()),
+                "date DESC"
+            )
+
+            cursor?.use {
+                while (cursor.moveToNext()) {
+                    val address = cursor.getString(cursor.getColumnIndexOrThrow("address"))
+                    val body = cursor.getString(cursor.getColumnIndexOrThrow("body"))
+                    val date = cursor.getLong(cursor.getColumnIndexOrThrow("date"))
+
+                    // 使用正则表达式提取验证码
+                    val regex = "\\d{4,6}".toRegex()
+                    val matchResult = regex.find(body)
+                    matchResult?.let { result ->
+                        val code = result.value
+                        // 使用 ViewModel 保存到数据库
+                        println("address")
+                        println(address)
+                        println(code)
+                        println(date)
+                       // homeViewModel.saveCode(address, code, date)
+                    }
+                }
+            }
+        } catch (e: Exception) {
+            e.printStackTrace()
+            Toast.makeText(this, "同步短信失败:${e.message}", Toast.LENGTH_SHORT).show()
+        }
+    }
 }
\ No newline at end of file
diff --git a/app/src/main/java/com/example/firstapp/activity/LoginActivity.kt b/app/src/main/java/com/example/firstapp/activity/LoginActivity.kt
new file mode 100644
index 0000000..3516e12
--- /dev/null
+++ b/app/src/main/java/com/example/firstapp/activity/LoginActivity.kt
@@ -0,0 +1,44 @@
+package com.example.firstapp.activity
+import android.os.Bundle
+import android.widget.Toast
+import androidx.appcompat.app.AppCompatActivity
+import android.content.Intent
+import com.example.firstapp.databinding.ActivityLoginBinding
+
+class LoginActivity : AppCompatActivity() {
+    private lateinit var binding: ActivityLoginBinding
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        binding = ActivityLoginBinding.inflate(layoutInflater)
+        setContentView(binding.root)
+        setupViews()
+    }
+
+    private fun setupViews() {
+        binding.btnStartLogin.setOnClickListener {
+            if (binding.cbAgreement.isChecked) {
+                try {
+                    val intent = Intent(this, PhoneLoginActivity::class.java)
+                    startActivity(intent)
+                    // 可以先不调用 finish(),确认跳转成功后再添加
+                     finish()
+                } catch (e: Exception) {
+                    e.printStackTrace()
+                    Toast.makeText(this, "跳转失败:${e.message}", Toast.LENGTH_SHORT).show()
+                }
+            } else {
+                Toast.makeText(this, "请先同意用户协议和隐私政策", Toast.LENGTH_SHORT).show()
+            }
+        }
+
+        binding.tvUserAgreement.setOnClickListener {
+            // 打开用户协议
+        }
+
+        binding.tvPrivacyPolicy.setOnClickListener {
+            // 打开隐私政策
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/firstapp/activity/PhoneLoginActivity.kt b/app/src/main/java/com/example/firstapp/activity/PhoneLoginActivity.kt
new file mode 100644
index 0000000..caec2fe
--- /dev/null
+++ b/app/src/main/java/com/example/firstapp/activity/PhoneLoginActivity.kt
@@ -0,0 +1,88 @@
+package com.example.firstapp.activity
+
+import android.content.Intent
+import android.os.Bundle
+import android.os.CountDownTimer
+import android.widget.Toast
+import androidx.activity.viewModels
+import androidx.appcompat.app.AppCompatActivity
+import com.example.firstapp.MainActivity
+import com.example.firstapp.databinding.ActivityPhoneLoginBinding
+import com.example.firstapp.ui.login.LoginViewModel
+import com.example.firstapp.utils.Log
+
+class PhoneLoginActivity : AppCompatActivity() {
+    private lateinit var binding: ActivityPhoneLoginBinding
+    private val viewModel: LoginViewModel by viewModels()
+    private var countDownTimer: CountDownTimer? = null
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        Log.d("PhoneLoginActivity", "onCreate called")
+        binding = ActivityPhoneLoginBinding.inflate(layoutInflater)
+        setContentView(binding.root)
+
+        setupViews()
+        observeViewModel()
+    }
+
+    private fun setupViews() {
+        binding.apply {
+            btnBack.setOnClickListener {
+                finish()
+            }
+
+            tvSendCode.setOnClickListener {
+                val phone = etPhone.text.toString()
+                if (phone.length == 11) {
+                    viewModel.sendVerificationCode(phone)
+                    startCountDown()
+//                    17625318565 111111
+                } else {
+                    Toast.makeText(this@PhoneLoginActivity,
+                        "请输入正确的手机号", Toast.LENGTH_SHORT).show()
+                }
+            }
+
+            btnLogin.setOnClickListener {
+                val phone = etPhone.text.toString()
+                val code = etCode.text.toString()
+                if (phone.length == 11 && code.length == 6) {
+                    viewModel.login(phone, code)
+                } else {
+                    Toast.makeText(this@PhoneLoginActivity,
+                        "请输入完整信息", Toast.LENGTH_SHORT).show()
+                }
+            }
+        }
+    }
+
+    private fun observeViewModel() {
+        viewModel.loginState.observe(this) { isLoggedIn ->
+            if (isLoggedIn) {
+                startActivity(Intent(this, MainActivity::class.java))
+                finishAffinity() // 结束所有之前的Activity
+            }
+        }
+    }
+
+    private fun startCountDown() {
+        binding.tvSendCode.isEnabled = false
+        countDownTimer?.cancel()
+        countDownTimer = object : CountDownTimer(60000, 1000) {
+            override fun onTick(millisUntilFinished: Long) {
+                binding.tvSendCode.text = "${millisUntilFinished / 1000}s"
+            }
+
+            override fun onFinish() {
+                binding.tvSendCode.isEnabled = true
+                binding.tvSendCode.text = "获取验证码"
+            }
+        }.start()
+    }
+
+    override fun onDestroy() {
+        super.onDestroy()
+        countDownTimer?.cancel()
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/firstapp/adapter/MyAdapter.kt b/app/src/main/java/com/example/firstapp/adapter/MyAdapter.kt
index d15ce6a..8c107fe 100644
--- a/app/src/main/java/com/example/firstapp/adapter/MyAdapter.kt
+++ b/app/src/main/java/com/example/firstapp/adapter/MyAdapter.kt
@@ -15,6 +15,7 @@
     class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
         val tvTitle: TextView = view.findViewById(R.id.tvTitle)
         val tvDescription: TextView = view.findViewById(R.id.tvDescription)
+        val overTimeMsg: TextView = view.findViewById(R.id.overTimeMsg)
     }
 
     override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
@@ -27,6 +28,9 @@
         val item = getItem(position) // 使用 getItem 来获取当前位置的 item
         holder.tvTitle.text = item.type // 假设 Code 类有一个 `type` 属性
         holder.tvDescription.text = item.code // 假设 Code 类有一个 `code` 属性
+        var overtime  = "请注意:当前取件免费截止时间是"+item.overtime+",超时会收取额外费用"
+        holder.overTimeMsg.text = overtime
+        println("打印......")
     }
 
     // 使用 DiffUtil 来优化列表更新
diff --git a/app/src/main/java/com/example/firstapp/adapter/MyAdapter2.kt b/app/src/main/java/com/example/firstapp/adapter/MyAdapter2.kt
deleted file mode 100644
index caea796..0000000
--- a/app/src/main/java/com/example/firstapp/adapter/MyAdapter2.kt
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.example.firstapp.adapter
-
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import android.widget.TextView
-import androidx.recyclerview.widget.RecyclerView
-import com.example.firstapp.R
-import com.example.firstapp.entity.Item
-
-class MyAdapter2(private val items: List<Item>) :
-    RecyclerView.Adapter<MyAdapter2.ViewHolder>() {
-
-    class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
-        val tvTitle: TextView = view.findViewById(R.id.tvTitle)
-        val tvDescription: TextView = view.findViewById(R.id.tvDescription)
-    }
-
-    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
-        val view = LayoutInflater.from(parent.context)
-            .inflate(R.layout.item_layout, parent, false)
-        return ViewHolder(view)
-    }
-
-    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
-        val item = items[position]
-        holder.tvTitle.text = item.title
-        holder.tvDescription.text = item.description
-    }
-
-    override fun getItemCount() = items.size
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/firstapp/adapter/MyAdapter_bak.kt b/app/src/main/java/com/example/firstapp/adapter/MyAdapter_bak.kt
deleted file mode 100644
index 33404e9..0000000
--- a/app/src/main/java/com/example/firstapp/adapter/MyAdapter_bak.kt
+++ /dev/null
@@ -1,33 +0,0 @@
-package com.example.firstapp.adapter
-
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import android.widget.TextView
-import androidx.recyclerview.widget.RecyclerView
-import com.example.firstapp.R
-import com.example.firstapp.database.entity.Code
-import com.example.firstapp.entity.Item
-
-class MyAdapter_bak(private val items: List<Code>) :
-    RecyclerView.Adapter<MyAdapter_bak.ViewHolder>() {
-
-    class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
-        val tvTitle: TextView = view.findViewById(R.id.tvTitle)
-        val tvDescription: TextView = view.findViewById(R.id.tvDescription)
-    }
-
-    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
-        val view = LayoutInflater.from(parent.context)
-            .inflate(R.layout.item_layout, parent, false)
-        return ViewHolder(view)
-    }
-
-    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
-        val item = items[position]
-        holder.tvTitle.text = item.type
-        holder.tvDescription.text = item.code
-    }
-
-    override fun getItemCount() = items.size
-}
\ 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 f1f55b4..47c3d20 100644
--- a/app/src/main/java/com/example/firstapp/core/Core.kt
+++ b/app/src/main/java/com/example/firstapp/core/Core.kt
@@ -4,6 +4,7 @@
 import androidx.work.Configuration
 import com.example.firstapp.App
 import com.example.firstapp.database.repository.CodeRepository
+import com.example.firstapp.database.repository.KeywordRepository
 import com.example.firstapp.database.repository.MsgRepository
 
 import kotlinx.coroutines.launch
@@ -13,6 +14,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 }
 
     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 42a1399..15e5bec 100644
--- a/app/src/main/java/com/example/firstapp/database/AppDatabase.kt
+++ b/app/src/main/java/com/example/firstapp/database/AppDatabase.kt
@@ -8,8 +8,10 @@
 import androidx.room.migration.Migration
 import androidx.sqlite.db.SupportSQLiteDatabase
 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.entity.Code
+import com.example.firstapp.database.entity.KeywordEntity
 import com.example.firstapp.database.entity.Msg
 import com.example.firstapp.utils.DATABASE_NAME
 import com.example.firstapp.utils.SettingUtils
@@ -20,15 +22,16 @@
 
 
 @Database(
-    entities = [ Msg::class, Code::class],
+    entities = [ Msg::class, Code::class, KeywordEntity::class],
 //    views = [LogsDetail::class],
-    version = 19,
+    version = 20,
     exportSchema = false
 )
 @TypeConverters(ConvertersDate::class)
 abstract class AppDatabase : RoomDatabase() {
     abstract fun msgDao(): MsgDao
     abstract fun codeDao(): CodeDao
+    abstract fun keywordDao(): KeywordDao
 
     companion object {
         @Volatile
@@ -81,21 +84,31 @@
                 //database.execSQL("Create table Msg as Select id,type,`from`,content,(case when sim_info like 'SIM1%' then '0' when sim_info like 'SIM2%' then '1' else '-1' end) as sim_slot,sim_info,sub_id,time from Logs where 1 = 1")
                 database.execSQL(
                     """
-CREATE TABLE "Msg" (
-  "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
-  "type" TEXT NOT NULL DEFAULT 'sms',
-  "from" TEXT NOT NULL DEFAULT '',
-  "content" TEXT NOT NULL DEFAULT '',
-  "sim_slot" INTEGER NOT NULL DEFAULT -1,
-  "sim_info" TEXT NOT NULL DEFAULT '',
-  "sub_id" INTEGER NOT NULL DEFAULT 0,
-  "time" INTEGER NOT NULL
-)
-""".trimIndent()
+                    CREATE TABLE "Msg" (
+                      "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+                      "type" TEXT NOT NULL DEFAULT 'sms',
+                      "from" TEXT NOT NULL DEFAULT '',
+                      "content" TEXT NOT NULL DEFAULT '',
+                      "sim_slot" INTEGER NOT NULL DEFAULT -1,
+                      "sim_info" TEXT NOT NULL DEFAULT '',
+                      "sub_id" INTEGER NOT NULL DEFAULT 0,
+                      "time" INTEGER NOT NULL
+                    )
+                """.trimIndent()
                 )
 
                 database.execSQL("CREATE UNIQUE INDEX \"index_Msg_id\" ON \"Msg\" ( \"id\" ASC)")
 
+                // 新增 KeywordEntity 表的创建逻辑
+                database.execSQL("""
+                    CREATE TABLE IF NOT EXISTS `keywords` (
+                        `id` INTEGER PRIMARY KEY AUTOINCREMENT, 
+                        `keyword` TEXT NOT NULL, 
+                        `type` TEXT NOT NULL, 
+                        `isEnabled` INTEGER 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
new file mode 100644
index 0000000..f4011d5
--- /dev/null
+++ b/app/src/main/java/com/example/firstapp/database/dao/KeywordDao.kt
@@ -0,0 +1,27 @@
+package com.example.firstapp.database.dao
+
+import androidx.room.Dao
+import androidx.room.Insert
+import androidx.room.OnConflictStrategy
+import androidx.room.Query
+import androidx.room.Update
+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>
+
+//    @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>
+}
diff --git a/app/src/main/java/com/example/firstapp/database/entity/ApiResponse.kt b/app/src/main/java/com/example/firstapp/database/entity/ApiResponse.kt
new file mode 100644
index 0000000..40a0f4b
--- /dev/null
+++ b/app/src/main/java/com/example/firstapp/database/entity/ApiResponse.kt
@@ -0,0 +1,8 @@
+package com.example.firstapp.database.entity
+
+data class ApiResponse<T>(
+    val status: Int,
+    val msg: String,
+    val info: String,
+    val data: T
+)
diff --git a/app/src/main/java/com/example/firstapp/database/entity/Code.kt b/app/src/main/java/com/example/firstapp/database/entity/Code.kt
index 24f5223..a4cf519 100644
--- a/app/src/main/java/com/example/firstapp/database/entity/Code.kt
+++ b/app/src/main/java/com/example/firstapp/database/entity/Code.kt
@@ -14,5 +14,6 @@
     val ruleId: Long,
     val msgId: Long,
     val code: String,
+    var overtime: String,
     var time: Date = Date(),
 )
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
new file mode 100644
index 0000000..2a3e3a2
--- /dev/null
+++ b/app/src/main/java/com/example/firstapp/database/entity/KeywordConfig.kt
@@ -0,0 +1,11 @@
+package com.example.firstapp.database.entity
+
+/**
+ *   关键字策略匹配类
+ */
+data class KeywordConfig(
+    val id: Long = 0, // 自增长的 id
+    val type: String,
+    val keyword: String,
+    val isEnable: Boolean
+)
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
new file mode 100644
index 0000000..55226ec
--- /dev/null
+++ b/app/src/main/java/com/example/firstapp/database/entity/KeywordEntity.kt
@@ -0,0 +1,13 @@
+package com.example.firstapp.database.entity
+
+import androidx.room.Entity
+import androidx.room.PrimaryKey
+import java.util.*
+
+@Entity(tableName = "keywords")
+data class KeywordEntity(
+    @PrimaryKey(autoGenerate = true) val id: Long = 0, // 自增长的 id
+    val keyword: String,
+    val type: String,
+    val isEnabled: Boolean
+)
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
new file mode 100644
index 0000000..ef48270
--- /dev/null
+++ b/app/src/main/java/com/example/firstapp/database/repository/KeywordRepository.kt
@@ -0,0 +1,40 @@
+package com.example.firstapp.database.repository
+
+import com.example.firstapp.database.dao.KeywordDao
+import com.example.firstapp.database.entity.KeywordConfig
+import com.example.firstapp.database.entity.KeywordEntity
+import com.example.firstapp.database.service.ApiService
+
+class KeywordRepository(
+
+    private val apiService: ApiService,
+    //本地缓存
+    private val keywordDao: KeywordDao
+) {
+    suspend fun getKeywords(): List<KeywordEntity> {
+        return try {
+            // 从网络获取配置
+            val response = apiService.getKeywords()
+            if (response.status == 1) {
+                // 保存到本地数据库作为缓存
+                saveToLocal(response.data)
+                response.data
+            } else {
+                // 如果接口请求失败,使用本地缓存
+                keywordDao.getAllKeywords()
+            }
+        } catch (e: Exception) {
+            e.printStackTrace()  // 打印完整堆栈信息 [[3,5]]
+            // 或使用以下方式输出基本信息
+            println("网络请求异常: ${e.message}")  // 打印异常消息 [[5]]
+            // 网络错误时使用本地缓存
+            keywordDao.getAllKeywords()
+        }
+    }
+
+    private suspend fun saveToLocal(keywords: List<KeywordEntity>) {
+        true
+        //keywordDao.insertAll(keywords.map { it.toEntity() })
+    }
+}
+
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
new file mode 100644
index 0000000..0ff9daf
--- /dev/null
+++ b/app/src/main/java/com/example/firstapp/database/service/ApiService.kt
@@ -0,0 +1,30 @@
+package com.example.firstapp.database.service
+
+import com.example.firstapp.database.entity.ApiResponse
+import com.example.firstapp.database.entity.KeywordConfig
+import com.example.firstapp.database.entity.KeywordEntity
+import retrofit2.Retrofit
+import retrofit2.converter.gson.GsonConverterFactory
+import retrofit2.http.GET
+
+/**
+ * API调用接口
+ */
+interface ApiService {
+
+    @GET("keywords")
+    suspend fun getKeywords():ApiResponse<List<KeywordEntity>>  //异步挂起
+}
+
+// 创建Retrofit实例(单例)
+object RetrofitClient{
+
+    private const val BASE_URL ="http://47.96.225.205:9009/cloud/"
+
+    //添加Gson解析器,用于自动将JSON响应转换为Kotlin/Java对象
+    private val retrofit = Retrofit.Builder().baseUrl(BASE_URL).addConverterFactory(GsonConverterFactory.create()).build()
+
+    //通过动态代理技术创建ApiService接口的具体实现类
+    val apiService:ApiService = retrofit.create(ApiService::class.java)
+
+}
\ No newline at end of file
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 1c2a82f..18dc9ee 100644
--- a/app/src/main/java/com/example/firstapp/receiver/SmsReceiver.kt
+++ b/app/src/main/java/com/example/firstapp/receiver/SmsReceiver.kt
@@ -3,20 +3,30 @@
 import android.content.BroadcastReceiver
 import android.content.Context
 import android.content.Intent
+import android.os.Build
 import android.os.Bundle
 import android.provider.Telephony
 import android.telephony.SmsMessage
 import android.util.Log
+import androidx.annotation.RequiresApi
 import com.example.firstapp.core.Core
 import com.example.firstapp.database.entity.Code
 import com.example.firstapp.database.entity.Msg
+import com.example.firstapp.database.repository.KeywordRepository
 import com.example.firstapp.entity.Rule
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import java.time.LocalDateTime
+import java.time.format.DateTimeFormatter
 
 
 class SmsReceiver : BroadcastReceiver() {
 
 
+    @RequiresApi(Build.VERSION_CODES.O)
     override fun onReceive(context: Context, intent: Intent) {
+
         // 检查广播的 Action 是否为短信接收
         if (Telephony.Sms.Intents.SMS_RECEIVED_ACTION == intent.action) {
             // 获取短信内容
@@ -43,18 +53,42 @@
                     Rule("快递","菜鸟驿站","\\d{1,2}-\\d{1,2}-\\d{4}")
                 )
 
+                CoroutineScope(Dispatchers.IO).launch {
+                    Log.d("SmsReceiver", "CoroutineScope started")
+                    // 获取最新的关键词配置
+                    val keywords = Core.keyword.getKeywords()
+                    Log.d("keywords", keywords.toString())
+                    println(keywords)
+                    // 保存匹配的短信
+                    //saveMessage(content)
+                }
+
+
                 // 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)
+                        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/login/LoginViewModel.kt b/app/src/main/java/com/example/firstapp/ui/login/LoginViewModel.kt
new file mode 100644
index 0000000..6d102f4
--- /dev/null
+++ b/app/src/main/java/com/example/firstapp/ui/login/LoginViewModel.kt
@@ -0,0 +1,45 @@
+package com.example.firstapp.ui.login
+
+import android.app.Application
+import android.content.Context
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.viewModelScope
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
+import androidx.lifecycle.AndroidViewModel
+
+
+class LoginViewModel(application: Application) : AndroidViewModel(application) {
+    private val _loginState = MutableLiveData<Boolean>()
+    val loginState: LiveData<Boolean> = _loginState
+
+    fun sendVerificationCode(phone: String) {
+        viewModelScope.launch {
+            // 这里实现发送验证码的逻辑
+            // 模拟网络请求
+            delay(1000)
+            // 实际应用中需要调用后端API
+        }
+    }
+
+    fun login(phone: String, code: String) {
+        viewModelScope.launch {
+            // 模拟登录请求
+            delay(1000)
+            // 保存登录状态和手机号
+            saveLoginInfo(phone)
+            _loginState.value = true
+        }
+    }
+
+    private fun saveLoginInfo(phone: String) {
+        getApplication<Application>().getSharedPreferences(
+            "user_info", Context.MODE_PRIVATE
+        ).edit().apply {
+            putBoolean("is_logged_in", true)
+            putString("phone", phone)
+            apply()
+        }
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/firstapp/workers/KeywordUpdateWorker.kt b/app/src/main/java/com/example/firstapp/workers/KeywordUpdateWorker.kt
new file mode 100644
index 0000000..66cb31b
--- /dev/null
+++ b/app/src/main/java/com/example/firstapp/workers/KeywordUpdateWorker.kt
@@ -0,0 +1,31 @@
+package com.example.firstapp.workers
+
+import android.content.Context
+import androidx.work.CoroutineWorker
+import androidx.work.WorkerParameters
+import com.example.firstapp.database.dao.KeywordDao
+import com.example.firstapp.database.repository.KeywordRepository
+import com.example.firstapp.database.service.RetrofitClient
+
+class KeywordUpdateWorker(
+    context: Context,
+    params: WorkerParameters,
+    private val keywordDao: KeywordDao // 注入 KeywordDao
+) : CoroutineWorker(context, params) {
+
+    override suspend fun doWork(): Result {
+// 另外一种实例化的方式
+//        val database = AppDatabase.getInstance(applicationContext) // 获取数据库实例
+//        val keywordDao = database.keywordDao() // 获取 KeywordDao 实例
+//        val repository = KeywordRepository(RetrofitClient.apiService, keywordDao) // 传递 keywordDao
+
+        val repository = KeywordRepository(RetrofitClient.apiService,keywordDao)
+        return try {
+            // 更新配置
+            repository.getKeywords()
+            Result.success()
+        } catch (e: Exception) {
+            Result.retry()
+        }
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/left_forward2.png b/app/src/main/res/drawable/left_forward2.png
new file mode 100644
index 0000000..6011620
--- /dev/null
+++ b/app/src/main/res/drawable/left_forward2.png
Binary files differ
diff --git a/app/src/main/res/drawable/login_robot.png b/app/src/main/res/drawable/login_robot.png
new file mode 100644
index 0000000..73710d3
--- /dev/null
+++ b/app/src/main/res/drawable/login_robot.png
Binary files differ
diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml
new file mode 100644
index 0000000..7628148
--- /dev/null
+++ b/app/src/main/res/layout/activity_login.xml
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    android:padding="24dp">
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="欢迎来到"
+        android:textSize="24sp"
+        android:textColor="#333333" />
+
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="智信管家!"
+        android:textSize="28sp"
+        android:textStyle="bold"
+        android:textColor="#333333" />
+
+    <ImageView
+        android:id="@+id/ivLogo"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="24dp"
+        android:layout_marginBottom="24dp"
+        android:layout_weight="0"
+        android:scaleType="centerCrop"
+        android:src="@drawable/login_robot" />
+
+    <Button
+        android:id="@+id/btnStartLogin"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:padding="16dp"
+        android:text="手机号登录/注册"
+        android:textColor="#FFFFFF"
+        android:textSize="16sp"
+        android:backgroundTint="@color/cardview_dark_background"
+        app:cornerRadius="14dp" />
+
+
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:layout_marginTop="16dp"
+        android:orientation="horizontal">
+
+        <CheckBox
+            android:id="@+id/cbAgreement"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:checked="true" />
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="我已阅读并同意"
+            android:textSize="14sp" />
+
+        <TextView
+            android:id="@+id/tvUserAgreement"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="用户协议"
+            android:textColor="#2196F3"
+            android:textSize="14sp" />
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text=" &amp; "
+            android:textSize="14sp" />
+
+        <TextView
+            android:id="@+id/tvPrivacyPolicy"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="隐私政策"
+            android:textColor="#2196F3"
+            android:textSize="14sp" />
+    </LinearLayout>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_phone_login.xml b/app/src/main/res/layout/activity_phone_login.xml
new file mode 100644
index 0000000..ff6ddc4
--- /dev/null
+++ b/app/src/main/res/layout/activity_phone_login.xml
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    android:padding="24dp">
+
+    <ImageButton
+        android:id="@+id/btnBack"
+        android:layout_width="48dp"
+        android:layout_height="48dp"
+        android:background="?attr/selectableItemBackgroundBorderless"
+        android:src="@drawable/left_forward2"
+        android:padding="12dp" />
+
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="24dp"
+        android:text="手机登录"
+        android:textSize="24sp"
+        android:textStyle="bold"
+        android:textColor="#333333" />
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="32dp"
+        android:orientation="vertical">
+
+        <EditText
+            android:id="@+id/etPhone"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:background="@null"
+            android:hint="请输入手机号"
+            android:text="177625318565"
+            android:inputType="phone"
+            android:maxLength="11"
+            android:textSize="16sp"
+            android:padding="12dp"/>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="1dp"
+            android:background="#EEEEEE" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            android:layout_marginTop="16dp">
+
+            <EditText
+                android:id="@+id/etCode"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:background="@null"
+                android:hint="请输入验证码"
+                android:text="123456"
+                android:inputType="number"
+                android:maxLength="6"
+                android:textSize="16sp"
+                android:padding="12dp"/>
+
+            <TextView
+                android:id="@+id/tvSendCode"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:padding="12dp"
+                android:text="获取验证码"
+                android:textColor="#2196F3"/>
+        </LinearLayout>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="1dp"
+            android:background="#EEEEEE" />
+    </LinearLayout>
+
+    <Button
+        android:id="@+id/btnLogin"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="32dp"
+        android:backgroundTint="@color/cardview_dark_background"
+        android:text="登录"
+        android:textColor="#FFFFFF"
+        android:textSize="16sp"
+        android:padding="12dp"
+        app:cornerRadius="14dp"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/dialog_feedback.xml b/app/src/main/res/layout/dialog_feedback.xml
new file mode 100644
index 0000000..0519ecb
--- /dev/null
+++ b/app/src/main/res/layout/dialog_feedback.xml
@@ -0,0 +1 @@
+ 
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_notifications.xml b/app/src/main/res/layout/fragment_notifications.xml
index d417935..1e902cb 100644
--- a/app/src/main/res/layout/fragment_notifications.xml
+++ b/app/src/main/res/layout/fragment_notifications.xml
@@ -1,22 +1,183 @@
 <?xml version="1.0" encoding="utf-8"?>
-<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    tools:context=".ui.notifications.NotificationsFragment">
+    android:orientation="vertical">
 
+    <!-- 标题栏 -->
     <TextView
-        android:id="@+id/text_notifications"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_marginStart="8dp"
-        android:layout_marginTop="8dp"
-        android:layout_marginEnd="8dp"
-        android:textAlignment="center"
-        android:textSize="20sp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toTopOf="parent" />
-</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
+        android:background="#FFE4C4"
+        android:gravity="center"
+        android:padding="16dp"
+        android:text="终身会员"
+        android:textSize="18sp" />
+
+    <!-- 功能区标题 -->
+    <TextView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:padding="8dp"
+        android:text="功能"
+        android:textSize="14sp" />
+
+    <!-- 设置选项 -->
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical">
+
+        <!-- 设置提醒 -->
+        <RelativeLayout
+            android:id="@+id/settings_reminder"
+            style="@style/SettingsItem">
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_centerVertical="true"
+                android:text="设置提醒" />
+
+            <ImageView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_alignParentEnd="true"
+                android:layout_centerVertical="true"
+                android:src="@android:drawable/ic_menu_more" />
+        </RelativeLayout>
+
+        <!-- 取录与反馈 -->
+        <TextView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:padding="8dp"
+            android:text="取录与反馈"
+            android:textSize="14sp" />
+
+        <!-- 关于小红书 -->
+        <RelativeLayout
+            android:id="@+id/about_app"
+            style="@style/SettingsItem">
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_centerVertical="true"
+                android:text="关于小红书" />
+
+            <ImageView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_alignParentEnd="true"
+                android:layout_centerVertical="true"
+                android:src="@android:drawable/ic_menu_more" />
+        </RelativeLayout>
+
+        <!-- 邮件联系 -->
+        <RelativeLayout
+            android:id="@+id/email_contact"
+            style="@style/SettingsItem">
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_centerVertical="true"
+                android:text="邮件联系" />
+
+            <ImageView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_alignParentEnd="true"
+                android:layout_centerVertical="true"
+                android:src="@android:drawable/ic_menu_more" />
+        </RelativeLayout>
+
+        <!-- 意见与反馈 -->
+        <RelativeLayout
+            android:id="@+id/feedback"
+            style="@style/SettingsItem">
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_centerVertical="true"
+                android:text="意见与反馈" />
+
+            <ImageView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_alignParentEnd="true"
+                android:layout_centerVertical="true"
+                android:src="@android:drawable/ic_menu_more" />
+        </RelativeLayout>
+
+        <!-- 分享给好友 -->
+        <RelativeLayout
+            android:id="@+id/share_to_friends"
+            style="@style/SettingsItem">
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_centerVertical="true"
+                android:text="分享给好友" />
+
+            <ImageView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_alignParentEnd="true"
+                android:layout_centerVertical="true"
+                android:src="@android:drawable/ic_menu_more" />
+        </RelativeLayout>
+
+        <!-- 其他区域标题 -->
+        <TextView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:padding="8dp"
+            android:text="其他"
+            android:textSize="14sp" />
+
+        <!-- 隐私协议 -->
+        <RelativeLayout
+            android:id="@+id/privacy_policy"
+            style="@style/SettingsItem">
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_centerVertical="true"
+                android:text="隐私协议" />
+
+            <ImageView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_alignParentEnd="true"
+                android:layout_centerVertical="true"
+                android:src="@android:drawable/ic_menu_more" />
+        </RelativeLayout>
+
+        <!-- 如何使用 -->
+        <RelativeLayout
+            android:id="@+id/how_to_use"
+            style="@style/SettingsItem">
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_centerVertical="true"
+                android:text="如何使用" />
+
+            <ImageView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_alignParentEnd="true"
+                android:layout_centerVertical="true"
+                android:src="@android:drawable/ic_menu_more" />
+        </RelativeLayout>
+
+    </LinearLayout>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_layout.xml b/app/src/main/res/layout/item_layout.xml
index 22792ce..db8b51a 100644
--- a/app/src/main/res/layout/item_layout.xml
+++ b/app/src/main/res/layout/item_layout.xml
@@ -6,6 +6,8 @@
     android:orientation="vertical"
     android:padding="16dp">
 
+
+
     <TextView
         android:id="@+id/tvTitle"
         android:layout_width="match_parent"
@@ -19,4 +21,11 @@
         android:layout_height="wrap_content"
         android:textSize="14sp"
         android:layout_marginTop="4dp"/>
+
+    <TextView
+        android:id="@+id/overTimeMsg"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="4dp"
+        android:textSize="14sp" />
 </LinearLayout>
\ No newline at end of file
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..71ad41b
--- /dev/null
+++ b/app/src/main/res/values/styles.xml
@@ -0,0 +1,8 @@
+<style name="SettingsItem">
+    <item name="android:layout_width">match_parent</item>
+    <item name="android:layout_height">wrap_content</item>
+    <item name="android:padding">16dp</item>
+    <item name="android:background">?android:attr/selectableItemBackground</item>
+    <item name="android:clickable">true</item>
+    <item name="android:focusable">true</item>
+</style> 
\ No newline at end of file
diff --git a/app/src/main/res/xml/network_security_config.xml b/app/src/main/res/xml/network_security_config.xml
new file mode 100644
index 0000000..8da54fa
--- /dev/null
+++ b/app/src/main/res/xml/network_security_config.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<network-security-config>
+    <domain-config cleartextTrafficPermitted="true">
+        <domain includeSubdomains="true">47.96.225.205</domain>
+        <!-- 可添加其他域名或IP(如192.168.0.101) -->
+    </domain-config>
+</network-security-config>

--
Gitblit v1.9.3