From b653b90d4598ee2a65bceffa793bb75353b6d186 Mon Sep 17 00:00:00 2001
From: cloudroam <cloudroam>
Date: 星期三, 26 二月 2025 17:21:53 +0800
Subject: [PATCH] add: 快递列表展示

---
 app/src/main/java/com/example/firstapp/adapter/ExpressAdapter.kt                 |   87 ++++++++
 app/src/main/java/com/example/firstapp/database/repository/CodeRepository.kt     |    4 
 app/src/main/java/com/example/firstapp/model/ExpressGroup.kt                     |   12 +
 app/src/main/res/navigation/mobile_navigation.xml                                |    2 
 app/src/main/java/com/example/firstapp/adapter/ReminderAdapter.kt                |    1 
 app/src/main/res/layout/item_express_package.xml                                 |   46 ++++
 app/src/main/java/com/example/firstapp/database/dao/CodeDao.kt                   |    7 
 app/src/main/res/layout/fragment_home.xml                                        |  130 ++++++++++--
 app/src/main/java/com/example/firstapp/ui/home/HomeViewModel.kt                  |   62 ++++-
 app/src/main/res/drawable/location.png                                           |    0 
 app/src/main/java/com/example/firstapp/database/dao/ReminderDao.kt               |    3 
 app/src/main/java/com/example/firstapp/ui/home/HomeFragment.kt                   |   82 +++++--
 app/src/main/java/com/example/firstapp/MainActivity.kt                           |   62 +++---
 app/src/main/java/com/example/firstapp/database/repository/ReminderRepository.kt |    5 
 app/src/main/res/layout/item_express_group.xml                                   |   54 +++++
 15 files changed, 459 insertions(+), 98 deletions(-)

diff --git a/app/src/main/java/com/example/firstapp/MainActivity.kt b/app/src/main/java/com/example/firstapp/MainActivity.kt
index df33c98..6abffe0 100644
--- a/app/src/main/java/com/example/firstapp/MainActivity.kt
+++ b/app/src/main/java/com/example/firstapp/MainActivity.kt
@@ -66,10 +66,10 @@
 //            logout()
 //        }
         // 在此位置初始化 homeViewModel
-        homeViewModel = ViewModelProvider(this).get(HomeViewModel::class.java)
-
-        val navView: BottomNavigationView = binding.navView
-
+//        homeViewModel = ViewModelProvider(this).get(HomeViewModel::class.java)
+//
+//        val navView: BottomNavigationView = binding.navView
+        val navView = binding.navView
         val navController = findNavController(R.id.nav_host_fragment_activity_main)
         // Passing each menu ID as a set of Ids because each
         // menu should be considered as top level destinations.
@@ -91,34 +91,34 @@
             registerSmsReceiver()
             syncRecentSms()
         }
-        val recyclerView = findViewById<RecyclerView>(R.id.recyclerView)
-        recyclerView.layoutManager = LinearLayoutManager(this)
+//        val recyclerView = findViewById<RecyclerView>(R.id.recyclerView)
+//        recyclerView.layoutManager = LinearLayoutManager(this)
+//
+//        // 初始化适配器
+//        adapter = MyAdapter()
+//        recyclerView.adapter = adapter
+//
+//        // 观察 LiveData 数据
+//        homeViewModel.codeList.observe(this) { codeList ->
+//            // 如果 codeList 为 null,避免闪退
+//            if (codeList != null) {
+//                adapter.submitList(codeList)
+//                // 滚动到顶部
+//                recyclerView.scrollToPosition(0)
+//            } else {
+//                // 如果数据为空,可以显示空列表或其他处理
+//                Toast.makeText(this, "No data available", Toast.LENGTH_SHORT).show()
+//            }
+//        }
 
-        // 初始化适配器
-        adapter = MyAdapter()
-        recyclerView.adapter = adapter
-
-        // 观察 LiveData 数据
-        homeViewModel.codeList.observe(this) { codeList ->
-            // 如果 codeList 为 null,避免闪退
-            if (codeList != null) {
-                adapter.submitList(codeList)
-                // 滚动到顶部
-                recyclerView.scrollToPosition(0)
-            } else {
-                // 如果数据为空,可以显示空列表或其他处理
-                Toast.makeText(this, "No data available", Toast.LENGTH_SHORT).show()
-            }
-        }
-
-        // 注册广播接收器来监听数据更新
-        val filter = IntentFilter("com.example.firstapp.DATA_UPDATED")
-        registerReceiver(object : BroadcastReceiver() {
-            override fun onReceive(context: Context, intent: Intent) {
-                // 数据已更新,刷新 LiveData
-                homeViewModel.loadData()
-            }
-        }, filter)
+//        // 注册广播接收器来监听数据更新
+//        val filter = IntentFilter("com.example.firstapp.DATA_UPDATED")
+//        registerReceiver(object : BroadcastReceiver() {
+//            override fun onReceive(context: Context, intent: Intent) {
+//                // 数据已更新,刷新 LiveData
+//                homeViewModel.loadData()
+//            }
+//        }, filter)
 
     }
 
diff --git a/app/src/main/java/com/example/firstapp/adapter/ExpressAdapter.kt b/app/src/main/java/com/example/firstapp/adapter/ExpressAdapter.kt
new file mode 100644
index 0000000..2445433
--- /dev/null
+++ b/app/src/main/java/com/example/firstapp/adapter/ExpressAdapter.kt
@@ -0,0 +1,87 @@
+package com.example.firstapp.adapter
+
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import androidx.recyclerview.widget.ListAdapter
+import com.example.firstapp.databinding.ItemExpressGroupBinding
+import com.example.firstapp.databinding.ItemExpressPackageBinding
+import androidx.recyclerview.widget.DiffUtil
+import com.example.firstapp.model.ExpressGroup
+import com.example.firstapp.model.ExpressPackage
+
+class ExpressAdapter : ListAdapter<ExpressGroup, ExpressAdapter.ViewHolder>(ExpressGroupDiffCallback()) {
+
+    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
+        val binding = ItemExpressGroupBinding.inflate(
+            LayoutInflater.from(parent.context), parent, false
+        )
+        return ViewHolder(binding)
+    }
+
+    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
+        val group = getItem(position)
+        holder.bind(group)
+    }
+
+    class ViewHolder(private val binding: ItemExpressGroupBinding) : RecyclerView.ViewHolder(binding.root) {
+        private val packagesAdapter = ExpressPackageAdapter()
+
+        init {
+            binding.rvPackages.apply {
+                layoutManager = LinearLayoutManager(context)
+                adapter = packagesAdapter
+            }
+        }
+
+        fun bind(group: ExpressGroup) {
+            binding.tvStationName.text = group.stationName
+            binding.tvPackageCount.text = "共${group.packages.size}个包裹"
+            packagesAdapter.submitList(group.packages)
+        }
+    }
+}
+
+class ExpressPackageAdapter : ListAdapter<ExpressPackage, ExpressPackageAdapter.ViewHolder>(ExpressPackageDiffCallback()) {
+
+    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
+        val binding = ItemExpressPackageBinding.inflate(
+            LayoutInflater.from(parent.context), parent, false
+        )
+        return ViewHolder(binding)
+    }
+
+    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
+        val pack = getItem(position)
+        holder.bind(pack)
+    }
+
+    class ViewHolder(private val binding: ItemExpressPackageBinding) : RecyclerView.ViewHolder(binding.root) {
+        fun bind(pack: ExpressPackage) {
+            binding.tvCompany.text = pack.company
+            binding.tvTrackingNumber.text = pack.trackingNumber
+            binding.tvDate.text = pack.date
+        }
+    }
+}
+
+private class ExpressGroupDiffCallback : DiffUtil.ItemCallback<ExpressGroup>() {
+    override fun areItemsTheSame(oldItem: ExpressGroup, newItem: ExpressGroup): Boolean {
+        return oldItem.stationName == newItem.stationName
+    }
+
+    override fun areContentsTheSame(oldItem: ExpressGroup, newItem: ExpressGroup): Boolean {
+        return oldItem == newItem
+    }
+}
+
+private class ExpressPackageDiffCallback : DiffUtil.ItemCallback<ExpressPackage>() {
+    override fun areItemsTheSame(oldItem: ExpressPackage, newItem: ExpressPackage): Boolean {
+        return oldItem.trackingNumber == newItem.trackingNumber
+    }
+
+    override fun areContentsTheSame(oldItem: ExpressPackage, newItem: ExpressPackage): Boolean {
+        return oldItem == newItem
+    }
+} 
\ No newline at end of file
diff --git a/app/src/main/java/com/example/firstapp/adapter/ReminderAdapter.kt b/app/src/main/java/com/example/firstapp/adapter/ReminderAdapter.kt
index e4a2ade..3a579bc 100644
--- a/app/src/main/java/com/example/firstapp/adapter/ReminderAdapter.kt
+++ b/app/src/main/java/com/example/firstapp/adapter/ReminderAdapter.kt
@@ -5,7 +5,6 @@
 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()) {
diff --git a/app/src/main/java/com/example/firstapp/database/dao/CodeDao.kt b/app/src/main/java/com/example/firstapp/database/dao/CodeDao.kt
index 8df5a2b..64e658e 100644
--- a/app/src/main/java/com/example/firstapp/database/dao/CodeDao.kt
+++ b/app/src/main/java/com/example/firstapp/database/dao/CodeDao.kt
@@ -41,4 +41,11 @@
 
     @Query("SELECT * FROM Code order by time desc")
     abstract fun getAllCodesDesc():  List<Code>
+
+    @Query("""
+        SELECT * FROM Code 
+        WHERE type LIKE '%' || :keyword || '%' 
+        ORDER BY time DESC
+    """)
+    fun getByKeyword(keyword: String): List<Code>
 }
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
index 59d5af1..e0cd71f 100644
--- a/app/src/main/java/com/example/firstapp/database/dao/ReminderDao.kt
+++ b/app/src/main/java/com/example/firstapp/database/dao/ReminderDao.kt
@@ -15,4 +15,7 @@
 
     @Delete
      fun delete(reminder: Reminder)
+
+    @Query("SELECT * FROM reminders WHERE type = :type")
+    fun getByType(type: String): List<Reminder>
 }
\ No newline at end of file
diff --git a/app/src/main/java/com/example/firstapp/database/repository/CodeRepository.kt b/app/src/main/java/com/example/firstapp/database/repository/CodeRepository.kt
index 2d9eceb..c5d1165 100644
--- a/app/src/main/java/com/example/firstapp/database/repository/CodeRepository.kt
+++ b/app/src/main/java/com/example/firstapp/database/repository/CodeRepository.kt
@@ -17,5 +17,9 @@
 
     fun getAllDesc() = codeDao.getAllCodesDesc()
 
+    @WorkerThread
+    fun getByKeyword(keyword: String): List<Code> {
+        return codeDao.getByKeyword(keyword)
+    }
 
 }
\ No newline at end of file
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
index 6017712..20f90f4 100644
--- a/app/src/main/java/com/example/firstapp/database/repository/ReminderRepository.kt
+++ b/app/src/main/java/com/example/firstapp/database/repository/ReminderRepository.kt
@@ -18,4 +18,9 @@
      fun delete(reminder: Reminder) {
         reminderDao.delete(reminder)
     }
+
+    @WorkerThread
+    fun getByType(type: String): List<Reminder> {
+        return reminderDao.getByType(type)
+    }
 } 
\ No newline at end of file
diff --git a/app/src/main/java/com/example/firstapp/model/ExpressGroup.kt b/app/src/main/java/com/example/firstapp/model/ExpressGroup.kt
new file mode 100644
index 0000000..7122769
--- /dev/null
+++ b/app/src/main/java/com/example/firstapp/model/ExpressGroup.kt
@@ -0,0 +1,12 @@
+package com.example.firstapp.model
+
+data class ExpressGroup(
+    val stationName: String,
+    val packages: List<ExpressPackage>
+)
+
+data class ExpressPackage(
+    val company: String,
+    val trackingNumber: String,
+    val date: String
+) 
\ No newline at end of file
diff --git a/app/src/main/java/com/example/firstapp/ui/home/HomeFragment.kt b/app/src/main/java/com/example/firstapp/ui/home/HomeFragment.kt
index bf4b7ec..5cdc5e0 100644
--- a/app/src/main/java/com/example/firstapp/ui/home/HomeFragment.kt
+++ b/app/src/main/java/com/example/firstapp/ui/home/HomeFragment.kt
@@ -10,7 +10,7 @@
 import androidx.recyclerview.widget.LinearLayoutManager
 import androidx.recyclerview.widget.RecyclerView
 import com.example.firstapp.R
-import com.example.firstapp.adapter.MyAdapter
+import com.example.firstapp.adapter.ExpressAdapter
 import com.example.firstapp.core.Core
 import com.example.firstapp.databinding.FragmentHomeBinding
 
@@ -23,45 +23,73 @@
     private val binding get() = _binding!!
 
     private lateinit var homeViewModel: HomeViewModel
-    private lateinit var adapter: MyAdapter
+    private lateinit var expressAdapter: ExpressAdapter
+//    private lateinit var financeAdapter: FinanceAdapter
+//    private lateinit var memorialAdapter: MemorialAdapter
 
-
+    //onCreateView这个方法创建后被调用,通常是初始化视图组件和观察者
     override fun onCreateView(
         inflater: LayoutInflater,
         container: ViewGroup?,
         savedInstanceState: Bundle?
     ): View {
-        homeViewModel =
-            ViewModelProvider(this).get(HomeViewModel::class.java)
-
         _binding = FragmentHomeBinding.inflate(inflater, container, false)
-        val root: View = binding.root
+        return binding.root
+    }
 
-//        val textView: TextView = binding.textHome
-//        homeViewModel.text.observe(viewLifecycleOwner) {
-//            textView.text = it
-//        }
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
 
+        //通过 ViewModelProvider 获取 HomeViewModel 的实例,以便在视图中使用。
+        homeViewModel = ViewModelProvider(this).get(HomeViewModel::class.java)
 
-        // 初始化适配器
-        adapter = MyAdapter()
+        //调用这个方法来设置 RecyclerView用于设置 RecyclerView 的布局和适配器。
+        setupRecyclerViews()
+        //调用这个方法来观察 ViewModel 中的数据变化
+        observeViewModelData()
+    }
 
-        // 获取数据
-//        val codeList = Core.code.getAllDesc()
-
-        // 使用 binding 来访问 RecyclerView
-        val recyclerView: RecyclerView = binding.recyclerView
-        recyclerView.layoutManager = LinearLayoutManager(requireContext()) // 使用 requireContext() 获取上下文
-        recyclerView.adapter = adapter
-
-        // 观察 LiveData,当数据发生变化时,更新 RecyclerView 的内容
-        homeViewModel.codeList.observe(viewLifecycleOwner) { codeList ->
-            adapter.submitList(codeList) // 更新 RecyclerView 的数据
-            // 滚动到顶部
-            recyclerView.scrollToPosition(0)
+    private fun setupRecyclerViews() {
+        // 快递列表
+        //layoutManager = LinearLayoutManager(context):设置 RecyclerView 的布局管理器为线性布局管理器,表示列表是垂直排列的。
+        //创建一个 ExpressAdapter 的实例,用于提供 RecyclerView 的数据。
+        //将适配器设置给 RecyclerView,以便显示数据。
+        binding.expressRecycler.apply {
+            layoutManager = LinearLayoutManager(context)
+            expressAdapter = ExpressAdapter()
+            adapter = expressAdapter
         }
 
-        return root
+//        // 财务列表
+//        binding.financeRecycler.apply {
+//            layoutManager = LinearLayoutManager(context)
+//            financeAdapter = FinanceAdapter()
+//            adapter = financeAdapter
+//        }
+//
+//        // 纪念日列表
+//        binding.memorialRecycler.apply {
+//            layoutManager = LinearLayoutManager(context)
+//            memorialAdapter = MemorialAdapter()
+//            adapter = memorialAdapter
+//        }
+    }
+
+    //这个方法用于观察 homeViewModel 中的 expressItems 数据。
+    private fun observeViewModelData() {
+        //当 expressItems 数据发生变化时,更新 RecyclerView 的数据。
+        homeViewModel.expressItems.observe(viewLifecycleOwner) { items ->
+            //将新的数据列表提交给适配器,以更新 RecyclerView 的显示内容。
+            expressAdapter.submitList(items)
+        }
+
+//        homeViewModel.financeItems.observe(viewLifecycleOwner) { items ->
+//            financeAdapter.submitList(items)
+//        }
+//
+//        homeViewModel.memorialItems.observe(viewLifecycleOwner) { items ->
+//            memorialAdapter.submitList(items)
+//        }
     }
 
     override fun onDestroyView() {
diff --git a/app/src/main/java/com/example/firstapp/ui/home/HomeViewModel.kt b/app/src/main/java/com/example/firstapp/ui/home/HomeViewModel.kt
index 630b6af..a8b15bf 100644
--- a/app/src/main/java/com/example/firstapp/ui/home/HomeViewModel.kt
+++ b/app/src/main/java/com/example/firstapp/ui/home/HomeViewModel.kt
@@ -3,34 +3,66 @@
 import androidx.lifecycle.LiveData
 import androidx.lifecycle.MutableLiveData
 import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
 import com.example.firstapp.core.Core
 import com.example.firstapp.database.entity.Code
+import com.example.firstapp.model.ExpressGroup
+import com.example.firstapp.model.ExpressPackage
+import kotlinx.coroutines.launch
 
 class HomeViewModel : ViewModel() {
 
-    private val _text = MutableLiveData<String>().apply {
-        value = "短信主页面"
-    }
-    val text: LiveData<String> = _text
+//    private val _text = MutableLiveData<String>().apply {
+//        value = "短信主页面"
+//    }
+//    val text: LiveData<String> = _text
+//
+//    private val _codeList = MutableLiveData<List<Code>>()
+//
+//    val codeList: LiveData<List<Code>> get() = _codeList
 
-    private val _codeList = MutableLiveData<List<Code>>()
-
-    val codeList: LiveData<List<Code>> get() = _codeList
+    private val _expressItems = MutableLiveData<List<ExpressGroup>>()
+    val expressItems: LiveData<List<ExpressGroup>> = _expressItems
 
     init {
         // 初始化时加载数据
-        loadData()
+      //  loadData()
+        loadExpressData()
     }
 
     // 加载数据的方法
-    fun loadData() {
-        // 获取数据,并更新 LiveData
-        _codeList.value = Core.code.getAllDesc() // 假设这是获取最新的 data 的方法
-    }
+//    fun loadData() {
+//        // 获取数据,并更新 LiveData
+//        _codeList.value = Core.code.getAllDesc() // 假设这是获取最新的 data 的方法
+//    }
+//
+//    // 如果需要手动更新数据,可以调用这个方法
+//    fun updateData() {
+//        _codeList.value = Core.code.getAllDesc() // 重新获取并更新数据
+//    }
 
-    // 如果需要手动更新数据,可以调用这个方法
-    fun updateData() {
-        _codeList.value = Core.code.getAllDesc() // 重新获取并更新数据
+    fun loadExpressData() {
+        viewModelScope.launch {
+            // 1. 获取所有驿站类型的提醒设置
+            val stations = Core.reminder.getByType("驿站")
+            
+            // 2. 按驿站分组获取包裹信息
+            val groups = stations.map { station ->
+                val packages = Core.code.getByKeyword(station.nickname).map { code ->
+                    ExpressPackage(
+                        company = code.name, //快递公司
+                        trackingNumber = code.code, // 取件码
+                        date = code.overtime  //时间
+                    )
+                }
+                ExpressGroup(
+                    stationName = station.nickname,
+                    packages = packages
+                )
+            }
+            
+            _expressItems.postValue(groups)
+        }
     }
 
 }
\ No newline at end of file
diff --git a/app/src/main/res/drawable/location.png b/app/src/main/res/drawable/location.png
new file mode 100644
index 0000000..89a457e
--- /dev/null
+++ b/app/src/main/res/drawable/location.png
Binary files differ
diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml
index 0a6dc93..87907ab 100644
--- a/app/src/main/res/layout/fragment_home.xml
+++ b/app/src/main/res/layout/fragment_home.xml
@@ -1,30 +1,112 @@
 <?xml version="1.0" encoding="utf-8"?>
-<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<ScrollView 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.home.HomeFragment">
+    android:layout_height="match_parent">
 
-<!--    <TextView-->
-<!--        android:id="@+id/text_home"-->
-<!--        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.recyclerview.widget.RecyclerView
-        xmlns:android="http://schemas.android.com/apk/res/android"
-        android:id="@+id/recyclerView"
+<!--    LinearLayout的作用是按照垂直或者水平方向排列其子视图-->
+<!--    CardView组件是用于实现卡片式布局-->
+<!--    RecyclerView 回收商视图 它使用适配器(Adapter)来管理数据的显示,-->
+<!--    开发者可以根据自己的需求实现适配器的方法,将数据与视图进行绑定。-->
+<!--    这使得 RecyclerView 能够轻松地处理各种类型的数据,并按照自定义的布局方式展示。-->
+<!--    支持局部刷新 通知数据集变化-->
+    <LinearLayout
         android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:padding="8dp"/>
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        android:padding="16dp">
 
-</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
+        <!-- 我的快递板块 -->
+        <androidx.cardview.widget.CardView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginBottom="16dp"
+            app:cardCornerRadius="8dp"
+            app:cardElevation="2dp">
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical">
+                <TextView
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:text="我的快递"
+                    android:textColor="#333333"
+                    android:textSize="16sp"
+                    android:textStyle="bold"/>
+
+                <androidx.recyclerview.widget.RecyclerView
+                    android:id="@+id/express_recycler"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginTop="8dp" />
+
+
+            </LinearLayout>
+        </androidx.cardview.widget.CardView>
+
+        <!-- 我的财务板块 -->
+        <androidx.cardview.widget.CardView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginBottom="16dp"
+            app:cardCornerRadius="8dp"
+            app:cardElevation="2dp">
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical"
+                android:padding="16dp"
+                android:background="#E8F5E9">
+
+                <androidx.recyclerview.widget.RecyclerView
+                    android:id="@+id/finance_recycler"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginTop="8dp"/>
+
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="我的财务"
+                    android:textColor="#333333"
+                    android:textSize="16sp"
+                    android:textStyle="bold"/>
+            </LinearLayout>
+        </androidx.cardview.widget.CardView>
+
+        <!-- 纪念日板块 -->
+        <androidx.cardview.widget.CardView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginBottom="16dp"
+            app:cardCornerRadius="8dp"
+            app:cardElevation="2dp">
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical"
+                android:padding="16dp"
+                android:background="#FFF3E0">
+
+                <androidx.recyclerview.widget.RecyclerView
+                    android:id="@+id/memorial_recycler"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginTop="8dp"/>
+
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="纪念日"
+                    android:textColor="#333333"
+                    android:textSize="16sp"
+                    android:textStyle="bold"/>
+            </LinearLayout>
+        </androidx.cardview.widget.CardView>
+
+    </LinearLayout>
+</ScrollView>
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_express_group.xml b/app/src/main/res/layout/item_express_group.xml
new file mode 100644
index 0000000..4a13e84
--- /dev/null
+++ b/app/src/main/res/layout/item_express_group.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.cardview.widget.CardView 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="wrap_content"
+    android:layout_marginHorizontal="12dp"
+    android:layout_marginVertical="6dp"
+    app:cardCornerRadius="8dp"
+    app:cardElevation="2dp">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        android:padding="16dp">
+
+        <!-- 驿站名称和包裹数量 -->
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            android:layout_marginBottom="12dp">
+
+            <ImageView
+                android:id="@+id/iv_station_icon"
+                android:layout_width="20dp"
+                android:layout_height="20dp"
+                android:layout_gravity="center_vertical"
+                android:src="@drawable/location"/>
+
+            <TextView
+                android:id="@+id/tv_station_name"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:layout_marginStart="8dp"
+                android:textSize="16sp"
+                android:textColor="#333333"/>
+
+            <TextView
+                android:id="@+id/tv_package_count"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:textSize="14sp"
+                android:textColor="#666666"/>
+        </LinearLayout>
+
+        <!-- 包裹列表 -->
+        <androidx.recyclerview.widget.RecyclerView
+            android:id="@+id/rv_packages"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"/>
+    </LinearLayout>
+</androidx.cardview.widget.CardView>
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_express_package.xml b/app/src/main/res/layout/item_express_package.xml
new file mode 100644
index 0000000..b5389c3
--- /dev/null
+++ b/app/src/main/res/layout/item_express_package.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="horizontal"
+    android:padding="12dp">
+
+    <ImageView
+        android:id="@+id/iv_company_logo"
+        android:layout_width="24dp"
+        android:layout_height="24dp"
+        android:layout_gravity="center_vertical" />
+
+    <LinearLayout
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="12dp"
+        android:layout_weight="1"
+        android:orientation="vertical">
+
+        <TextView
+            android:id="@+id/tv_company"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textColor="#333333"
+            android:textSize="15sp" />
+
+        <TextView
+            android:id="@+id/tv_date"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical"
+            android:textColor="#999999"
+            android:textSize="12sp" />
+
+    </LinearLayout>
+
+    <TextView
+        android:id="@+id/tv_tracking_number"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="4dp"
+        android:textColor="#666666"
+        android:textSize="14sp" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/app/src/main/res/navigation/mobile_navigation.xml b/app/src/main/res/navigation/mobile_navigation.xml
index bc776fe..293c825 100644
--- a/app/src/main/res/navigation/mobile_navigation.xml
+++ b/app/src/main/res/navigation/mobile_navigation.xml
@@ -5,6 +5,8 @@
     android:id="@+id/mobile_navigation"
     app:startDestination="@+id/navigation_home">
 
+    <!--    对应的多个片段-->
+    <!--    tools:layout="@layout/fragment_home"表示设计视图中显示的应该是fragment_home.xml的内容,而不是当前布局的内容-->
     <fragment
         android:id="@+id/navigation_home"
         android:name="com.example.firstapp.ui.home.HomeFragment"

--
Gitblit v1.9.3